homebridge-smartsystem 6.8.4 → 6.8.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -307,6 +307,8 @@ Homebridge UI version
307
307
  - 1: max/min values for hbValues
308
308
  - 2: HB up/down -> don't respond to motor unit's, only macro
309
309
  - 3: remember request before the login kicked in (and redirect to that one, once the login was succesful)
310
+ - 4: now using only TCP sockets to the server
311
+ - 5: making it more robust / inline with repo-service version
310
312
 
311
313
  ## Hardware
312
314
  A Raspberry Pi that connects to a Duotecno IP Node
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "homebridge-smartsystem",
3
3
  "displayname": "Duotecno Bridge",
4
- "version": "6.8.4",
5
- "description": "SmartServer (Proxy Websockets to TCP sockets, Smappee MQTT, Duotecno IP Nodes, Homekit interface)",
4
+ "version": "6.8.5",
5
+ "description": "SmartServer (Proxy TCP sockets to the cloud, Smappee MQTT, Duotecno IP Nodes, Homekit interface)",
6
6
  "main": "index.js",
7
7
  "author": "Johan Coppieters",
8
8
  "homepage": "http://www.duotecno.be",
package/server/proxy.js CHANGED
@@ -63,7 +63,7 @@ function error(str) {
63
63
  if (config.uniqueId) {
64
64
  makeNewCloudConnection(config.masterAddress, config.masterPort, config.cloudServer, config.cloudPort, config.uniqueId);
65
65
  }
66
- function makeNewCloudConnection(master, masterPort, server, serverPort, uniqueId) {
66
+ function makeNewCloudConnection(master, masterPort, server, serverPort, uniqueId, count = 0) {
67
67
  const cloudSocket = new net.Socket();
68
68
  cloudSocket.connect(serverPort, server, () => {
69
69
  log(`[PROXY] → [CLOUD] Connected to Cloud at ${server}:${serverPort}`);
@@ -75,27 +75,23 @@ function makeNewCloudConnection(master, masterPort, server, serverPort, uniqueId
75
75
  log(`[PROXY] → [CLOUD] New free connection #${gCloudConnections.length} to the Cloud at ${server}:${serverPort}`);
76
76
  });
77
77
  cloudSocket.on('error', (err) => {
78
- error(`[PROXY] → [CLOUD] Failed to connect to Cloud: ${err.message}`);
78
+ error(`[PROXY] → [CLOUD] Failed to connect ${count + 1} times to the Cloud server: ${err.message}`);
79
+ if (count < 3) {
80
+ setTimeout(() => {
81
+ makeNewCloudConnection(master, masterPort, server, serverPort, uniqueId, count + 1);
82
+ }, 1000);
83
+ }
79
84
  });
80
- log(`[PROXY] → [CLOUD] Attempting to start a new free connection for ${config.uniqueId} to the Cloud at ${server}:${serverPort}`);
85
+ log(`[PROXY] → [CLOUD] Attempt ${count + 1} to start a new free connection for ${config.uniqueId} to the Cloud at ${server}:${serverPort}`);
81
86
  }
82
87
  exports.makeNewCloudConnection = makeNewCloudConnection;
83
88
  ////////////////
84
89
  // Restarting //
85
90
  ////////////////
86
91
  function cleanStart(restart = false) {
87
- if (gCloudConnections.length) {
88
- gCloudConnections.forEach(context => {
89
- if (context.deviceSocket) {
90
- context.deviceSocket.end();
91
- context.deviceSocket = null;
92
- }
93
- context.cloudSocket.end();
94
- context.cloudSocket = null;
95
- });
96
- gCloudConnections.splice(0, gCloudConnections.length); // clear the array
97
- log(`[PROXY] → [CLOUD] Cleaned up all cloud connections.`);
98
- }
92
+ gCloudConnections.forEach(ctx => ctx.cleanupSockets());
93
+ log(`[PROXY] → [CLOUD] Cleaned up all ${gCloudConnections.length} cloud connections.`);
94
+ gCloudConnections.splice(0, gCloudConnections.length); // clear the array
99
95
  if (restart) {
100
96
  if (config.uniqueId) {
101
97
  makeNewCloudConnection(config.masterAddress, config.masterPort, config.cloudServer, config.cloudPort, config.uniqueId);
@@ -122,7 +118,7 @@ class Context {
122
118
  }
123
119
  setupCloudSocket() {
124
120
  // set up handlers for the cloud socket
125
- this.cloudSocket.on('data', data => {
121
+ this.cloudSocket.on('data', (data) => {
126
122
  this.handleDataFromCloud(data);
127
123
  });
128
124
  this.cloudSocket.on('close', () => {
@@ -165,8 +161,8 @@ class Context {
165
161
  }
166
162
  }
167
163
  else if (this.deviceSocket.readyState === 'open') {
168
- this.deviceSocket.write(new Uint8Array(data));
169
- debug(`[PROXY] → [DEVICE] forwarding data to device: ${data.toString().slice(0, -1)}`);
164
+ this.deviceSocket.write(data);
165
+ debug(`[PROXY] → [DEVICE] forwarding data to device: ${data.toString().trim()}`);
170
166
  }
171
167
  else {
172
168
  warning(`[PROXY] → [DEVICE] Device socket is not open yet, waiting for connection... what to do with the data??`);
@@ -185,13 +181,13 @@ class Context {
185
181
  }
186
182
  log(`[PROXY] → [DEVICE] Connected to local device at ${address}:${port}`);
187
183
  this.setUpDeviceSocket();
188
- log(`[PROXY] → [DEVICE] Sending initial message: ${data.toString().slice(0, -1)}`);
189
- this.deviceSocket.write(new Uint8Array(data));
184
+ log(`[PROXY] → [DEVICE] Sending initial message: ${data.toString().trim()}`);
185
+ this.deviceSocket.write(data);
190
186
  });
191
187
  }
192
188
  else if (this.deviceSocket.readyState === 'open') {
193
189
  warning(`[PROXY] → [DEVICE] Device socket already open, sending data directly -- STRANGE !!`);
194
- this.deviceSocket.write(new Uint8Array(data));
190
+ this.deviceSocket.write(data);
195
191
  }
196
192
  else {
197
193
  error(`[PROXY] → [DEVICE] Device socket exists, but is not open yet !!`);
@@ -204,8 +200,8 @@ class Context {
204
200
  }
205
201
  this.deviceSocket.on('data', (data) => {
206
202
  const message = data.toString('utf-8');
207
- debug(`[DEVICE] → [PROXY] forwarding data to Cloud: ${message.slice(0, -1)}`);
208
- this.cloudSocket.write(message);
203
+ debug(`[DEVICE] → [PROXY] forwarding data to Cloud: ${message.trim()}`);
204
+ this.cloudSocket.write(data);
209
205
  });
210
206
  this.deviceSocket.on('close', () => {
211
207
  log(`[DEVICE] → [PROXY] Device socket closed`);
@@ -216,33 +212,43 @@ class Context {
216
212
  this.removeConnection();
217
213
  });
218
214
  }
219
- removeConnection() {
220
- // Clean up device socket
215
+ cleanupSockets() {
216
+ // Clean up the device socket
221
217
  if (this.deviceSocket) {
222
218
  if (!this.deviceSocket.destroyed) {
219
+ this.deviceSocket.removeAllListeners();
223
220
  this.deviceSocket.end();
221
+ this.deviceSocket.destroy();
224
222
  }
225
223
  this.deviceSocket = null;
226
224
  }
227
- // remove this context and close the cloud socket
228
- const index = gCloudConnections.indexOf(this);
229
- if (index !== -1) {
230
- this.cloudSocket.end();
225
+ // Clean up the cloud socket
226
+ if (this.cloudSocket) {
227
+ if (!this.cloudSocket.destroyed) {
228
+ this.cloudSocket.removeAllListeners();
229
+ this.cloudSocket.end();
230
+ this.cloudSocket.destroy();
231
+ }
231
232
  this.cloudSocket = null;
232
- gCloudConnections.splice(index, 1);
233
- log(`[PROXY] → [CLOUD] Closed socket to Cloud and removed context for device ${this.master}`);
234
233
  }
234
+ }
235
+ removeConnection() {
236
+ const index = gCloudConnections.indexOf(this);
237
+ if (index !== -1)
238
+ gCloudConnections.splice(index, 1);
239
+ this.cleanupSockets();
240
+ log(`[PROXY] → [CLOUD] Closed socket to Cloud and removed context for device ${this.master}`);
235
241
  if (gCloudConnections.length === 0) {
236
242
  log(`[PROXY] → [CLOUD] No more cloud connections, restarting proxy.`);
237
243
  // just to be sure: restart...
238
244
  if (config.kind === "pm2") {
239
245
  // PM2 should restart us.
240
246
  log(`[PROXY] → [CLOUD] PM2 should restart us, exiting now.`);
241
- process.exit();
247
+ setTimeout(() => process.exit(0), 100);
242
248
  }
243
249
  else if (config.kind === "solo") {
244
250
  log(`[PROXY] → [CLOUD] Running solo, restarting proxy.`);
245
- this.restart();
251
+ restart();
246
252
  }
247
253
  else {
248
254
  log(`[PROXY] → [CLOUD] Running under gateway/homebridge, not restarting... not sure what to do here.`);
@@ -252,25 +258,18 @@ class Context {
252
258
  ///////////////
253
259
  // Utilities //
254
260
  ///////////////
255
- restart() {
256
- console.log('🔄 Restarting...');
257
- (0, child_process_1.spawn)(process_1.execPath, process_1.argv.slice(1), {
258
- cwd: (0, process_1.cwd)(),
259
- detached: true,
260
- stdio: 'inherit',
261
- });
262
- process.exit();
263
- }
264
261
  // check if it's a heartbeat request from the server
265
262
  isHeartbeatRequest(data) {
263
+ const msg = data.toString('utf-8').trim();
264
+ return msg === '[215,3]';
266
265
  // hearbeatKind = (poll = 1, poll_old = 2, serve = 3)
267
- return ((data[0] === 91) && // [
268
- (data[1] === 50) && // 2
269
- (data[2] === 49) && // 1
270
- (data[3] === 53) && // 5
271
- (data[4] === 44) && // ,
272
- (data[5] === 51) && // 3
273
- (data[6] === 93)); // ]
266
+ // return ((data[0] === 91) && // [
267
+ // (data[1] === 50) && // 2
268
+ // (data[2] === 49) && // 1
269
+ // (data[3] === 53) && // 5
270
+ // (data[4] === 44) && // ,
271
+ // (data[5] === 51) && // 3
272
+ // (data[6] === 93)); // ]
274
273
  }
275
274
  // check if it's a server response after connecting and sending our uniqueID
276
275
  isConnectionResponse(data) {
@@ -280,4 +279,50 @@ class Context {
280
279
  }
281
280
  }
282
281
  exports.Context = Context;
282
+ function restart() {
283
+ console.log('🔄 Restarting...');
284
+ setTimeout(() => {
285
+ (0, child_process_1.spawn)(process_1.execPath, process_1.argv.slice(1), {
286
+ cwd: (0, process_1.cwd)(),
287
+ detached: true,
288
+ stdio: 'inherit',
289
+ });
290
+ process.exit(0);
291
+ }, 100);
292
+ }
293
+ // Graceful shutdown handler
294
+ function handleShutdown(signal) {
295
+ log(`[PROXY] → [SYSTEM] Received ${signal}, shutting down gracefully...`);
296
+ // Close all cloud connections
297
+ gCloudConnections.forEach(ctx => ctx.cleanupSockets());
298
+ gCloudConnections.splice(0, gCloudConnections.length);
299
+ log(`[PROXY] → [SYSTEM] All connections closed. Exiting.`);
300
+ if (config.kind === "solo") {
301
+ log(`[PROXY] → [SYSTEM] Restarting proxy in solo mode...`);
302
+ restart();
303
+ }
304
+ else {
305
+ log(`[PROXY] → [SYSTEM] Exiting without restart.`);
306
+ setTimeout(() => process.exit(0), 100);
307
+ }
308
+ }
309
+ // Listen for termination signals
310
+ process.on('SIGINT', () => handleShutdown('SIGINT'));
311
+ process.on('SIGTERM', () => handleShutdown('SIGTERM'));
312
+ process.on('SIGINT', (err) => {
313
+ error(`[SYSTEM] received SIGINT`);
314
+ handleShutdown('SIGINT');
315
+ });
316
+ process.on('SIGTERM', (err) => {
317
+ error(`[SYSTEM] received SIGTERM`);
318
+ handleShutdown('SIGTERM');
319
+ });
320
+ process.on('uncaughtException', (err) => {
321
+ error(`[SYSTEM] Uncaught Exception: ${err.message}`);
322
+ handleShutdown('uncaughtException');
323
+ });
324
+ process.on('unhandledRejection', (reason) => {
325
+ error(`[SYSTEM] Unhandled Rejection: ${reason}`);
326
+ handleShutdown('unhandledRejection');
327
+ });
283
328
  //# sourceMappingURL=proxy.js.map
package/server/proxy.ts CHANGED
@@ -44,7 +44,7 @@ export function setProxyConfig(c?: ProxyConfig): ProxyConfig {
44
44
 
45
45
  let config: ProxyConfig;
46
46
  try {
47
- setProxyConfig(require('../config-proxy.json'))
47
+ setProxyConfig(require('../config-proxy.json'));
48
48
  } catch (e) {
49
49
  setProxyConfig();
50
50
  console.log("No config-proxy.json found, using default values from homebridge or other.");
@@ -82,7 +82,7 @@ if (config.uniqueId) {
82
82
  }
83
83
 
84
84
 
85
- export function makeNewCloudConnection(master: string, masterPort: number, server: string, serverPort: number, uniqueId: string) {
85
+ export function makeNewCloudConnection(master: string, masterPort: number, server: string, serverPort: number, uniqueId: string, count = 0) {
86
86
  const cloudSocket = new net.Socket();
87
87
 
88
88
  cloudSocket.connect(serverPort, server, () => {
@@ -98,10 +98,15 @@ export function makeNewCloudConnection(master: string, masterPort: number, serve
98
98
  });
99
99
 
100
100
  cloudSocket.on('error', (err) => {
101
- error(`[PROXY] → [CLOUD] Failed to connect to Cloud: ${err.message}`);
101
+ error(`[PROXY] → [CLOUD] Failed to connect ${count+1} times to the Cloud server: ${err.message}`);
102
+ if (count < 3) {
103
+ setTimeout(() => {
104
+ makeNewCloudConnection(master, masterPort, server, serverPort, uniqueId, count + 1);
105
+ }, 1000);
106
+ }
102
107
  });
103
108
 
104
- log(`[PROXY] → [CLOUD] Attempting to start a new free connection for ${config.uniqueId} to the Cloud at ${server}:${serverPort}`);
109
+ log(`[PROXY] → [CLOUD] Attempt ${count+1} to start a new free connection for ${config.uniqueId} to the Cloud at ${server}:${serverPort}`);
105
110
  }
106
111
 
107
112
 
@@ -109,18 +114,10 @@ export function makeNewCloudConnection(master: string, masterPort: number, serve
109
114
  // Restarting //
110
115
  ////////////////
111
116
  export function cleanStart(restart: boolean = false) {
112
- if (gCloudConnections.length) {
113
- gCloudConnections.forEach(context => {
114
- if (context.deviceSocket) {
115
- context.deviceSocket.end();
116
- context.deviceSocket = null;
117
- }
118
- context.cloudSocket.end();
119
- context.cloudSocket = null;
120
- });
121
- gCloudConnections.splice(0, gCloudConnections.length); // clear the array
122
- log(`[PROXY] → [CLOUD] Cleaned up all cloud connections.`);
123
- }
117
+ gCloudConnections.forEach(ctx => ctx.cleanupSockets());
118
+ log(`[PROXY] → [CLOUD] Cleaned up all ${gCloudConnections.length} cloud connections.`);
119
+
120
+ gCloudConnections.splice(0, gCloudConnections.length); // clear the array
124
121
 
125
122
  if (restart) {
126
123
  if (config.uniqueId) {
@@ -135,11 +132,11 @@ export function cleanStart(restart: boolean = false) {
135
132
 
136
133
 
137
134
  export class Context {
138
- deviceSocket: net.Socket;
135
+ deviceSocket: net.Socket | null;
139
136
  master: string;
140
137
  masterPort: number;
141
138
 
142
- cloudSocket: net.Socket;
139
+ cloudSocket: net.Socket | null;
143
140
  server: string;
144
141
  serverPort: number;
145
142
 
@@ -162,8 +159,8 @@ export class Context {
162
159
 
163
160
  setupCloudSocket() {
164
161
  // set up handlers for the cloud socket
165
- this.cloudSocket.on('data', data => {
166
- this.handleDataFromCloud(data as Buffer);
162
+ this.cloudSocket.on('data', (data: Buffer) => {
163
+ this.handleDataFromCloud(data);
167
164
  });
168
165
 
169
166
  this.cloudSocket.on('close', () => {
@@ -210,8 +207,8 @@ export class Context {
210
207
  }
211
208
 
212
209
  } else if (this.deviceSocket.readyState === 'open') {
213
- this.deviceSocket.write(new Uint8Array(data));
214
- debug(`[PROXY] → [DEVICE] forwarding data to device: ${data.toString().slice(0, -1)}`);
210
+ this.deviceSocket.write(data);
211
+ debug(`[PROXY] → [DEVICE] forwarding data to device: ${data.toString().trim()}`);
215
212
 
216
213
  } else {
217
214
  warning(`[PROXY] → [DEVICE] Device socket is not open yet, waiting for connection... what to do with the data??`);
@@ -236,14 +233,14 @@ export class Context {
236
233
  log(`[PROXY] → [DEVICE] Connected to local device at ${address}:${port}`);
237
234
 
238
235
  this.setUpDeviceSocket();
239
-
240
- log(`[PROXY] → [DEVICE] Sending initial message: ${data.toString().slice(0, -1)}`);
241
- this.deviceSocket.write(new Uint8Array(data));
236
+
237
+ log(`[PROXY] → [DEVICE] Sending initial message: ${data.toString().trim()}`);
238
+ this.deviceSocket.write(data);
242
239
  });
243
240
 
244
241
  } else if (this.deviceSocket.readyState === 'open') {
245
242
  warning(`[PROXY] → [DEVICE] Device socket already open, sending data directly -- STRANGE !!`);
246
- this.deviceSocket.write(new Uint8Array(data));
243
+ this.deviceSocket.write(data);
247
244
 
248
245
  } else {
249
246
  error(`[PROXY] → [DEVICE] Device socket exists, but is not open yet !!`);
@@ -258,8 +255,8 @@ export class Context {
258
255
 
259
256
  this.deviceSocket.on('data', (data: Buffer) => {
260
257
  const message = data.toString('utf-8');
261
- debug(`[DEVICE] → [PROXY] forwarding data to Cloud: ${message.slice(0, -1)}`);
262
- this.cloudSocket.write(message);
258
+ debug(`[DEVICE] → [PROXY] forwarding data to Cloud: ${message.trim()}`);
259
+ this.cloudSocket.write(data);
263
260
  });
264
261
 
265
262
  this.deviceSocket.on('close', () => {
@@ -273,23 +270,34 @@ export class Context {
273
270
  });
274
271
  }
275
272
 
276
- removeConnection() {
277
- // Clean up device socket
273
+ cleanupSockets() {
274
+ // Clean up the device socket
278
275
  if (this.deviceSocket) {
279
276
  if (!this.deviceSocket.destroyed) {
277
+ this.deviceSocket.removeAllListeners();
280
278
  this.deviceSocket.end();
279
+ this.deviceSocket.destroy();
281
280
  }
282
281
  this.deviceSocket = null;
283
282
  }
284
283
 
285
- // remove this context and close the cloud socket
286
- const index = gCloudConnections.indexOf(this);
287
- if (index !== -1) {
288
- this.cloudSocket.end();
284
+ // Clean up the cloud socket
285
+ if (this.cloudSocket) {
286
+ if (!this.cloudSocket.destroyed) {
287
+ this.cloudSocket.removeAllListeners();
288
+ this.cloudSocket.end();
289
+ this.cloudSocket.destroy();
290
+ }
289
291
  this.cloudSocket = null;
290
- gCloudConnections.splice(index, 1);
291
- log(`[PROXY] → [CLOUD] Closed socket to Cloud and removed context for device ${this.master}`);
292
292
  }
293
+ }
294
+
295
+ removeConnection() {
296
+ const index = gCloudConnections.indexOf(this);
297
+ if (index !== -1) gCloudConnections.splice(index, 1);
298
+
299
+ this.cleanupSockets();
300
+ log(`[PROXY] → [CLOUD] Closed socket to Cloud and removed context for device ${this.master}`);
293
301
 
294
302
  if (gCloudConnections.length === 0) {
295
303
  log(`[PROXY] → [CLOUD] No more cloud connections, restarting proxy.`);
@@ -297,11 +305,11 @@ export class Context {
297
305
  if (config.kind === "pm2") {
298
306
  // PM2 should restart us.
299
307
  log(`[PROXY] → [CLOUD] PM2 should restart us, exiting now.`);
300
- process.exit();
308
+ setTimeout(() => process.exit(0), 100);
301
309
 
302
310
  } else if (config.kind === "solo"){
303
311
  log(`[PROXY] → [CLOUD] Running solo, restarting proxy.`);
304
- this.restart();
312
+ restart();
305
313
 
306
314
  } else {
307
315
  log(`[PROXY] → [CLOUD] Running under gateway/homebridge, not restarting... not sure what to do here.`);
@@ -314,28 +322,18 @@ export class Context {
314
322
  // Utilities //
315
323
  ///////////////
316
324
 
317
- restart() {
318
- console.log('🔄 Restarting...');
319
-
320
- spawn(execPath, argv.slice(1), {
321
- cwd: cwd(),
322
- detached: true,
323
- stdio: 'inherit',
324
- });
325
-
326
- process.exit();
327
- }
328
-
329
325
  // check if it's a heartbeat request from the server
330
326
  isHeartbeatRequest(data: Buffer): boolean {
327
+ const msg = data.toString('utf-8').trim();
328
+ return msg === '[215,3]';
331
329
  // hearbeatKind = (poll = 1, poll_old = 2, serve = 3)
332
- return ((data[0] === 91) && // [
333
- (data[1] === 50) && // 2
334
- (data[2] === 49) && // 1
335
- (data[3] === 53) && // 5
336
- (data[4] === 44) && // ,
337
- (data[5] === 51) && // 3
338
- (data[6] === 93)); // ]
330
+ // return ((data[0] === 91) && // [
331
+ // (data[1] === 50) && // 2
332
+ // (data[2] === 49) && // 1
333
+ // (data[3] === 53) && // 5
334
+ // (data[4] === 44) && // ,
335
+ // (data[5] === 51) && // 3
336
+ // (data[6] === 93)); // ]
339
337
  }
340
338
 
341
339
  // check if it's a server response after connecting and sending our uniqueID
@@ -346,3 +344,62 @@ export class Context {
346
344
  return (message.startsWith('[OK')) || (message.startsWith('[ERROR'));
347
345
  }
348
346
  }
347
+
348
+ function restart() {
349
+ console.log('🔄 Restarting...');
350
+
351
+ setTimeout(() => {
352
+ spawn(execPath, argv.slice(1), {
353
+ cwd: cwd(),
354
+ detached: true,
355
+ stdio: 'inherit',
356
+ });
357
+
358
+ process.exit(0);
359
+ }, 100);
360
+ }
361
+
362
+
363
+ // Graceful shutdown handler
364
+ function handleShutdown(signal: string) {
365
+ log(`[PROXY] → [SYSTEM] Received ${signal}, shutting down gracefully...`);
366
+
367
+ // Close all cloud connections
368
+ gCloudConnections.forEach(ctx => ctx.cleanupSockets());
369
+ gCloudConnections.splice(0, gCloudConnections.length);
370
+
371
+ log(`[PROXY] → [SYSTEM] All connections closed. Exiting.`);
372
+
373
+ if (config.kind === "solo") {
374
+ log(`[PROXY] → [SYSTEM] Restarting proxy in solo mode...`);
375
+ restart();
376
+ } else {
377
+ log(`[PROXY] → [SYSTEM] Exiting without restart.`);
378
+ setTimeout(() => process.exit(0), 100);
379
+ }
380
+ }
381
+
382
+ // Listen for termination signals
383
+ process.on('SIGINT', () => handleShutdown('SIGINT'));
384
+ process.on('SIGTERM', () => handleShutdown('SIGTERM'));
385
+
386
+
387
+ process.on('SIGINT', (err) => {
388
+ error(`[SYSTEM] received SIGINT`);
389
+ handleShutdown('SIGINT');
390
+ });
391
+
392
+ process.on('SIGTERM', (err) => {
393
+ error(`[SYSTEM] received SIGTERM`);
394
+ handleShutdown('SIGTERM');
395
+ });
396
+
397
+ process.on('uncaughtException', (err) => {
398
+ error(`[SYSTEM] Uncaught Exception: ${err.message}`);
399
+ handleShutdown('uncaughtException');
400
+ });
401
+
402
+ process.on('unhandledRejection', (reason) => {
403
+ error(`[SYSTEM] Unhandled Rejection: ${reason}`);
404
+ handleShutdown('unhandledRejection');
405
+ });