matterbridge 1.3.5 → 1.3.7

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.
Files changed (37) hide show
  1. package/CHANGELOG.md +32 -0
  2. package/README.md +3 -1
  3. package/dist/cluster/ElectricalEnergyMeasurementCluster.js +1 -1
  4. package/dist/cluster/ElectricalEnergyMeasurementCluster.js.map +1 -1
  5. package/dist/cluster/ElectricalPowerMeasurementCluster.js +10 -10
  6. package/dist/cluster/ElectricalPowerMeasurementCluster.js.map +1 -1
  7. package/dist/logger/export.d.ts.map +1 -0
  8. package/dist/logger/export.js.map +1 -0
  9. package/dist/matterbridge.d.ts +4 -4
  10. package/dist/matterbridge.d.ts.map +1 -1
  11. package/dist/matterbridge.js +182 -101
  12. package/dist/matterbridge.js.map +1 -1
  13. package/dist/matterbridgeDevice.d.ts +1 -5
  14. package/dist/matterbridgeDevice.d.ts.map +1 -1
  15. package/dist/matterbridgeDevice.js +9 -9
  16. package/dist/matterbridgeDevice.js.map +1 -1
  17. package/frontend/build/asset-manifest.json +6 -6
  18. package/frontend/build/index.html +1 -1
  19. package/frontend/build/static/css/{main.57bd18a9.css → main.abff2627.css} +8 -2
  20. package/frontend/build/static/css/main.abff2627.css.map +1 -0
  21. package/frontend/build/static/js/{main.c3b5dfce.js → main.942a74a2.js} +3 -3
  22. package/frontend/build/static/js/{main.c3b5dfce.js.map → main.942a74a2.js.map} +1 -1
  23. package/package.json +29 -7
  24. package/dist/cluster/export.d.ts +0 -25
  25. package/dist/cluster/export.d.ts.map +0 -1
  26. package/dist/cluster/export.js +0 -25
  27. package/dist/cluster/export.js.map +0 -1
  28. package/dist/log/export.d.ts.map +0 -1
  29. package/dist/log/export.js.map +0 -1
  30. package/dist/utils/export.d.ts +0 -3
  31. package/dist/utils/export.d.ts.map +0 -1
  32. package/dist/utils/export.js +0 -3
  33. package/dist/utils/export.js.map +0 -1
  34. package/frontend/build/static/css/main.57bd18a9.css.map +0 -1
  35. /package/dist/{log → logger}/export.d.ts +0 -0
  36. /package/dist/{log → logger}/export.js +0 -0
  37. /package/frontend/build/static/js/{main.c3b5dfce.js.LICENSE.txt → main.942a74a2.js.LICENSE.txt} +0 -0
