1 | import Logger from 'nightingale/src';
|
2 | import { hostname } from 'os';
|
3 | import createSocketClient from 'socket.io-client';
|
4 | import { serverHost, serverPort, token, device } from './params';
|
5 | import { getTime as getConfigTime } from './config';
|
6 | import { onConfigUpdated } from './manager';
|
7 | import * as screen from './commands/screen';
|
8 | import * as display from './commands/display';
|
9 | import availableDisplays from './utils/availableDisplays';
|
10 | import findNetworkInterface from './utils/networkInterface';
|
11 | import { selfUpdate } from './update';
|
12 | import pkg from '../../package.json';
|
13 | import { runSync } from './utils/exec';
|
14 |
|
15 | const logger = new Logger('app:client');
|
16 |
|
17 | const socket =
|
18 | serverHost &&
|
19 | serverPort &&
|
20 | createSocketClient(`${serverHost}:${serverPort}/raspberry-client`, {
|
21 | autoConnect: false,
|
22 | reconnection: true,
|
23 | reconnectionDelay: 500,
|
24 | reconnectionDelayMax: 120000,
|
25 | reconnectionAttempts: Infinity,
|
26 | timeout: 4000,
|
27 | transports: ['websocket'],
|
28 | });
|
29 |
|
30 | const emit = (eventName: string, ...args: Array<any>) => {
|
31 | if (!socket) {
|
32 | logger.warn('cannot emit', { eventName, args });
|
33 | return;
|
34 | }
|
35 |
|
36 | logger.debug('emit', { eventName, args });
|
37 | return socket.emit(eventName, ...args);
|
38 | };
|
39 |
|
40 | export const sendUpdate = (data: Object): void => {
|
41 | emit('update', data);
|
42 | };
|
43 |
|
44 | if (socket) {
|
45 |
|
46 | setTimeout(() => {
|
47 | logger.debug('Connecting', { serverHost, serverPort });
|
48 | socket.on('connect_error', err =>
|
49 | logger.error('connect error', { serverHost, serverPort, errMessage: err.message }),
|
50 | );
|
51 | socket.on('reconnect_error', err =>
|
52 | logger.debug('reconnect error', { serverHost, serverPort, err }),
|
53 | );
|
54 |
|
55 | socket.on('disconnect', () => logger.warn('disconnected'));
|
56 |
|
57 | socket.on('reconnect', () => logger.success('reconnected'));
|
58 |
|
59 | socket.on('connect', () => {
|
60 | logger.success('connected');
|
61 |
|
62 | const networkInterface = findNetworkInterface();
|
63 | const screenState = screen.getCurrentScreenState();
|
64 | emit('hello', {
|
65 | configTime: getConfigTime(),
|
66 | client: { name: pkg.name, version: pkg.version },
|
67 | token,
|
68 | screenState,
|
69 | ...networkInterface,
|
70 | hostname: hostname(),
|
71 | device,
|
72 | screen: {
|
73 | state: screenState,
|
74 | screens: screen.getCurrentScreens(),
|
75 | },
|
76 | availableDisplays,
|
77 | });
|
78 | });
|
79 |
|
80 | socket.on('updateConfig', onConfigUpdated);
|
81 | socket.on('changeConfig', onConfigUpdated);
|
82 |
|
83 | socket.on('selfUpdate', () => selfUpdate());
|
84 |
|
85 | socket.on('action', (action: string) => {
|
86 | logger.info('received action', { action });
|
87 | switch (action) {
|
88 | case 'self-upgrade':
|
89 | case 'self-update':
|
90 | case 'selfUpdate':
|
91 | return selfUpdate();
|
92 |
|
93 | case 'screen-off':
|
94 | return screen.off();
|
95 | case 'screen-on':
|
96 | return screen.on();
|
97 |
|
98 | case 'refresh':
|
99 | return display.refresh();
|
100 |
|
101 | case 'reboot':
|
102 | sendUpdate({ rebooting: true });
|
103 | display.stop();
|
104 | return runSync('reboot');
|
105 |
|
106 | case 'poweroff':
|
107 | sendUpdate({ rebooting: true });
|
108 | display.stop();
|
109 | return runSync('poweroff');
|
110 | }
|
111 |
|
112 | logger.warn(`unknown action: ${action}`);
|
113 | });
|
114 |
|
115 | socket.on('poll-data', () => {
|
116 | logger.debug('poll data');
|
117 | const screenshotBuffer = screen.screenshot();
|
118 | if (!screenshotBuffer) {
|
119 | return;
|
120 | }
|
121 |
|
122 | logger.debug('send screenshot');
|
123 | socket.emit('update-data', { screenshotBuffer });
|
124 | });
|
125 |
|
126 | socket.connect();
|
127 | }, 1000);
|
128 | }
|
129 |
|
130 | export function close(): Promise<any> | void {
|
131 | if (!socket || !socket.connected) {
|
132 | return;
|
133 | }
|
134 |
|
135 | return new Promise(resolve => {
|
136 | logger.info('Closing...');
|
137 | socket.once('disconnect', () => {
|
138 | logger.info('Closed');
|
139 | resolve();
|
140 | });
|
141 | socket.close();
|
142 | });
|
143 | }
|