matterbridge 2.0.0 → 2.1.0-dev.10
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 +26 -4
- package/README.md +1 -1
- package/dist/cli.js +0 -26
- package/dist/cluster/export.js +0 -2
- package/dist/defaultConfigSchema.js +0 -23
- package/dist/deviceManager.js +1 -26
- package/dist/frontend.js +143 -313
- package/dist/index.js +2 -30
- package/dist/logger/export.js +0 -1
- package/dist/matter/behaviors.js +1 -0
- package/dist/matter/clusters.js +1 -0
- package/dist/matter/devices.js +1 -0
- package/dist/matter/endpoints.js +1 -0
- package/dist/matter/export.js +1 -11
- package/dist/matter/types.js +2 -0
- package/dist/matterbridge.js +77 -715
- package/dist/matterbridgeAccessoryPlatform.js +0 -33
- package/dist/matterbridgeBehaviors.js +38 -38
- package/dist/matterbridgeDeviceTypes.js +11 -112
- package/dist/matterbridgeDynamicPlatform.js +0 -33
- package/dist/matterbridgeEndpoint.js +664 -2563
- package/dist/matterbridgeEndpointHelpers.js +513 -0
- package/dist/matterbridgePlatform.js +5 -125
- package/dist/matterbridgeTypes.js +0 -28
- package/dist/pluginManager.js +3 -240
- package/dist/storage/export.js +0 -1
- package/dist/utils/colorUtils.js +2 -205
- package/dist/utils/export.js +0 -1
- package/dist/utils/utils.js +7 -251
- package/frontend/build/asset-manifest.json +3 -3
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/js/{main.6df4ebe4.js → main.26dbf9b9.js} +3 -3
- package/frontend/build/static/js/{main.6df4ebe4.js.map → main.26dbf9b9.js.map} +1 -1
- package/npm-shrinkwrap.json +86 -78
- package/package.json +22 -4
- package/dist/cli.d.ts +0 -25
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cluster/export.d.ts +0 -2
- package/dist/cluster/export.d.ts.map +0 -1
- package/dist/cluster/export.js.map +0 -1
- package/dist/defaultConfigSchema.d.ts +0 -27
- package/dist/defaultConfigSchema.d.ts.map +0 -1
- package/dist/defaultConfigSchema.js.map +0 -1
- package/dist/deviceManager.d.ts +0 -46
- package/dist/deviceManager.d.ts.map +0 -1
- package/dist/deviceManager.js.map +0 -1
- package/dist/frontend.d.ts +0 -98
- package/dist/frontend.d.ts.map +0 -1
- package/dist/frontend.js.map +0 -1
- package/dist/index.d.ts +0 -34
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/logger/export.d.ts +0 -2
- package/dist/logger/export.d.ts.map +0 -1
- package/dist/logger/export.js.map +0 -1
- package/dist/matter/export.d.ts +0 -10
- package/dist/matter/export.d.ts.map +0 -1
- package/dist/matter/export.js.map +0 -1
- package/dist/matterbridge.d.ts +0 -356
- package/dist/matterbridge.d.ts.map +0 -1
- package/dist/matterbridge.js.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.d.ts +0 -39
- package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
- package/dist/matterbridgeBehaviors.d.ts +0 -963
- package/dist/matterbridgeBehaviors.d.ts.map +0 -1
- package/dist/matterbridgeBehaviors.js.map +0 -1
- package/dist/matterbridgeDeviceTypes.d.ts +0 -177
- package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
- package/dist/matterbridgeDeviceTypes.js.map +0 -1
- package/dist/matterbridgeDynamicPlatform.d.ts +0 -39
- package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
- package/dist/matterbridgeDynamicPlatform.js.map +0 -1
- package/dist/matterbridgeEndpoint.d.ts +0 -10254
- package/dist/matterbridgeEndpoint.d.ts.map +0 -1
- package/dist/matterbridgeEndpoint.js.map +0 -1
- package/dist/matterbridgeEndpointDefault.d.ts +0 -2
- package/dist/matterbridgeEndpointDefault.d.ts.map +0 -1
- package/dist/matterbridgeEndpointDefault.js +0 -159
- package/dist/matterbridgeEndpointDefault.js.map +0 -1
- package/dist/matterbridgePlatform.d.ts +0 -164
- package/dist/matterbridgePlatform.d.ts.map +0 -1
- package/dist/matterbridgePlatform.js.map +0 -1
- package/dist/matterbridgeTypes.d.ts +0 -167
- package/dist/matterbridgeTypes.d.ts.map +0 -1
- package/dist/matterbridgeTypes.js.map +0 -1
- package/dist/pluginManager.d.ts +0 -238
- package/dist/pluginManager.d.ts.map +0 -1
- package/dist/pluginManager.js.map +0 -1
- package/dist/storage/export.d.ts +0 -2
- package/dist/storage/export.d.ts.map +0 -1
- package/dist/storage/export.js.map +0 -1
- package/dist/utils/colorUtils.d.ts +0 -61
- package/dist/utils/colorUtils.d.ts.map +0 -1
- package/dist/utils/colorUtils.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.map +0 -1
- package/dist/utils/utils.d.ts +0 -221
- package/dist/utils/utils.d.ts.map +0 -1
- package/dist/utils/utils.js.map +0 -1
- /package/frontend/build/static/js/{main.6df4ebe4.js.LICENSE.txt → main.26dbf9b9.js.LICENSE.txt} +0 -0
package/dist/frontend.js
CHANGED
|
@@ -1,28 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This file contains the class Frontend.
|
|
3
|
-
*
|
|
4
|
-
* @file frontend.ts
|
|
5
|
-
* @author Luca Liguori
|
|
6
|
-
* @date 2025-01-13
|
|
7
|
-
* @version 1.0.0
|
|
8
|
-
*
|
|
9
|
-
* Copyright 2025, 2026, 2027 Luca Liguori.
|
|
10
|
-
*
|
|
11
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
12
|
-
* you may not use this file except in compliance with the License.
|
|
13
|
-
* You may obtain a copy of the License at
|
|
14
|
-
*
|
|
15
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
16
|
-
*
|
|
17
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
18
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
19
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
20
|
-
* See the License for the specific language governing permissions and
|
|
21
|
-
* limitations under the License. *
|
|
22
|
-
*/
|
|
23
|
-
// @matter
|
|
24
1
|
import { EndpointServer, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat } from '@matter/main';
|
|
25
|
-
// Node modules
|
|
26
2
|
import { createServer } from 'http';
|
|
27
3
|
import https from 'https';
|
|
28
4
|
import express from 'express';
|
|
@@ -30,32 +6,13 @@ import WebSocket, { WebSocketServer } from 'ws';
|
|
|
30
6
|
import os from 'os';
|
|
31
7
|
import path from 'path';
|
|
32
8
|
import { promises as fs } from 'fs';
|
|
33
|
-
// AnsiLogger module
|
|
34
9
|
import { AnsiLogger, CYAN, db, debugStringify, er, nf, rs, stringify, UNDERLINE, UNDERLINEOFF, wr, YELLOW } from './logger/export.js';
|
|
35
|
-
// Matterbridge
|
|
36
10
|
import { createZip, hasParameter, isValidNumber, isValidObject, isValidString } from './utils/utils.js';
|
|
37
11
|
import { plg } from './matterbridgeTypes.js';
|
|
38
12
|
import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
|
|
39
|
-
/**
|
|
40
|
-
* Websocket message ID for logging.
|
|
41
|
-
* @constant {number}
|
|
42
|
-
*/
|
|
43
13
|
export const WS_ID_LOG = 0;
|
|
44
|
-
/**
|
|
45
|
-
* Websocket message ID indicating a refresh is needed.
|
|
46
|
-
* @constant {number}
|
|
47
|
-
*/
|
|
48
14
|
export const WS_ID_REFRESH_NEEDED = 1;
|
|
49
|
-
/**
|
|
50
|
-
* Websocket message ID indicating a restart is needed.
|
|
51
|
-
* @constant {number}
|
|
52
|
-
*/
|
|
53
15
|
export const WS_ID_RESTART_NEEDED = 2;
|
|
54
|
-
/**
|
|
55
|
-
* Initializes the frontend of Matterbridge.
|
|
56
|
-
*
|
|
57
|
-
* @param port The port number to run the frontend server on. Default is 8283.
|
|
58
|
-
*/
|
|
59
16
|
export class Frontend {
|
|
60
17
|
matterbridge;
|
|
61
18
|
log;
|
|
@@ -67,26 +24,15 @@ export class Frontend {
|
|
|
67
24
|
webSocketServer;
|
|
68
25
|
constructor(matterbridge) {
|
|
69
26
|
this.matterbridge = matterbridge;
|
|
70
|
-
this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4
|
|
27
|
+
this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
|
|
71
28
|
}
|
|
72
29
|
async start(port = 8283) {
|
|
73
30
|
this.port = port;
|
|
74
31
|
this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${this.port}${db}`);
|
|
75
|
-
// Create the express app that serves the frontend
|
|
76
32
|
this.expressApp = express();
|
|
77
|
-
// Log all requests to the server for debugging
|
|
78
|
-
/*
|
|
79
|
-
this.expressApp.use((req, res, next) => {
|
|
80
|
-
this.log.debug(`Received request on expressApp: ${req.method} ${req.url}`);
|
|
81
|
-
next();
|
|
82
|
-
});
|
|
83
|
-
*/
|
|
84
|
-
// Serve static files from '/static' endpoint
|
|
85
33
|
this.expressApp.use(express.static(path.join(this.matterbridge.rootDirectory, 'frontend/build')));
|
|
86
34
|
if (!hasParameter('ssl')) {
|
|
87
|
-
// Create an HTTP server and attach the express app
|
|
88
35
|
this.httpServer = createServer(this.expressApp);
|
|
89
|
-
// Listen on the specified port
|
|
90
36
|
if (hasParameter('ingress')) {
|
|
91
37
|
this.httpServer.listen(this.port, '0.0.0.0', () => {
|
|
92
38
|
this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
|
|
@@ -100,7 +46,6 @@ export class Frontend {
|
|
|
100
46
|
this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
|
|
101
47
|
});
|
|
102
48
|
}
|
|
103
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
104
49
|
this.httpServer.on('error', (error) => {
|
|
105
50
|
this.log.error(`Frontend http server error listening on ${this.port}`);
|
|
106
51
|
switch (error.code) {
|
|
@@ -116,7 +61,6 @@ export class Frontend {
|
|
|
116
61
|
});
|
|
117
62
|
}
|
|
118
63
|
else {
|
|
119
|
-
// Load the SSL certificate, the private key and optionally the CA certificate
|
|
120
64
|
let cert;
|
|
121
65
|
try {
|
|
122
66
|
cert = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
|
|
@@ -144,9 +88,7 @@ export class Frontend {
|
|
|
144
88
|
this.log.info(`CA certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
|
|
145
89
|
}
|
|
146
90
|
const serverOptions = { cert, key, ca };
|
|
147
|
-
// Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
|
|
148
91
|
this.httpsServer = https.createServer(serverOptions, this.expressApp);
|
|
149
|
-
// Listen on the specified port
|
|
150
92
|
if (hasParameter('ingress')) {
|
|
151
93
|
this.httpsServer.listen(this.port, '0.0.0.0', () => {
|
|
152
94
|
this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
|
|
@@ -160,7 +102,6 @@ export class Frontend {
|
|
|
160
102
|
this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
|
|
161
103
|
});
|
|
162
104
|
}
|
|
163
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
164
105
|
this.httpsServer.on('error', (error) => {
|
|
165
106
|
this.log.error(`Frontend https server error listening on ${this.port}`);
|
|
166
107
|
switch (error.code) {
|
|
@@ -177,13 +118,12 @@ export class Frontend {
|
|
|
177
118
|
}
|
|
178
119
|
if (this.initializeError)
|
|
179
120
|
return;
|
|
180
|
-
// Createe a WebSocket server and attach it to the http or https server
|
|
181
121
|
const wssPort = this.port;
|
|
182
122
|
const wssHost = hasParameter('ssl') ? `wss://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}`;
|
|
183
123
|
this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
|
|
184
124
|
this.webSocketServer.on('connection', (ws, request) => {
|
|
185
125
|
const clientIp = request.socket.remoteAddress;
|
|
186
|
-
AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug"
|
|
126
|
+
AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug");
|
|
187
127
|
this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
|
|
188
128
|
ws.on('message', (message) => {
|
|
189
129
|
this.wsMessageHandler(ws, message);
|
|
@@ -215,7 +155,6 @@ export class Frontend {
|
|
|
215
155
|
this.webSocketServer.on('error', (ws, error) => {
|
|
216
156
|
this.log.error(`WebSocketServer error: ${error}`);
|
|
217
157
|
});
|
|
218
|
-
// Endpoint to validate login code
|
|
219
158
|
this.expressApp.post('/api/login', express.json(), async (req, res) => {
|
|
220
159
|
const { password } = req.body;
|
|
221
160
|
this.log.debug('The frontend sent /api/login', password);
|
|
@@ -234,33 +173,28 @@ export class Frontend {
|
|
|
234
173
|
this.log.warn('/api/login error wrong password');
|
|
235
174
|
res.json({ valid: false });
|
|
236
175
|
}
|
|
237
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
238
176
|
}
|
|
239
177
|
catch (error) {
|
|
240
178
|
this.log.error('/api/login error getting password');
|
|
241
179
|
res.json({ valid: false });
|
|
242
180
|
}
|
|
243
181
|
});
|
|
244
|
-
// Endpoint to provide health check
|
|
245
182
|
this.expressApp.get('/health', (req, res) => {
|
|
246
183
|
this.log.debug('Express received /health');
|
|
247
184
|
const healthStatus = {
|
|
248
|
-
status: 'ok',
|
|
249
|
-
uptime: process.uptime(),
|
|
250
|
-
timestamp: new Date().toISOString(),
|
|
185
|
+
status: 'ok',
|
|
186
|
+
uptime: process.uptime(),
|
|
187
|
+
timestamp: new Date().toISOString(),
|
|
251
188
|
};
|
|
252
189
|
res.status(200).json(healthStatus);
|
|
253
190
|
});
|
|
254
|
-
// Endpoint to provide memory usage details
|
|
255
191
|
this.expressApp.get('/memory', async (req, res) => {
|
|
256
192
|
this.log.debug('Express received /memory');
|
|
257
|
-
// Function to format bytes to KB or MB
|
|
258
193
|
const formatMemoryUsage = (bytes) => {
|
|
259
194
|
const kb = bytes / 1024;
|
|
260
195
|
const mb = kb / 1024;
|
|
261
196
|
return mb >= 1 ? `${mb.toFixed(2)} MB` : `${kb.toFixed(2)} KB`;
|
|
262
197
|
};
|
|
263
|
-
// Memory usage from process
|
|
264
198
|
const memoryUsageRaw = process.memoryUsage();
|
|
265
199
|
const memoryUsage = {
|
|
266
200
|
rss: formatMemoryUsage(memoryUsageRaw.rss),
|
|
@@ -269,13 +203,10 @@ export class Frontend {
|
|
|
269
203
|
external: formatMemoryUsage(memoryUsageRaw.external),
|
|
270
204
|
arrayBuffers: formatMemoryUsage(memoryUsageRaw.arrayBuffers),
|
|
271
205
|
};
|
|
272
|
-
// V8 heap statistics
|
|
273
206
|
const { default: v8 } = await import('node:v8');
|
|
274
207
|
const heapStatsRaw = v8.getHeapStatistics();
|
|
275
208
|
const heapSpacesRaw = v8.getHeapSpaceStatistics();
|
|
276
|
-
// Format heapStats
|
|
277
209
|
const heapStats = Object.fromEntries(Object.entries(heapStatsRaw).map(([key, value]) => [key, formatMemoryUsage(value)]));
|
|
278
|
-
// Format heapSpaces
|
|
279
210
|
const heapSpaces = heapSpacesRaw.map((space) => ({
|
|
280
211
|
...space,
|
|
281
212
|
space_size: formatMemoryUsage(space.space_size),
|
|
@@ -293,42 +224,29 @@ export class Frontend {
|
|
|
293
224
|
};
|
|
294
225
|
res.status(200).json(memoryReport);
|
|
295
226
|
});
|
|
296
|
-
|
|
227
|
+
this.expressApp.get('/api/advertise', express.json(), async (req, res) => {
|
|
228
|
+
const pairingCodes = await this.matterbridge.advertiseServerNode(this.matterbridge.serverNode);
|
|
229
|
+
if (pairingCodes) {
|
|
230
|
+
const { manualPairingCode, qrPairingCode } = pairingCodes;
|
|
231
|
+
res.json({ manualPairingCode, qrPairingCode: 'https://project-chip.github.io/connectedhomeip/qrcode.html?data=' + qrPairingCode });
|
|
232
|
+
}
|
|
233
|
+
else {
|
|
234
|
+
res.status(500).json({ error: 'Failed to generate pairing codes' });
|
|
235
|
+
}
|
|
236
|
+
});
|
|
297
237
|
this.expressApp.get('/api/settings', express.json(), async (req, res) => {
|
|
298
238
|
this.log.debug('The frontend sent /api/settings');
|
|
299
|
-
|
|
300
|
-
this.matterbridge.matterbridgeInformation.restartMode = this.matterbridge.restartMode;
|
|
301
|
-
this.matterbridge.matterbridgeInformation.loggerLevel = this.log.logLevel;
|
|
302
|
-
this.matterbridge.matterbridgeInformation.matterLoggerLevel = Logger.defaultLogLevel;
|
|
303
|
-
this.matterbridge.matterbridgeInformation.mattermdnsinterface = (await this.matterbridge.nodeContext?.get('mattermdnsinterface', '')) || '';
|
|
304
|
-
this.matterbridge.matterbridgeInformation.matteripv4address = (await this.matterbridge.nodeContext?.get('matteripv4address', '')) || '';
|
|
305
|
-
this.matterbridge.matterbridgeInformation.matteripv6address = (await this.matterbridge.nodeContext?.get('matteripv6address', '')) || '';
|
|
306
|
-
this.matterbridge.matterbridgeInformation.matterPort = (await this.matterbridge.nodeContext?.get('matterport', 5540)) ?? 5540;
|
|
307
|
-
this.matterbridge.matterbridgeInformation.matterDiscriminator = await this.matterbridge.nodeContext?.get('matterdiscriminator');
|
|
308
|
-
this.matterbridge.matterbridgeInformation.matterPasscode = await this.matterbridge.nodeContext?.get('matterpasscode');
|
|
309
|
-
this.matterbridge.matterbridgeInformation.matterbridgePaired = this.matterbridge.matterbridgePaired;
|
|
310
|
-
this.matterbridge.matterbridgeInformation.matterbridgeQrPairingCode = this.matterbridge.matterbridgeQrPairingCode;
|
|
311
|
-
this.matterbridge.matterbridgeInformation.matterbridgeManualPairingCode = this.matterbridge.matterbridgeManualPairingCode;
|
|
312
|
-
this.matterbridge.matterbridgeInformation.matterbridgeFabricInformations = this.matterbridge.matterbridgeFabricInformations;
|
|
313
|
-
this.matterbridge.matterbridgeInformation.matterbridgeSessionInformations = Array.from(this.matterbridge.matterbridgeSessionInformations.values());
|
|
314
|
-
this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
|
|
315
|
-
const response = { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: this.matterbridge.matterbridgeInformation };
|
|
316
|
-
// this.log.debug('Response:', debugStringify(response));
|
|
317
|
-
res.json(response);
|
|
239
|
+
res.json(await this.getApiSettings());
|
|
318
240
|
});
|
|
319
|
-
// Endpoint to provide plugins
|
|
320
241
|
this.expressApp.get('/api/plugins', async (req, res) => {
|
|
321
242
|
this.log.debug('The frontend sent /api/plugins');
|
|
322
|
-
const response =
|
|
323
|
-
// this.log.debug('Response:', debugStringify(response));
|
|
243
|
+
const response = this.getBaseRegisteredPlugins();
|
|
324
244
|
res.json(response);
|
|
325
245
|
});
|
|
326
|
-
// Endpoint to provide devices
|
|
327
246
|
this.expressApp.get('/api/devices', (req, res) => {
|
|
328
247
|
this.log.debug('The frontend sent /api/devices');
|
|
329
248
|
const devices = [];
|
|
330
249
|
this.matterbridge.devices.forEach(async (device) => {
|
|
331
|
-
// Check if the device has the required properties
|
|
332
250
|
if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId)
|
|
333
251
|
return;
|
|
334
252
|
const cluster = this.getClusterTextFromDevice(device);
|
|
@@ -344,10 +262,8 @@ export class Frontend {
|
|
|
344
262
|
cluster: cluster,
|
|
345
263
|
});
|
|
346
264
|
});
|
|
347
|
-
// this.log.debug('Response:', debugStringify(data));
|
|
348
265
|
res.json(devices);
|
|
349
266
|
});
|
|
350
|
-
// Endpoint to provide the cluster servers of the devices
|
|
351
267
|
this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
|
|
352
268
|
const selectedPluginName = req.params.selectedPluginName;
|
|
353
269
|
const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
|
|
@@ -420,7 +336,6 @@ export class Frontend {
|
|
|
420
336
|
});
|
|
421
337
|
res.json(data);
|
|
422
338
|
});
|
|
423
|
-
// Endpoint to view the log
|
|
424
339
|
this.expressApp.get('/api/view-log', async (req, res) => {
|
|
425
340
|
this.log.debug('The frontend sent /api/log');
|
|
426
341
|
try {
|
|
@@ -433,12 +348,10 @@ export class Frontend {
|
|
|
433
348
|
res.status(500).send('Error reading log file');
|
|
434
349
|
}
|
|
435
350
|
});
|
|
436
|
-
// Endpoint to download the matterbridge log
|
|
437
351
|
this.expressApp.get('/api/download-mblog', async (req, res) => {
|
|
438
352
|
this.log.debug('The frontend sent /api/download-mblog');
|
|
439
353
|
try {
|
|
440
354
|
await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), fs.constants.F_OK);
|
|
441
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
442
355
|
}
|
|
443
356
|
catch (error) {
|
|
444
357
|
fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
|
|
@@ -450,12 +363,10 @@ export class Frontend {
|
|
|
450
363
|
}
|
|
451
364
|
});
|
|
452
365
|
});
|
|
453
|
-
// Endpoint to download the matter log
|
|
454
366
|
this.expressApp.get('/api/download-mjlog', async (req, res) => {
|
|
455
367
|
this.log.debug('The frontend sent /api/download-mjlog');
|
|
456
368
|
try {
|
|
457
369
|
await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), fs.constants.F_OK);
|
|
458
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
459
370
|
}
|
|
460
371
|
catch (error) {
|
|
461
372
|
fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
|
|
@@ -467,7 +378,6 @@ export class Frontend {
|
|
|
467
378
|
}
|
|
468
379
|
});
|
|
469
380
|
});
|
|
470
|
-
// Endpoint to download the matter storage file
|
|
471
381
|
this.expressApp.get('/api/download-mjstorage', async (req, res) => {
|
|
472
382
|
this.log.debug('The frontend sent /api/download-mjstorage');
|
|
473
383
|
await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.matterStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterStorageName));
|
|
@@ -478,7 +388,6 @@ export class Frontend {
|
|
|
478
388
|
}
|
|
479
389
|
});
|
|
480
390
|
});
|
|
481
|
-
// Endpoint to download the matterbridge storage directory
|
|
482
391
|
this.expressApp.get('/api/download-mbstorage', async (req, res) => {
|
|
483
392
|
this.log.debug('The frontend sent /api/download-mbstorage');
|
|
484
393
|
await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.nodeStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.nodeStorageName));
|
|
@@ -489,7 +398,6 @@ export class Frontend {
|
|
|
489
398
|
}
|
|
490
399
|
});
|
|
491
400
|
});
|
|
492
|
-
// Endpoint to download the matterbridge plugin directory
|
|
493
401
|
this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
|
|
494
402
|
this.log.debug('The frontend sent /api/download-pluginstorage');
|
|
495
403
|
await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridge.matterbridgePluginDirectory);
|
|
@@ -500,11 +408,9 @@ export class Frontend {
|
|
|
500
408
|
}
|
|
501
409
|
});
|
|
502
410
|
});
|
|
503
|
-
// Endpoint to download the matterbridge plugin config files
|
|
504
411
|
this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
|
|
505
412
|
this.log.debug('The frontend sent /api/download-pluginconfig');
|
|
506
413
|
await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, '*.config.json')));
|
|
507
|
-
// await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, 'certs', '*.*')), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, '*.config.json')));
|
|
508
414
|
res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
|
|
509
415
|
if (error) {
|
|
510
416
|
this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
|
|
@@ -512,7 +418,6 @@ export class Frontend {
|
|
|
512
418
|
}
|
|
513
419
|
});
|
|
514
420
|
});
|
|
515
|
-
// Endpoint to download the matterbridge plugin config files
|
|
516
421
|
this.expressApp.get('/api/download-backup', async (req, res) => {
|
|
517
422
|
this.log.debug('The frontend sent /api/download-backup');
|
|
518
423
|
res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
|
|
@@ -522,7 +427,6 @@ export class Frontend {
|
|
|
522
427
|
}
|
|
523
428
|
});
|
|
524
429
|
});
|
|
525
|
-
// Endpoint to receive commands
|
|
526
430
|
this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
|
|
527
431
|
const command = req.params.command;
|
|
528
432
|
let param = req.params.param;
|
|
@@ -532,15 +436,13 @@ export class Frontend {
|
|
|
532
436
|
return;
|
|
533
437
|
}
|
|
534
438
|
this.log.debug(`Received frontend command: ${command}:${param}`);
|
|
535
|
-
// Handle the command setpassword from Settings
|
|
536
439
|
if (command === 'setpassword') {
|
|
537
|
-
const password = param.slice(1, -1);
|
|
440
|
+
const password = param.slice(1, -1);
|
|
538
441
|
this.log.debug('setpassword', param, password);
|
|
539
442
|
await this.matterbridge.nodeContext?.set('password', password);
|
|
540
443
|
res.json({ message: 'Command received' });
|
|
541
444
|
return;
|
|
542
445
|
}
|
|
543
|
-
// Handle the command setbridgemode from Settings
|
|
544
446
|
if (command === 'setbridgemode') {
|
|
545
447
|
this.log.debug(`setbridgemode: ${param}`);
|
|
546
448
|
this.wssSendRestartRequired();
|
|
@@ -548,7 +450,6 @@ export class Frontend {
|
|
|
548
450
|
res.json({ message: 'Command received' });
|
|
549
451
|
return;
|
|
550
452
|
}
|
|
551
|
-
// Handle the command backup from Settings
|
|
552
453
|
if (command === 'backup') {
|
|
553
454
|
this.log.notice(`Prepairing the backup...`);
|
|
554
455
|
await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridge.matterbridgeDirectory), path.join(this.matterbridge.matterbridgePluginDirectory));
|
|
@@ -556,26 +457,25 @@ export class Frontend {
|
|
|
556
457
|
res.json({ message: 'Command received' });
|
|
557
458
|
return;
|
|
558
459
|
}
|
|
559
|
-
// Handle the command setmbloglevel from Settings
|
|
560
460
|
if (command === 'setmbloglevel') {
|
|
561
461
|
this.log.debug('Matterbridge log level:', param);
|
|
562
462
|
if (param === 'Debug') {
|
|
563
|
-
this.log.logLevel = "debug"
|
|
463
|
+
this.log.logLevel = "debug";
|
|
564
464
|
}
|
|
565
465
|
else if (param === 'Info') {
|
|
566
|
-
this.log.logLevel = "info"
|
|
466
|
+
this.log.logLevel = "info";
|
|
567
467
|
}
|
|
568
468
|
else if (param === 'Notice') {
|
|
569
|
-
this.log.logLevel = "notice"
|
|
469
|
+
this.log.logLevel = "notice";
|
|
570
470
|
}
|
|
571
471
|
else if (param === 'Warn') {
|
|
572
|
-
this.log.logLevel = "warn"
|
|
472
|
+
this.log.logLevel = "warn";
|
|
573
473
|
}
|
|
574
474
|
else if (param === 'Error') {
|
|
575
|
-
this.log.logLevel = "error"
|
|
475
|
+
this.log.logLevel = "error";
|
|
576
476
|
}
|
|
577
477
|
else if (param === 'Fatal') {
|
|
578
|
-
this.log.logLevel = "fatal"
|
|
478
|
+
this.log.logLevel = "fatal";
|
|
579
479
|
}
|
|
580
480
|
await this.matterbridge.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
|
|
581
481
|
MatterbridgeEndpoint.logLevel = this.log.logLevel;
|
|
@@ -583,13 +483,12 @@ export class Frontend {
|
|
|
583
483
|
for (const plugin of this.matterbridge.plugins) {
|
|
584
484
|
if (!plugin.platform || !plugin.platform.config)
|
|
585
485
|
continue;
|
|
586
|
-
plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug"
|
|
587
|
-
await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug"
|
|
486
|
+
plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" : this.log.logLevel;
|
|
487
|
+
await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" : this.log.logLevel);
|
|
588
488
|
}
|
|
589
489
|
res.json({ message: 'Command received' });
|
|
590
490
|
return;
|
|
591
491
|
}
|
|
592
|
-
// Handle the command setmbloglevel from Settings
|
|
593
492
|
if (command === 'setmjloglevel') {
|
|
594
493
|
this.log.debug('Matter.js log level:', param);
|
|
595
494
|
if (param === 'Debug') {
|
|
@@ -614,34 +513,30 @@ export class Frontend {
|
|
|
614
513
|
res.json({ message: 'Command received' });
|
|
615
514
|
return;
|
|
616
515
|
}
|
|
617
|
-
// Handle the command setmdnsinterface from Settings
|
|
618
516
|
if (command === 'setmdnsinterface') {
|
|
619
|
-
param = param.slice(1, -1);
|
|
517
|
+
param = param.slice(1, -1);
|
|
620
518
|
this.matterbridge.matterbridgeInformation.mattermdnsinterface = param;
|
|
621
519
|
this.log.debug('Matter.js mdns interface:', param === '' ? 'All interfaces' : param);
|
|
622
520
|
await this.matterbridge.nodeContext?.set('mattermdnsinterface', param);
|
|
623
521
|
res.json({ message: 'Command received' });
|
|
624
522
|
return;
|
|
625
523
|
}
|
|
626
|
-
// Handle the command setipv4address from Settings
|
|
627
524
|
if (command === 'setipv4address') {
|
|
628
|
-
param = param.slice(1, -1);
|
|
525
|
+
param = param.slice(1, -1);
|
|
629
526
|
this.matterbridge.matterbridgeInformation.matteripv4address = param;
|
|
630
527
|
this.log.debug('Matter.js ipv4 address:', param === '' ? 'All ipv4 addresses' : param);
|
|
631
528
|
await this.matterbridge.nodeContext?.set('matteripv4address', param);
|
|
632
529
|
res.json({ message: 'Command received' });
|
|
633
530
|
return;
|
|
634
531
|
}
|
|
635
|
-
// Handle the command setipv6address from Settings
|
|
636
532
|
if (command === 'setipv6address') {
|
|
637
|
-
param = param.slice(1, -1);
|
|
533
|
+
param = param.slice(1, -1);
|
|
638
534
|
this.matterbridge.matterbridgeInformation.matteripv6address = param;
|
|
639
535
|
this.log.debug('Matter.js ipv6 address:', param === '' ? 'All ipv6 addresses' : param);
|
|
640
536
|
await this.matterbridge.nodeContext?.set('matteripv6address', param);
|
|
641
537
|
res.json({ message: 'Command received' });
|
|
642
538
|
return;
|
|
643
539
|
}
|
|
644
|
-
// Handle the command setmatterport from Settings
|
|
645
540
|
if (command === 'setmatterport') {
|
|
646
541
|
const port = Math.min(Math.max(parseInt(param), 5540), 5560);
|
|
647
542
|
this.matterbridge.matterbridgeInformation.matterPort = port;
|
|
@@ -650,7 +545,6 @@ export class Frontend {
|
|
|
650
545
|
res.json({ message: 'Command received' });
|
|
651
546
|
return;
|
|
652
547
|
}
|
|
653
|
-
// Handle the command setmatterdiscriminator from Settings
|
|
654
548
|
if (command === 'setmatterdiscriminator') {
|
|
655
549
|
const discriminator = Math.min(Math.max(parseInt(param), 1000), 4095);
|
|
656
550
|
this.matterbridge.matterbridgeInformation.matterDiscriminator = discriminator;
|
|
@@ -659,7 +553,6 @@ export class Frontend {
|
|
|
659
553
|
res.json({ message: 'Command received' });
|
|
660
554
|
return;
|
|
661
555
|
}
|
|
662
|
-
// Handle the command setmatterpasscode from Settings
|
|
663
556
|
if (command === 'setmatterpasscode') {
|
|
664
557
|
const passcode = Math.min(Math.max(parseInt(param), 10000000), 90000000);
|
|
665
558
|
this.matterbridge.matterbridgeInformation.matterPasscode = passcode;
|
|
@@ -668,20 +561,17 @@ export class Frontend {
|
|
|
668
561
|
res.json({ message: 'Command received' });
|
|
669
562
|
return;
|
|
670
563
|
}
|
|
671
|
-
// Handle the command setmbloglevel from Settings
|
|
672
564
|
if (command === 'setmblogfile') {
|
|
673
565
|
this.log.debug('Matterbridge file log:', param);
|
|
674
566
|
this.matterbridge.matterbridgeInformation.fileLogger = param === 'true';
|
|
675
567
|
await this.matterbridge.nodeContext?.set('matterbridgeFileLog', param === 'true');
|
|
676
|
-
// Create the file logger for matterbridge
|
|
677
568
|
if (param === 'true')
|
|
678
|
-
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug"
|
|
569
|
+
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug", true);
|
|
679
570
|
else
|
|
680
571
|
AnsiLogger.setGlobalLogfile(undefined);
|
|
681
572
|
res.json({ message: 'Command received' });
|
|
682
573
|
return;
|
|
683
574
|
}
|
|
684
|
-
// Handle the command setmbloglevel from Settings
|
|
685
575
|
if (command === 'setmjlogfile') {
|
|
686
576
|
this.log.debug('Matter file log:', param);
|
|
687
577
|
this.matterbridge.matterbridgeInformation.matterFileLogger = param === 'true';
|
|
@@ -708,43 +598,36 @@ export class Frontend {
|
|
|
708
598
|
res.json({ message: 'Command received' });
|
|
709
599
|
return;
|
|
710
600
|
}
|
|
711
|
-
// Handle the command unregister from Settings
|
|
712
601
|
if (command === 'unregister') {
|
|
713
602
|
await this.matterbridge.unregisterAndShutdownProcess();
|
|
714
603
|
res.json({ message: 'Command received' });
|
|
715
604
|
return;
|
|
716
605
|
}
|
|
717
|
-
// Handle the command reset from Settings
|
|
718
606
|
if (command === 'reset') {
|
|
719
607
|
await this.matterbridge.shutdownProcessAndReset();
|
|
720
608
|
res.json({ message: 'Command received' });
|
|
721
609
|
return;
|
|
722
610
|
}
|
|
723
|
-
// Handle the command factoryreset from Settings
|
|
724
611
|
if (command === 'factoryreset') {
|
|
725
612
|
await this.matterbridge.shutdownProcessAndFactoryReset();
|
|
726
613
|
res.json({ message: 'Command received' });
|
|
727
614
|
return;
|
|
728
615
|
}
|
|
729
|
-
// Handle the command shutdown from Header
|
|
730
616
|
if (command === 'shutdown') {
|
|
731
617
|
await this.matterbridge.shutdownProcess();
|
|
732
618
|
res.json({ message: 'Command received' });
|
|
733
619
|
return;
|
|
734
620
|
}
|
|
735
|
-
// Handle the command restart from Header
|
|
736
621
|
if (command === 'restart') {
|
|
737
622
|
await this.matterbridge.restartProcess();
|
|
738
623
|
res.json({ message: 'Command received' });
|
|
739
624
|
return;
|
|
740
625
|
}
|
|
741
|
-
// Handle the command update from Header
|
|
742
626
|
if (command === 'update') {
|
|
743
627
|
this.log.info('Updating matterbridge...');
|
|
744
628
|
try {
|
|
745
629
|
await this.matterbridge.spawnCommand('npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose']);
|
|
746
630
|
this.log.info('Matterbridge has been updated. Full restart required.');
|
|
747
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
748
631
|
}
|
|
749
632
|
catch (error) {
|
|
750
633
|
this.log.error('Error updating matterbridge');
|
|
@@ -754,11 +637,9 @@ export class Frontend {
|
|
|
754
637
|
res.json({ message: 'Command received' });
|
|
755
638
|
return;
|
|
756
639
|
}
|
|
757
|
-
// Handle the command saveconfig from Home
|
|
758
640
|
if (command === 'saveconfig') {
|
|
759
641
|
param = param.replace(/\*/g, '\\');
|
|
760
642
|
this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
|
|
761
|
-
// console.log('Req.body:', JSON.stringify(req.body, null, 2));
|
|
762
643
|
if (!this.matterbridge.plugins.has(param)) {
|
|
763
644
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
764
645
|
}
|
|
@@ -772,58 +653,49 @@ export class Frontend {
|
|
|
772
653
|
res.json({ message: 'Command received' });
|
|
773
654
|
return;
|
|
774
655
|
}
|
|
775
|
-
// Handle the command installplugin from Home
|
|
776
656
|
if (command === 'installplugin') {
|
|
777
657
|
param = param.replace(/\*/g, '\\');
|
|
778
658
|
this.log.info(`Installing plugin ${plg}${param}${nf}...`);
|
|
779
659
|
try {
|
|
780
660
|
await this.matterbridge.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
|
|
781
661
|
this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
|
|
782
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
783
662
|
}
|
|
784
663
|
catch (error) {
|
|
785
664
|
this.log.error(`Error installing plugin ${plg}${param}${er}`);
|
|
786
665
|
}
|
|
787
666
|
this.wssSendRestartRequired();
|
|
788
667
|
param = param.split('@')[0];
|
|
789
|
-
// Also add the plugin to matterbridge so no return!
|
|
790
668
|
if (param === 'matterbridge') {
|
|
791
|
-
// If we used the command installplugin to install a dev or a specific version of matterbridge we don't want to add it to matterbridge
|
|
792
669
|
res.json({ message: 'Command received' });
|
|
793
670
|
return;
|
|
794
671
|
}
|
|
795
672
|
}
|
|
796
|
-
// Handle the command addplugin from Home
|
|
797
673
|
if (command === 'addplugin' || command === 'installplugin') {
|
|
798
674
|
param = param.replace(/\*/g, '\\');
|
|
799
675
|
const plugin = await this.matterbridge.plugins.add(param);
|
|
800
676
|
if (plugin) {
|
|
801
677
|
if (this.matterbridge.bridgeMode === 'childbridge') {
|
|
802
|
-
// We don't know now if the plugin is a dynamic platform or an accessory platform so we create the server node and the aggregator node
|
|
803
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
804
678
|
this.matterbridge.createDynamicPlugin(plugin, true);
|
|
805
679
|
}
|
|
806
|
-
this.matterbridge.plugins.load(plugin, true, 'The plugin has been added', true);
|
|
680
|
+
this.matterbridge.plugins.load(plugin, true, 'The plugin has been added', true);
|
|
807
681
|
}
|
|
808
682
|
res.json({ message: 'Command received' });
|
|
809
683
|
this.wssSendRefreshRequired();
|
|
810
684
|
return;
|
|
811
685
|
}
|
|
812
|
-
// Handle the command removeplugin from Home
|
|
813
686
|
if (command === 'removeplugin') {
|
|
814
687
|
if (!this.matterbridge.plugins.has(param)) {
|
|
815
688
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
816
689
|
}
|
|
817
690
|
else {
|
|
818
691
|
const plugin = this.matterbridge.plugins.get(param);
|
|
819
|
-
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true);
|
|
692
|
+
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true);
|
|
820
693
|
await this.matterbridge.plugins.remove(param);
|
|
821
694
|
}
|
|
822
695
|
res.json({ message: 'Command received' });
|
|
823
696
|
this.wssSendRefreshRequired();
|
|
824
697
|
return;
|
|
825
698
|
}
|
|
826
|
-
// Handle the command enableplugin from Home
|
|
827
699
|
if (command === 'enableplugin') {
|
|
828
700
|
if (!this.matterbridge.plugins.has(param)) {
|
|
829
701
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
@@ -841,17 +713,15 @@ export class Frontend {
|
|
|
841
713
|
plugin.addedDevices = undefined;
|
|
842
714
|
await this.matterbridge.plugins.enable(param);
|
|
843
715
|
if (this.matterbridge.bridgeMode === 'childbridge' && plugin.type === 'DynamicPlatform') {
|
|
844
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
845
716
|
this.matterbridge.createDynamicPlugin(plugin, true);
|
|
846
717
|
}
|
|
847
|
-
this.matterbridge.plugins.load(plugin, true, 'The plugin has been enabled', true);
|
|
718
|
+
this.matterbridge.plugins.load(plugin, true, 'The plugin has been enabled', true);
|
|
848
719
|
}
|
|
849
720
|
}
|
|
850
721
|
res.json({ message: 'Command received' });
|
|
851
722
|
this.wssSendRefreshRequired();
|
|
852
723
|
return;
|
|
853
724
|
}
|
|
854
|
-
// Handle the command disableplugin from Home
|
|
855
725
|
if (command === 'disableplugin') {
|
|
856
726
|
if (!this.matterbridge.plugins.has(param)) {
|
|
857
727
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
@@ -859,7 +729,7 @@ export class Frontend {
|
|
|
859
729
|
else {
|
|
860
730
|
const plugin = this.matterbridge.plugins.get(param);
|
|
861
731
|
if (plugin && plugin.enabled) {
|
|
862
|
-
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true);
|
|
732
|
+
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true);
|
|
863
733
|
await this.matterbridge.plugins.disable(param);
|
|
864
734
|
}
|
|
865
735
|
}
|
|
@@ -868,7 +738,6 @@ export class Frontend {
|
|
|
868
738
|
return;
|
|
869
739
|
}
|
|
870
740
|
});
|
|
871
|
-
// Fallback for routing (must be the last route)
|
|
872
741
|
this.expressApp.get('*', (req, res) => {
|
|
873
742
|
this.log.debug('The frontend sent:', req.url);
|
|
874
743
|
this.log.debug('Response send file:', path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
|
|
@@ -877,29 +746,24 @@ export class Frontend {
|
|
|
877
746
|
this.log.debug(`Frontend initialized on port ${YELLOW}${this.port}${db} static ${UNDERLINE}${path.join(this.matterbridge.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
|
|
878
747
|
}
|
|
879
748
|
async stop() {
|
|
880
|
-
// Close the http server
|
|
881
749
|
if (this.httpServer) {
|
|
882
750
|
this.httpServer.close();
|
|
883
751
|
this.httpServer.removeAllListeners();
|
|
884
752
|
this.httpServer = undefined;
|
|
885
753
|
this.log.debug('Frontend http server closed successfully');
|
|
886
754
|
}
|
|
887
|
-
// Close the https server
|
|
888
755
|
if (this.httpsServer) {
|
|
889
756
|
this.httpsServer.close();
|
|
890
757
|
this.httpsServer.removeAllListeners();
|
|
891
758
|
this.httpsServer = undefined;
|
|
892
759
|
this.log.debug('Frontend https server closed successfully');
|
|
893
760
|
}
|
|
894
|
-
// Remove listeners from the express app
|
|
895
761
|
if (this.expressApp) {
|
|
896
762
|
this.expressApp.removeAllListeners();
|
|
897
763
|
this.expressApp = undefined;
|
|
898
764
|
this.log.debug('Frontend app closed successfully');
|
|
899
765
|
}
|
|
900
|
-
// Close the WebSocket server
|
|
901
766
|
if (this.webSocketServer) {
|
|
902
|
-
// Close all active connections
|
|
903
767
|
this.webSocketServer.clients.forEach((client) => {
|
|
904
768
|
if (client.readyState === WebSocket.OPEN) {
|
|
905
769
|
client.close();
|
|
@@ -916,11 +780,25 @@ export class Frontend {
|
|
|
916
780
|
this.webSocketServer = undefined;
|
|
917
781
|
}
|
|
918
782
|
}
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
783
|
+
async getApiSettings() {
|
|
784
|
+
this.matterbridge.matterbridgeInformation.bridgeMode = this.matterbridge.bridgeMode;
|
|
785
|
+
this.matterbridge.matterbridgeInformation.restartMode = this.matterbridge.restartMode;
|
|
786
|
+
this.matterbridge.matterbridgeInformation.loggerLevel = this.log.logLevel;
|
|
787
|
+
this.matterbridge.matterbridgeInformation.matterLoggerLevel = Logger.defaultLogLevel;
|
|
788
|
+
this.matterbridge.matterbridgeInformation.mattermdnsinterface = this.matterbridge.mdnsInterface;
|
|
789
|
+
this.matterbridge.matterbridgeInformation.matteripv4address = this.matterbridge.ipv4address;
|
|
790
|
+
this.matterbridge.matterbridgeInformation.matteripv6address = this.matterbridge.ipv6address;
|
|
791
|
+
this.matterbridge.matterbridgeInformation.matterPort = (await this.matterbridge.nodeContext?.get('matterport', 5540)) ?? 5540;
|
|
792
|
+
this.matterbridge.matterbridgeInformation.matterDiscriminator = await this.matterbridge.nodeContext?.get('matterdiscriminator');
|
|
793
|
+
this.matterbridge.matterbridgeInformation.matterPasscode = await this.matterbridge.nodeContext?.get('matterpasscode');
|
|
794
|
+
this.matterbridge.matterbridgeInformation.matterbridgePaired = this.matterbridge.matterbridgePaired;
|
|
795
|
+
this.matterbridge.matterbridgeInformation.matterbridgeQrPairingCode = this.matterbridge.matterbridgeQrPairingCode;
|
|
796
|
+
this.matterbridge.matterbridgeInformation.matterbridgeManualPairingCode = this.matterbridge.matterbridgeManualPairingCode;
|
|
797
|
+
this.matterbridge.matterbridgeInformation.matterbridgeFabricInformations = this.matterbridge.matterbridgeFabricInformations;
|
|
798
|
+
this.matterbridge.matterbridgeInformation.matterbridgeSessionInformations = this.matterbridge.matterbridgeSessionInformations;
|
|
799
|
+
this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
|
|
800
|
+
return { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: this.matterbridge.matterbridgeInformation };
|
|
801
|
+
}
|
|
924
802
|
getClusterTextFromDevice(device) {
|
|
925
803
|
const getAttribute = (device, cluster, attribute) => {
|
|
926
804
|
let value = undefined;
|
|
@@ -958,85 +836,87 @@ export class Frontend {
|
|
|
958
836
|
return '';
|
|
959
837
|
};
|
|
960
838
|
let attributes = '';
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
839
|
+
device.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
|
|
840
|
+
if (typeof attributeValue === 'undefined')
|
|
841
|
+
return;
|
|
842
|
+
if (clusterName === 'onOff' && attributeName === 'onOff')
|
|
843
|
+
attributes += `OnOff: ${attributeValue} `;
|
|
844
|
+
if (clusterName === 'switch' && attributeName === 'currentPosition')
|
|
845
|
+
attributes += `Position: ${attributeValue} `;
|
|
846
|
+
if (clusterName === 'windowCovering' && attributeName === 'currentPositionLiftPercent100ths' && isValidNumber(attributeValue, 0, 10000))
|
|
847
|
+
attributes += `Cover position: ${attributeValue / 100}% `;
|
|
848
|
+
if (clusterName === 'doorLock' && attributeName === 'lockState')
|
|
849
|
+
attributes += `State: ${attributeValue === 1 ? 'Locked' : 'Not locked'} `;
|
|
850
|
+
if (clusterName === 'thermostat' && attributeName === 'localTemperature' && isValidNumber(attributeValue))
|
|
851
|
+
attributes += `Temperature: ${attributeValue / 100}°C `;
|
|
852
|
+
if (clusterName === 'thermostat' && attributeName === 'occupiedHeatingSetpoint' && isValidNumber(attributeValue))
|
|
853
|
+
attributes += `Heat to: ${attributeValue / 100}°C `;
|
|
854
|
+
if (clusterName === 'thermostat' && attributeName === 'occupiedCoolingSetpoint' && isValidNumber(attributeValue))
|
|
855
|
+
attributes += `Cool to: ${attributeValue / 100}°C `;
|
|
856
|
+
if (clusterName === 'pumpConfigurationAndControl' && attributeName === 'operationMode')
|
|
857
|
+
attributes += `Mode: ${attributeValue} `;
|
|
858
|
+
if (clusterName === 'valveConfigurationAndControl' && attributeName === 'currentState')
|
|
859
|
+
attributes += `State: ${attributeValue} `;
|
|
860
|
+
if (clusterName === 'levelControl' && attributeName === 'currentLevel')
|
|
861
|
+
attributes += `Level: ${attributeValue} `;
|
|
862
|
+
if (clusterName === 'colorControl' && attributeName === 'colorMode' && isValidNumber(attributeValue, 0, 2))
|
|
863
|
+
attributes += `Mode: ${['HS', 'XY', 'CT'][attributeValue]} `;
|
|
864
|
+
if (clusterName === 'colorControl' && getAttribute(device, 'colorControl', 'colorMode') === 0 && attributeName === 'currentHue' && isValidNumber(attributeValue))
|
|
865
|
+
attributes += `Hue: ${Math.round(attributeValue)} `;
|
|
866
|
+
if (clusterName === 'colorControl' && getAttribute(device, 'colorControl', 'colorMode') === 0 && attributeName === 'currentSaturation' && isValidNumber(attributeValue))
|
|
867
|
+
attributes += `Saturation: ${Math.round(attributeValue)} `;
|
|
868
|
+
if (clusterName === 'colorControl' && getAttribute(device, 'colorControl', 'colorMode') === 1 && attributeName === 'currentX' && isValidNumber(attributeValue))
|
|
869
|
+
attributes += `X: ${Math.round(attributeValue / 655.36) / 100} `;
|
|
870
|
+
if (clusterName === 'colorControl' && getAttribute(device, 'colorControl', 'colorMode') === 1 && attributeName === 'currentY' && isValidNumber(attributeValue))
|
|
871
|
+
attributes += `Y: ${Math.round(attributeValue / 655.36) / 100} `;
|
|
872
|
+
if (clusterName === 'colorControl' && getAttribute(device, 'colorControl', 'colorMode') === 2 && attributeName === 'colorTemperatureMireds' && isValidNumber(attributeValue))
|
|
873
|
+
attributes += `ColorTemp: ${Math.round(attributeValue)} `;
|
|
874
|
+
if (clusterName === 'booleanState' && attributeName === 'stateValue')
|
|
875
|
+
attributes += `Contact: ${attributeValue} `;
|
|
876
|
+
if (clusterName === 'booleanStateConfiguration' && attributeName === 'alarmsActive' && isValidObject(attributeValue))
|
|
877
|
+
attributes += `Active alarms: ${stringify(attributeValue)} `;
|
|
878
|
+
if (clusterName === 'smokeCoAlarm' && attributeName === 'smokeState')
|
|
879
|
+
attributes += `Smoke: ${attributeValue} `;
|
|
880
|
+
if (clusterName === 'smokeCoAlarm' && attributeName === 'coState')
|
|
881
|
+
attributes += `Co: ${attributeValue} `;
|
|
882
|
+
if (clusterName === 'fanControl' && attributeName === 'fanMode')
|
|
883
|
+
attributes += `Mode: ${attributeValue} `;
|
|
884
|
+
if (clusterName === 'fanControl' && attributeName === 'percentCurrent')
|
|
885
|
+
attributes += `Percent: ${attributeValue} `;
|
|
886
|
+
if (clusterName === 'fanControl' && attributeName === 'speedCurrent')
|
|
887
|
+
attributes += `Speed: ${attributeValue} `;
|
|
888
|
+
if (clusterName === 'occupancySensing' && attributeName === 'occupancy' && isValidObject(attributeValue, 1))
|
|
889
|
+
attributes += `Occupancy: ${attributeValue.occupied} `;
|
|
890
|
+
if (clusterName === 'illuminanceMeasurement' && attributeName === 'measuredValue' && isValidNumber(attributeValue))
|
|
891
|
+
attributes += `Illuminance: ${Math.round(Math.max(Math.pow(10, attributeValue / 10000), 0))} `;
|
|
892
|
+
if (clusterName === 'airQuality' && attributeName === 'airQuality')
|
|
893
|
+
attributes += `Air quality: ${attributeValue} `;
|
|
894
|
+
if (clusterName === 'totalVolatileOrganicCompoundsConcentrationMeasurement' && attributeName === 'measuredValue')
|
|
895
|
+
attributes += `Voc: ${attributeValue} `;
|
|
896
|
+
if (clusterName === 'pm1ConcentrationMeasurement' && attributeName === 'measuredValue')
|
|
897
|
+
attributes += `Pm1: ${attributeValue} `;
|
|
898
|
+
if (clusterName === 'pm25ConcentrationMeasurement' && attributeName === 'measuredValue')
|
|
899
|
+
attributes += `Pm2.5: ${attributeValue} `;
|
|
900
|
+
if (clusterName === 'pm10ConcentrationMeasurement' && attributeName === 'measuredValue')
|
|
901
|
+
attributes += `Pm10: ${attributeValue} `;
|
|
902
|
+
if (clusterName === 'formaldehydeConcentrationMeasurement' && attributeName === 'measuredValue')
|
|
903
|
+
attributes += `CH₂O: ${attributeValue} `;
|
|
904
|
+
if (clusterName === 'temperatureMeasurement' && attributeName === 'measuredValue' && isValidNumber(attributeValue))
|
|
905
|
+
attributes += `Temperature: ${attributeValue / 100}°C `;
|
|
906
|
+
if (clusterName === 'relativeHumidityMeasurement' && attributeName === 'measuredValue' && isValidNumber(attributeValue))
|
|
907
|
+
attributes += `Humidity: ${attributeValue / 100}% `;
|
|
908
|
+
if (clusterName === 'pressureMeasurement' && attributeName === 'measuredValue')
|
|
909
|
+
attributes += `Pressure: ${attributeValue} `;
|
|
910
|
+
if (clusterName === 'flowMeasurement' && attributeName === 'measuredValue')
|
|
911
|
+
attributes += `Flow: ${attributeValue} `;
|
|
912
|
+
if (clusterName === 'fixedLabel' && attributeName === 'labelList')
|
|
913
|
+
attributes += `${getFixedLabel(device)} `;
|
|
914
|
+
if (clusterName === 'userLabel' && attributeName === 'labelList')
|
|
915
|
+
attributes += `${getUserLabel(device)} `;
|
|
1032
916
|
});
|
|
1033
917
|
return attributes.trimStart().trimEnd();
|
|
1034
918
|
}
|
|
1035
|
-
|
|
1036
|
-
* Retrieves the base registered plugins sanitized for res.json().
|
|
1037
|
-
* @returns {BaseRegisteredPlugin[]} A promise that resolves to an array of BaseRegisteredPlugin objects.
|
|
1038
|
-
*/
|
|
1039
|
-
async getBaseRegisteredPlugins() {
|
|
919
|
+
getBaseRegisteredPlugins() {
|
|
1040
920
|
const baseRegisteredPlugins = [];
|
|
1041
921
|
for (const plugin of this.matterbridge.plugins) {
|
|
1042
922
|
baseRegisteredPlugins.push({
|
|
@@ -1066,14 +946,6 @@ export class Frontend {
|
|
|
1066
946
|
}
|
|
1067
947
|
return baseRegisteredPlugins;
|
|
1068
948
|
}
|
|
1069
|
-
/**
|
|
1070
|
-
* Handles incoming websocket messages for the Matterbridge.
|
|
1071
|
-
*
|
|
1072
|
-
* @param {Matterbridge} this - The Matterbridge instance.
|
|
1073
|
-
* @param {WebSocket} client - The websocket client that sent the message.
|
|
1074
|
-
* @param {WebSocket.RawData} message - The raw data of the message received from the client.
|
|
1075
|
-
* @returns {Promise<void>} A promise that resolves when the message has been handled.
|
|
1076
|
-
*/
|
|
1077
949
|
async wsMessageHandler(client, message) {
|
|
1078
950
|
let data;
|
|
1079
951
|
try {
|
|
@@ -1144,39 +1016,25 @@ export class Frontend {
|
|
|
1144
1016
|
await this.matterbridge.shutdownProcess();
|
|
1145
1017
|
return;
|
|
1146
1018
|
}
|
|
1019
|
+
else if (data.method === '/api/advertise') {
|
|
1020
|
+
const pairingCodes = await this.matterbridge.advertiseServerNode(this.matterbridge.serverNode);
|
|
1021
|
+
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: pairingCodes }));
|
|
1022
|
+
return;
|
|
1023
|
+
}
|
|
1147
1024
|
else if (data.method === '/api/settings') {
|
|
1148
|
-
|
|
1149
|
-
this.matterbridge.matterbridgeInformation.restartMode = this.matterbridge.restartMode;
|
|
1150
|
-
this.matterbridge.matterbridgeInformation.loggerLevel = this.log.logLevel;
|
|
1151
|
-
this.matterbridge.matterbridgeInformation.matterLoggerLevel = Logger.defaultLogLevel;
|
|
1152
|
-
this.matterbridge.matterbridgeInformation.mattermdnsinterface = (await this.matterbridge.nodeContext?.get('mattermdnsinterface', '')) || '';
|
|
1153
|
-
this.matterbridge.matterbridgeInformation.matteripv4address = (await this.matterbridge.nodeContext?.get('matteripv4address', '')) || '';
|
|
1154
|
-
this.matterbridge.matterbridgeInformation.matteripv6address = (await this.matterbridge.nodeContext?.get('matteripv6address', '')) || '';
|
|
1155
|
-
this.matterbridge.matterbridgeInformation.matterPort = (await this.matterbridge.nodeContext?.get('matterport', 5540)) ?? 5540;
|
|
1156
|
-
this.matterbridge.matterbridgeInformation.matterDiscriminator = await this.matterbridge.nodeContext?.get('matterdiscriminator');
|
|
1157
|
-
this.matterbridge.matterbridgeInformation.matterPasscode = await this.matterbridge.nodeContext?.get('matterpasscode');
|
|
1158
|
-
this.matterbridge.matterbridgeInformation.matterbridgePaired = this.matterbridge.matterbridgePaired;
|
|
1159
|
-
this.matterbridge.matterbridgeInformation.matterbridgeQrPairingCode = this.matterbridge.matterbridgeQrPairingCode;
|
|
1160
|
-
this.matterbridge.matterbridgeInformation.matterbridgeManualPairingCode = this.matterbridge.matterbridgeManualPairingCode;
|
|
1161
|
-
this.matterbridge.matterbridgeInformation.matterbridgeFabricInformations = this.matterbridge.matterbridgeFabricInformations;
|
|
1162
|
-
this.matterbridge.matterbridgeInformation.matterbridgeSessionInformations = Array.from(this.matterbridge.matterbridgeSessionInformations.values());
|
|
1163
|
-
this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
|
|
1164
|
-
const response = { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: this.matterbridge.matterbridgeInformation };
|
|
1165
|
-
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response }));
|
|
1025
|
+
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: await this.getApiSettings() }));
|
|
1166
1026
|
return;
|
|
1167
1027
|
}
|
|
1168
1028
|
else if (data.method === '/api/plugins') {
|
|
1169
|
-
const response =
|
|
1029
|
+
const response = this.getBaseRegisteredPlugins();
|
|
1170
1030
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response }));
|
|
1171
1031
|
return;
|
|
1172
1032
|
}
|
|
1173
1033
|
else if (data.method === '/api/devices') {
|
|
1174
1034
|
const devices = [];
|
|
1175
1035
|
this.matterbridge.devices.forEach(async (device) => {
|
|
1176
|
-
// Filter by pluginName if provided
|
|
1177
1036
|
if (data.params.pluginName && data.params.pluginName !== device.plugin)
|
|
1178
1037
|
return;
|
|
1179
|
-
// Check if the device has the required properties
|
|
1180
1038
|
if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId)
|
|
1181
1039
|
return;
|
|
1182
1040
|
const cluster = this.getClusterTextFromDevice(device);
|
|
@@ -1220,8 +1078,11 @@ export class Frontend {
|
|
|
1220
1078
|
const clusterServers = endpointServer.getAllClusterServers();
|
|
1221
1079
|
clusterServers.forEach((clusterServer) => {
|
|
1222
1080
|
Object.entries(clusterServer.attributes).forEach(([key, value]) => {
|
|
1223
|
-
if (clusterServer.name === 'EveHistory')
|
|
1224
|
-
|
|
1081
|
+
if (clusterServer.name === 'EveHistory') {
|
|
1082
|
+
if (['configDataGet', 'configDataSet', 'historyStatus', 'historyEntries', 'historyRequest', 'historySetTime', 'rLoc'].includes(key)) {
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1225
1086
|
if (clusterServer.name === 'Descriptor' && key === 'deviceTypeList') {
|
|
1226
1087
|
value.getLocal().forEach((deviceType) => {
|
|
1227
1088
|
deviceTypes.push(deviceType.deviceType);
|
|
@@ -1256,7 +1117,6 @@ export class Frontend {
|
|
|
1256
1117
|
});
|
|
1257
1118
|
endpointServer.getChildEndpoints().forEach((childEndpoint) => {
|
|
1258
1119
|
deviceTypes = [];
|
|
1259
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1260
1120
|
const name = childEndpoint.endpoint?.id;
|
|
1261
1121
|
const clusterServers = childEndpoint.getAllClusterServers();
|
|
1262
1122
|
clusterServers.forEach((clusterServer) => {
|
|
@@ -1339,73 +1199,44 @@ export class Frontend {
|
|
|
1339
1199
|
return;
|
|
1340
1200
|
}
|
|
1341
1201
|
}
|
|
1342
|
-
/**
|
|
1343
|
-
* Sends a WebSocket message to all connected clients. The function is called by AnsiLogger.setGlobalCallback.
|
|
1344
|
-
*
|
|
1345
|
-
* @param {string} level - The logger level of the message: debug info notice warn error fatal...
|
|
1346
|
-
* @param {string} time - The time string of the message
|
|
1347
|
-
* @param {string} name - The logger name of the message
|
|
1348
|
-
* @param {string} message - The content of the message.
|
|
1349
|
-
*/
|
|
1350
1202
|
wssSendMessage(level, time, name, message) {
|
|
1351
1203
|
if (!level || !time || !name || !message)
|
|
1352
1204
|
return;
|
|
1353
|
-
// Remove ANSI escape codes from the message
|
|
1354
|
-
// eslint-disable-next-line no-control-regex
|
|
1355
1205
|
message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
|
|
1356
|
-
// Remove leading asterisks from the message
|
|
1357
1206
|
message = message.replace(/^\*+/, '');
|
|
1358
|
-
// Replace all occurrences of \t and \n
|
|
1359
1207
|
message = message.replace(/[\t\n]/g, '');
|
|
1360
|
-
// Remove non-printable characters
|
|
1361
|
-
// eslint-disable-next-line no-control-regex
|
|
1362
1208
|
message = message.replace(/[\x00-\x1F\x7F]/g, '');
|
|
1363
|
-
// Replace all occurrences of \" with "
|
|
1364
1209
|
message = message.replace(/\\"/g, '"');
|
|
1365
|
-
// Define the maximum allowed length for continuous characters without a space
|
|
1366
1210
|
const maxContinuousLength = 100;
|
|
1367
1211
|
const keepStartLength = 20;
|
|
1368
1212
|
const keepEndLength = 20;
|
|
1369
|
-
// Split the message into words
|
|
1370
1213
|
message = message
|
|
1371
1214
|
.split(' ')
|
|
1372
1215
|
.map((word) => {
|
|
1373
|
-
// If the word length exceeds the max continuous length, insert spaces and truncate
|
|
1374
1216
|
if (word.length > maxContinuousLength) {
|
|
1375
1217
|
return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
|
|
1376
1218
|
}
|
|
1377
1219
|
return word;
|
|
1378
1220
|
})
|
|
1379
1221
|
.join(' ');
|
|
1380
|
-
// Send the message to all connected clients
|
|
1381
1222
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1382
1223
|
if (client.readyState === WebSocket.OPEN) {
|
|
1383
1224
|
client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
|
|
1384
1225
|
}
|
|
1385
1226
|
});
|
|
1386
1227
|
}
|
|
1387
|
-
/**
|
|
1388
|
-
* Sends a need to refresh WebSocket message to all connected clients.
|
|
1389
|
-
*
|
|
1390
|
-
*/
|
|
1391
1228
|
wssSendRefreshRequired() {
|
|
1392
1229
|
this.log.debug('Sending a refresh required message to all connected clients');
|
|
1393
1230
|
this.matterbridge.matterbridgeInformation.refreshRequired = true;
|
|
1394
|
-
// Send the message to all connected clients
|
|
1395
1231
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1396
1232
|
if (client.readyState === WebSocket.OPEN) {
|
|
1397
1233
|
client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', params: {} }));
|
|
1398
1234
|
}
|
|
1399
1235
|
});
|
|
1400
1236
|
}
|
|
1401
|
-
/**
|
|
1402
|
-
* Sends a need to restart WebSocket message to all connected clients.
|
|
1403
|
-
*
|
|
1404
|
-
*/
|
|
1405
1237
|
wssSendRestartRequired() {
|
|
1406
1238
|
this.log.debug('Sending a restart required message to all connected clients');
|
|
1407
1239
|
this.matterbridge.matterbridgeInformation.restartRequired = true;
|
|
1408
|
-
// Send the message to all connected clients
|
|
1409
1240
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1410
1241
|
if (client.readyState === WebSocket.OPEN) {
|
|
1411
1242
|
client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', params: {} }));
|
|
@@ -1413,4 +1244,3 @@ export class Frontend {
|
|
|
1413
1244
|
});
|
|
1414
1245
|
}
|
|
1415
1246
|
}
|
|
1416
|
-
//# sourceMappingURL=frontend.js.map
|