@@ -25,6 +25,7 @@ import { AnsiLogger, BRIGHT, RESET, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugSt
25
25
  import { fileURLToPath, pathToFileURL } from 'url';
26
26
  import { promises as fs } from 'fs';
27
27
  import { exec, spawn } from 'child_process';
28
+ import { createServer } from 'http';
28
29
  import https from 'https';
29
30
  import EventEmitter from 'events';
30
31
  import express from 'express';
@@ -99,17 +100,20 @@ export class Matterbridge extends EventEmitter {
99
100
  bridgeMode = '';
100
101
  restartMode = '';
101
102
  debugEnabled = false;
102
- port = 5540;
103
+ mdnsInterface; // matter server mdnsInterface: 'eth0' or 'wlan0' or 'WiFi'
104
+ port = 5540; // first commissioning server port
103
105
  log;
104
106
  hasCleanupStarted = false;
105
- plugins = new Map();
106
- devices = new Map();
107
+ // private plugins = new Map<string, RegisteredPlugin>();
108
+ // private devices = new Map<string, RegisteredDevice>();
107
109
  registeredPlugins = [];
108
110
  registeredDevices = [];
109
111
  nodeStorage;
110
112
  nodeContext;
111
113
  expressApp;
112
114
  expressServer;
115
+ httpServer;
116
+ httpsServer;
113
117
  webSocketServer;
114
118
  storageManager;
115
119
  matterbridgeContext;
@@ -259,12 +263,17 @@ export class Matterbridge extends EventEmitter {
259
263
  - help: show the help
260
264
  - bridge: start Matterbridge in bridge mode
261
265
  - childbridge: start Matterbridge in childbridge mode
266
+ - port [port]: start the commissioning server on the given port (default 5540)
267
+ - mdnsinterface [name]: set the interface to use for the matter server mdnsInterface (default all interfaces)
262
268
  - frontend [port]: start the frontend on the given port (default 8283)
263
269
  - debug: enable the Matterbridge debug mode (default false)
264
270
  - matterlogger: set the matter.js logger level: debug | info | notice | warn | error | fatal (default info)
265
271
  - reset: remove the commissioning for Matterbridge (bridge mode). Shutdown Matterbridge before using it!
266
272
  - factoryreset: remove all commissioning information and reset all internal storages. Shutdown Matterbridge before using it!
267
273
  - list: list the registered plugins
274
+ - loginterfaces: log the network interfaces
275
+ - logstorage: log the node storage
276
+ - ssl: enable SSL for the frontend and WebSockerServer (certificates in .matterbridge/certs directory cert.pem, key.pem and ca.pem (optional))
268
277
  - add [plugin path]: register the plugin from the given absolute or relative path
269
278
  - add [plugin name]: register the globally installed plugin with the given name
270
279
  - remove [plugin path]: remove the plugin from the given absolute or relative path
@@ -277,7 +286,9 @@ export class Matterbridge extends EventEmitter {
277
286
  - reset [plugin name]: remove the commissioning for the globally installed plugin (childbridge mode). Shutdown Matterbridge before using it!\n`);
278
287
  process.exit(0);
279
288
  }
280
- // Set the first port to use
289
+ // Set the interface to use for the matter server mdnsInterface
290
+ this.mdnsInterface = getParameter('mdnsinterface');
291
+ // Set the first port to use for the commissioning server
281
292
  this.port = getIntParameter('port') ?? 5540;
282
293
  // Set the restart mode
283
294
  if (hasParameter('service'))
@@ -339,11 +350,11 @@ export class Matterbridge extends EventEmitter {
339
350
  }
340
351
  else {
341
352
  this.log.warn(`Invalid matterlogger level: ${level}. Using default level ${this.debugEnabled ? 'debug' : 'info'}.`);
342
- Logger.defaultLogLevel = this.debugEnabled ? Level.DEBUG : Level.INFO;
353
+ Logger.defaultLogLevel = Level.INFO;
343
354
  }
344
355
  }
345
356
  else {
346
- Logger.defaultLogLevel = this.debugEnabled ? Level.DEBUG : Level.INFO;
357
+ Logger.defaultLogLevel = Level.INFO;
347
358
  }
348
359
  Logger.format = Format.ANSI;
349
360
  // Parse command line
@@ -794,7 +805,7 @@ export class Matterbridge extends EventEmitter {
794
805
  this.log.debug('All listeners removed');
795
806
  this.checkUpdateInterval && clearInterval(this.checkUpdateInterval);
796
807
  this.checkUpdateInterval = undefined;
797
- // Calling the shutdown functions with a reason
808
+ // Calling the shutdown method of each plugin
798
809
  for (const plugin of this.registeredPlugins) {
799
810
  if (!plugin.enabled || plugin.error)
800
811
  continue;
@@ -853,14 +864,29 @@ export class Matterbridge extends EventEmitter {
853
864
  // Close the express server
854
865
  if (this.expressServer) {
855
866
  this.expressServer.close();
867
+ this.expressServer.removeAllListeners();
856
868
  this.expressServer = undefined;
857
869
  this.log.debug('Express server closed successfully');
858
870
  }
859
- // Remove listeners
871
+ // Close the http server
872
+ if (this.httpServer) {
873
+ this.httpServer.close();
874
+ this.httpServer.removeAllListeners();
875
+ this.httpServer = undefined;
876
+ this.log.debug('Frontend http server closed successfully');
877
+ }
878
+ // Close the https server
879
+ if (this.httpsServer) {
880
+ this.httpsServer.close();
881
+ this.httpsServer.removeAllListeners();
882
+ this.httpsServer = undefined;
883
+ this.log.debug('Frontend https server closed successfully');
884
+ }
885
+ // Remove listeners from the express app
860
886
  if (this.expressApp) {
861
887
  this.expressApp.removeAllListeners();
862
888
  this.expressApp = undefined;
863
- this.log.debug('Frontend closed successfully');
889
+ this.log.debug('Frontend app closed successfully');
864
890
  }
865
891
  // Close the WebSocket server
866
892
  if (this.webSocketServer) {
@@ -2062,6 +2088,8 @@ export class Matterbridge extends EventEmitter {
2062
2088
  this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with hardwareVersion ${hardwareVersion} hardwareVersionString ${hardwareVersionString}`);
2063
2089
  const commissioningServer = new CommissioningServer({
2064
2090
  port: this.port++,
2091
+ // listeningAddressIpv4
2092
+ // listeningAddressIpv6
2065
2093
  passcode: undefined,
2066
2094
  discriminator: undefined,
2067
2095
  deviceName,
@@ -2166,13 +2194,25 @@ export class Matterbridge extends EventEmitter {
2166
2194
  return commissioningServer;
2167
2195
  }
2168
2196
  /**
2169
- * Creates a Matter server using the provided storage manager.
2197
+ * Creates a Matter server using the provided storage manager and the provided mdnsInterface.
2170
2198
  * @param storageManager The storage manager to be used by the Matter server.
2171
2199
  *
2172
2200
  */
2173
2201
  createMatterServer(storageManager) {
2174
2202
  this.log.debug('Creating matter server');
2175
- const matterServer = new MatterServer(storageManager, { mdnsAnnounceInterface: undefined });
2203
+ // Validate mdnsInterface
2204
+ if (this.mdnsInterface) {
2205
+ const networkInterfaces = os.networkInterfaces();
2206
+ const availableInterfaces = Object.keys(networkInterfaces);
2207
+ if (!availableInterfaces.includes(this.mdnsInterface)) {
2208
+ this.log.error(`Invalid mdnsInterface: ${this.mdnsInterface}. Available interfaces are: ${availableInterfaces.join(', ')}. Using all available interfaces.`);
2209
+ this.mdnsInterface = undefined;
2210
+ }
2211
+ else {
2212
+ this.log.info(`Using mdnsInterface '${this.mdnsInterface}' for the Matter server MdnsBroadcaster.`);
2213
+ }
2214
+ }
2215
+ const matterServer = new MatterServer(storageManager, { mdnsInterface: this.mdnsInterface });
2176
2216
  this.log.debug('Created matter server');
2177
2217
  return matterServer;
2178
2218
  }
@@ -2269,26 +2309,29 @@ export class Matterbridge extends EventEmitter {
2269
2309
  async logNodeAndSystemInfo() {
2270
2310
  // IP address information
2271
2311
  const networkInterfaces = os.networkInterfaces();
2272
- this.systemInformation.ipv4Address = 'Not found';
2273
- this.systemInformation.ipv6Address = 'Not found';
2312
+ this.systemInformation.ipv4Address = '';
2313
+ this.systemInformation.ipv6Address = '';
2274
2314
  for (const [interfaceName, interfaceDetails] of Object.entries(networkInterfaces)) {
2275
2315
  if (!interfaceDetails) {
2276
2316
  break;
2277
2317
  }
2278
2318
  for (const detail of interfaceDetails) {
2279
- if (detail.family === 'IPv4' && !detail.internal && this.systemInformation.ipv4Address === 'Not found') {
2319
+ if (detail.family === 'IPv4' && !detail.internal && this.systemInformation.ipv4Address === '') {
2280
2320
  this.systemInformation.interfaceName = interfaceName;
2281
2321
  this.systemInformation.ipv4Address = detail.address;
2282
2322
  this.systemInformation.macAddress = detail.mac;
2283
2323
  }
2284
- else if (detail.family === 'IPv6' && !detail.internal && this.systemInformation.ipv6Address === 'Not found') {
2324
+ else if (detail.family === 'IPv6' && !detail.internal && this.systemInformation.ipv6Address === '') {
2285
2325
  this.systemInformation.interfaceName = interfaceName;
2286
2326
  this.systemInformation.ipv6Address = detail.address;
2287
2327
  this.systemInformation.macAddress = detail.mac;
2288
2328
  }
2289
2329
  }
2290
- // Break if both addresses are found to improve efficiency
2291
- if (this.systemInformation.ipv4Address !== 'Not found' && this.systemInformation.ipv6Address !== 'Not found') {
2330
+ if (this.systemInformation.ipv4Address !== '' /* && this.systemInformation.ipv6Address !== ''*/) {
2331
+ this.log.debug(`Using interface: '${this.systemInformation.interfaceName}'`);
2332
+ this.log.debug(`- with MAC address: '${this.systemInformation.macAddress}'`);
2333
+ this.log.debug(`- with IPv4 address: '${this.systemInformation.ipv4Address}'`);
2334
+ this.log.debug(`- with IPv6 address: '${this.systemInformation.ipv6Address}'`);
2292
2335
  break;
2293
2336
  }
2294
2337
  }
@@ -2627,64 +2670,156 @@ export class Matterbridge extends EventEmitter {
2627
2670
  * @param port The port number to run the frontend server on. Default is 3000.
2628
2671
  */
2629
2672
  async initializeFrontend(port = 8283) {
2630
- if (hasParameter('test_https')) {
2631
- await this.initializeHttpsFrontend(8443);
2632
- return;
2673
+ this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${port}${db}`);
2674
+ // Create the express app that serves the frontend
2675
+ this.expressApp = express();
2676
+ this.expressApp.use(express.static(path.join(this.rootDirectory, 'frontend/build')));
2677
+ if (!hasParameter('ssl')) {
2678
+ // Create an HTTP server and attach the express app
2679
+ this.httpServer = createServer(this.expressApp);
2680
+ // Listen on the specified port
2681
+ this.httpServer.listen(port, () => {
2682
+ if (this.systemInformation.ipv4Address !== '')
2683
+ this.log.info(`The frontend http server is listening on ${UNDERLINE}http://${this.systemInformation.ipv4Address}:${port}${UNDERLINEOFF}${rs}`);
2684
+ if (this.systemInformation.ipv6Address !== '')
2685
+ this.log.debug(`The frontend http server is listening on ${UNDERLINE}http://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2686
+ });
2687
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2688
+ this.httpServer.on('error', (error) => {
2689
+ this.log.error(`Frontend http server error listening on ${port}`);
2690
+ switch (error.code) {
2691
+ case 'EACCES':
2692
+ this.log.error(`Port ${port} requires elevated privileges`);
2693
+ break;
2694
+ case 'EADDRINUSE':
2695
+ this.log.error(`Port ${port} is already in use`);
2696
+ break;
2697
+ }
2698
+ process.exit(1);
2699
+ });
2633
2700
  }
2634
- this.log.debug(`Initializing the frontend on port ${YELLOW}${port}${db} static ${UNDERLINE}${path.join(this.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
2635
- // Create a WebSocket server
2636
- const wssPort = 8284;
2637
- const wssHost = `ws://${this.systemInformation.ipv4Address}:${wssPort}`;
2638
- this.webSocketServer = new WebSocketServer({ port: wssPort, host: this.systemInformation.ipv4Address });
2639
- this.log.debug(`WebSocket server created on ${UNDERLINE}${wssHost}${UNDERLINEOFF}${rs}`);
2640
- this.webSocketServer.on('connection', (ws) => {
2641
- this.log.info('WebSocketServer client connected');
2701
+ else {
2702
+ // Load the SSL certificate, the private key and optionally the CA certificate
2703
+ let cert;
2704
+ try {
2705
+ cert = await fs.readFile(path.join(this.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
2706
+ this.log.info(`Loaded certificate file ${path.join(this.matterbridgeDirectory, 'certs/cert.pem')}`);
2707
+ }
2708
+ catch (error) {
2709
+ this.log.error(`Error reading certificate file: ${error}`);
2710
+ process.exit(1);
2711
+ }
2712
+ let key;
2713
+ try {
2714
+ key = await fs.readFile(path.join(this.matterbridgeDirectory, 'certs/key.pem'), 'utf8');
2715
+ this.log.info(`Loaded key file ${path.join(this.matterbridgeDirectory, 'certs/key.pem')}`);
2716
+ }
2717
+ catch (error) {
2718
+ this.log.error(`Error reading key file: ${error}`);
2719
+ process.exit(1);
2720
+ }
2721
+ let ca;
2722
+ try {
2723
+ ca = await fs.readFile(path.join(this.matterbridgeDirectory, 'certs/ca.pem'), 'utf8');
2724
+ this.log.info(`Loaded CA certificate file ${path.join(this.matterbridgeDirectory, 'certs/ca.pem')}`);
2725
+ }
2726
+ catch (error) {
2727
+ this.log.info(`CA certificate file ${path.join(this.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
2728
+ }
2729
+ const serverOptions = { cert, key, ca };
2730
+ // Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
2731
+ this.httpsServer = https.createServer(serverOptions, this.expressApp);
2732
+ // Listen on the specified port
2733
+ this.httpsServer.listen(port, () => {
2734
+ if (this.systemInformation.ipv4Address !== '')
2735
+ this.log.info(`The frontend https server is listening on ${UNDERLINE}https://${this.systemInformation.ipv4Address}:${port}${UNDERLINEOFF}${rs}`);
2736
+ if (this.systemInformation.ipv6Address !== '')
2737
+ this.log.debug(`The frontend https server is listening on ${UNDERLINE}https://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2738
+ });
2739
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
2740
+ this.httpsServer.on('error', (error) => {
2741
+ this.log.error(`Frontend https server error listening on ${port}`);
2742
+ switch (error.code) {
2743
+ case 'EACCES':
2744
+ this.log.error(`Port ${port} requires elevated privileges`);
2745
+ break;
2746
+ case 'EADDRINUSE':
2747
+ this.log.error(`Port ${port} is already in use`);
2748
+ break;
2749
+ }
2750
+ process.exit(1);
2751
+ });
2752
+ }
2753
+ // Createe a WebSocket server and attach it to the http server
2754
+ const wssPort = port;
2755
+ const wssHost = hasParameter('ssl') ? `wss://${this.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.systemInformation.ipv4Address}:${wssPort}`;
2756
+ this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
2757
+ this.webSocketServer.on('connection', (ws, request) => {
2758
+ const clientIp = request.socket.remoteAddress;
2759
+ this.log.info(`WebSocketServer client ${clientIp} connected`);
2642
2760
  this.log.setGlobalCallback(this.wssSendMessage.bind(this));
2643
2761
  this.log.debug('WebSocketServer logger callback added');
2644
- this.wssSendMessage('Matterbridge', 'info', 'WebSocketServer client connected to Matterbridge');
2762
+ this.wssSendMessage('Matterbridge', 'info', `WebSocketServer client ${clientIp} connected to Matterbridge`);
2645
2763
  ws.on('message', (message) => {
2646
- this.log.info(`WebSocket client sent a message => ${message}`);
2764
+ this.log.debug(`WebSocket client message: ${message}`);
2647
2765
  });
2648
2766
  ws.on('close', () => {
2649
2767
  this.log.info('WebSocket client disconnected');
2650
2768
  if (this.webSocketServer?.clients.size === 0) {
2651
2769
  this.log.setGlobalCallback(undefined);
2652
- this.log.debug('All WebSocket client disconnected. WebSocketServer logger callback removed');
2770
+ this.log.debug('All WebSocket clients disconnected. WebSocketServer logger callback removed');
2653
2771
  }
2654
2772
  });
2655
2773
  ws.on('error', (error) => {
2656
2774
  this.log.error(`WebSocket client error: ${error}`);
2657
2775
  });
2658
2776
  });
2777
+ this.webSocketServer.on('close', () => {
2778
+ this.log.debug(`WebSocketServer closed`);
2779
+ });
2780
+ this.webSocketServer.on('listening', () => {
2781
+ this.log.info(`The WebSocketServer is listening on ${UNDERLINE}${wssHost}${UNDERLINEOFF}${rs}`);
2782
+ });
2659
2783
  this.webSocketServer.on('error', (ws, error) => {
2660
2784
  this.log.error(`WebSocketServer error: ${error}`);
2661
- return;
2662
2785
  });
2786
+ /*
2787
+ // Create a WebSocket server
2788
+ const wssPort = 8284;
2789
+ const wssHost = `ws://${this.systemInformation.ipv4Address}:${wssPort}`;
2790
+ this.webSocketServer = new WebSocketServer({ port: wssPort, host: this.systemInformation.ipv4Address });
2791
+ this.log.debug(`WebSocket server created on ${UNDERLINE}${wssHost}${UNDERLINEOFF}${rs}`);
2792
+
2663
2793
  this.webSocketServer.on('listening', () => {
2664
- this.log.info(`WebSocketServer is listening on ${UNDERLINE}${wssHost}${UNDERLINEOFF}${rs}`);
2665
- return;
2794
+ this.log.info(`WebSocketServer is listening on ${UNDERLINE}${wssHost}${UNDERLINEOFF}${rs}`);
2795
+ return;
2666
2796
  });
2797
+ */
2798
+ /*
2667
2799
  // Serve React build directory
2668
2800
  this.expressApp = express();
2669
2801
  this.expressApp.use(express.static(path.join(this.rootDirectory, 'frontend/build')));
2802
+
2670
2803
  // Listen on HTTP
2671
2804
  this.expressServer = this.expressApp.listen(port, () => {
2672
- this.log.info(`The frontend is listening on ${UNDERLINE}http://${this.systemInformation.ipv4Address}:${port}${UNDERLINEOFF}${rs}`);
2673
- this.log.debug(`The frontend is listening on ${UNDERLINE}http://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2805
+ this.log.info(`The frontend is listening on ${UNDERLINE}http://${this.systemInformation.ipv4Address}:${port}${UNDERLINEOFF}${rs}`);
2806
+ this.log.debug(`The frontend is listening on ${UNDERLINE}http://[${this.systemInformation.ipv6Address}]:${port}${UNDERLINEOFF}${rs}`);
2674
2807
  });
2808
+
2675
2809
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
2676
- this.expressServer.on('error', (error) => {
2677
- this.log.error(`Frontend error listening on ${UNDERLINE}http://${this.systemInformation.ipv4Address}:${port}${UNDERLINEOFF}${rs}`);
2678
- switch (error.code) {
2679
- case 'EACCES':
2680
- this.log.error(`Port ${port} requires elevated privileges`);
2681
- break;
2682
- case 'EADDRINUSE':
2683
- this.log.error(`Port ${port} is already in use`);
2684
- break;
2685
- }
2686
- process.exit(1);
2810
+ this.expressServer.on('error', (error: any) => {
2811
+ this.log.error(`Frontend error listening on ${UNDERLINE}http://${this.systemInformation.ipv4Address}:${port}${UNDERLINEOFF}${rs}`);
2812
+ switch (error.code) {
2813
+ case 'EACCES':
2814
+ this.log.error(`Port ${port} requires elevated privileges`);
2815
+ break;
2816
+ case 'EADDRINUSE':
2817
+ this.log.error(`Port ${port} is already in use`);
2818
+ break;
2819
+ }
2820
+ process.exit(1);
2687
2821
  });
2822
+ */
2688
2823
  // Endpoint to validate login code
2689
2824
  this.expressApp.post('/api/login', express.json(), async (req, res) => {
2690
2825
  const { password } = req.body;
@@ -3102,60 +3237,6 @@ export class Matterbridge extends EventEmitter {
3102
3237
  });
3103
3238
  this.log.debug(`Frontend initialized on port ${YELLOW}${port}${db} static ${UNDERLINE}${path.join(this.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
3104
3239
  }
3105
- // Just for testing purposes. Use with matterbridge -test_https so no bridge is loaded
3106
- async initializeHttpsFrontend(port = 8443) {
3107
- this.log.debug(`Initializing the https frontend on port ${YELLOW}${port}${db} static ${UNDERLINE}${path.join(this.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
3108
- // Create the express app that serves the frontend
3109
- this.expressApp = express();
3110
- // Load the SSL certificate and private key
3111
- // If we need also the CA certificate, we can add it to the serverOptions object
3112
- // I created dev certificates with openssl using the following commands:
3113
- // openssl genrsa -out key.pem 2048
3114
- // openssl req -new -key key.pem -out csr.pem
3115
- // openssl x509 -req -days 365 -in csr.pem -signkey key.pem -out cert.pem
3116
- const serverOptions = {
3117
- cert: await fs.readFile(path.join(this.matterbridgeDirectory, 'certs/cert.pem'), 'utf8'),
3118
- key: await fs.readFile(path.join(this.matterbridgeDirectory, 'certs/key.pem'), 'utf8'),
3119
- // ca: await fs.readFile(path.join(this.matterbridgeDirectory, 'certs/ca.pem'), 'utf8'),
3120
- };
3121
- // Create an HTTPS server with the SSL certificate and private key and attach the express app
3122
- const httpsServer = https.createServer(serverOptions, this.expressApp);
3123
- // Fallback for routing
3124
- this.expressApp.get('/', (req, res) => {
3125
- this.log.debug('The frontend sent:', req.url);
3126
- res.send('Hello, HTTPS!');
3127
- });
3128
- // Listen on a specific port
3129
- // Connect to the frontend with 'https://localhost:8443'
3130
- httpsServer.listen(port, () => {
3131
- this.log.info(`HTTPS server listening on ${UNDERLINE}'https://localhost:${port}${UNDERLINEOFF}${rs}`);
3132
- });
3133
- // Attach WebSocket server to HTTPS server
3134
- this.webSocketServer = new WebSocketServer({ server: httpsServer });
3135
- this.log.info(`WebSocketServer runnig on ${UNDERLINE}wss://localhost:${port}${UNDERLINEOFF}${rs}`);
3136
- // Handle connections to the WebSocketServer
3137
- // Connect to the WebSocket server using wss from the react frontend this way: const ws = new WebSocket('wss://localhost:8443');
3138
- this.webSocketServer.on('connection', (ws) => {
3139
- this.log.info('WebSocketServer: WebSocket client connected');
3140
- ws.on('message', (message) => {
3141
- this.log.info(`WebSocket client sent message => ${message}`);
3142
- });
3143
- ws.on('close', () => {
3144
- this.log.info('WebSocket client disconnected');
3145
- if (this.webSocketServer?.clients.size === 0) {
3146
- this.log.info('All WebSocket clients disconnected');
3147
- }
3148
- });
3149
- ws.on('error', (error) => {
3150
- this.log.error(`WebSocket client error: ${error}`);
3151
- });
3152
- });
3153
- // Handle error from the WebSocketServer
3154
- this.webSocketServer.on('error', (ws, error) => {
3155
- this.log.error(`WebSocketServer error: ${error}`);
3156
- return;
3157
- });
3158
- }
3159
3240
  /**
3160
3241
  * Retrieves the cluster text from a given device.
3161
3242
  * @param device - The MatterbridgeDevice object.