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.
- package/CHANGELOG.md +32 -0
- package/README.md +3 -1
- package/dist/cluster/ElectricalEnergyMeasurementCluster.js +1 -1
- package/dist/cluster/ElectricalEnergyMeasurementCluster.js.map +1 -1
- package/dist/cluster/ElectricalPowerMeasurementCluster.js +10 -10
- package/dist/cluster/ElectricalPowerMeasurementCluster.js.map +1 -1
- package/dist/logger/export.d.ts.map +1 -0
- package/dist/logger/export.js.map +1 -0
- package/dist/matterbridge.d.ts +4 -4
- package/dist/matterbridge.d.ts.map +1 -1
- package/dist/matterbridge.js +182 -101
- package/dist/matterbridge.js.map +1 -1
- package/dist/matterbridgeDevice.d.ts +1 -5
- package/dist/matterbridgeDevice.d.ts.map +1 -1
- package/dist/matterbridgeDevice.js +9 -9
- package/dist/matterbridgeDevice.js.map +1 -1
- package/frontend/build/asset-manifest.json +6 -6
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/css/{main.57bd18a9.css → main.abff2627.css} +8 -2
- package/frontend/build/static/css/main.abff2627.css.map +1 -0
- package/frontend/build/static/js/{main.c3b5dfce.js → main.942a74a2.js} +3 -3
- package/frontend/build/static/js/{main.c3b5dfce.js.map → main.942a74a2.js.map} +1 -1
- package/package.json +29 -7
- package/dist/cluster/export.d.ts +0 -25
- package/dist/cluster/export.d.ts.map +0 -1
- package/dist/cluster/export.js +0 -25
- package/dist/cluster/export.js.map +0 -1
- package/dist/log/export.d.ts.map +0 -1
- package/dist/log/export.js.map +0 -1
- package/dist/utils/export.d.ts +0 -3
- package/dist/utils/export.d.ts.map +0 -1
- package/dist/utils/export.js +0 -3
- package/dist/utils/export.js.map +0 -1
- package/frontend/build/static/css/main.57bd18a9.css.map +0 -1
- /package/dist/{log → logger}/export.d.ts +0 -0
- /package/dist/{log → logger}/export.js +0 -0
- /package/frontend/build/static/js/{main.c3b5dfce.js.LICENSE.txt → main.942a74a2.js.LICENSE.txt} +0 -0
package/dist/matterbridge.js
CHANGED
|
@@ -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
|
-
|
|
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
|
|
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 =
|
|
353
|
+
Logger.defaultLogLevel = Level.INFO;
|
|
343
354
|
}
|
|
344
355
|
}
|
|
345
356
|
else {
|
|
346
|
-
Logger.defaultLogLevel =
|
|
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
|
|
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
|
-
//
|
|
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
|
-
|
|
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 = '
|
|
2273
|
-
this.systemInformation.ipv6Address = '
|
|
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 === '
|
|
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 === '
|
|
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
|
-
|
|
2291
|
-
|
|
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
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
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
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
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',
|
|
2762
|
+
this.wssSendMessage('Matterbridge', 'info', `WebSocketServer client ${clientIp} connected to Matterbridge`);
|
|
2645
2763
|
ws.on('message', (message) => {
|
|
2646
|
-
this.log.
|
|
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
|
|
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
|
-
|
|
2665
|
-
|
|
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
|
-
|
|
2673
|
-
|
|
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
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
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.
|