matterbridge 2.0.0 → 2.1.0-dev.1
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 +21 -1
- 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 +57 -242
- package/dist/index.js +1 -30
- package/dist/logger/export.js +0 -1
- package/dist/matter/export.js +0 -7
- package/dist/matterbridge.js +77 -702
- package/dist/matterbridgeAccessoryPlatform.js +0 -33
- package/dist/matterbridgeBehaviors.js +33 -38
- package/dist/matterbridgeDeviceTypes.js +11 -112
- package/dist/matterbridgeDynamicPlatform.js +0 -33
- package/dist/matterbridgeEndpoint.js +970 -2524
- package/dist/matterbridgePlatform.js +3 -123
- package/dist/matterbridgeTypes.js +0 -25
- 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 +83 -68
- package/package.json +2 -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,23 @@ 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
|
+
res.json(pairingCodes);
|
|
230
|
+
});
|
|
297
231
|
this.expressApp.get('/api/settings', express.json(), async (req, res) => {
|
|
298
232
|
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);
|
|
233
|
+
res.json(await this.getApiSettings());
|
|
318
234
|
});
|
|
319
|
-
// Endpoint to provide plugins
|
|
320
235
|
this.expressApp.get('/api/plugins', async (req, res) => {
|
|
321
236
|
this.log.debug('The frontend sent /api/plugins');
|
|
322
|
-
const response =
|
|
323
|
-
// this.log.debug('Response:', debugStringify(response));
|
|
237
|
+
const response = this.getBaseRegisteredPlugins();
|
|
324
238
|
res.json(response);
|
|
325
239
|
});
|
|
326
|
-
// Endpoint to provide devices
|
|
327
240
|
this.expressApp.get('/api/devices', (req, res) => {
|
|
328
241
|
this.log.debug('The frontend sent /api/devices');
|
|
329
242
|
const devices = [];
|
|
330
243
|
this.matterbridge.devices.forEach(async (device) => {
|
|
331
|
-
// Check if the device has the required properties
|
|
332
244
|
if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId)
|
|
333
245
|
return;
|
|
334
246
|
const cluster = this.getClusterTextFromDevice(device);
|
|
@@ -344,10 +256,8 @@ export class Frontend {
|
|
|
344
256
|
cluster: cluster,
|
|
345
257
|
});
|
|
346
258
|
});
|
|
347
|
-
// this.log.debug('Response:', debugStringify(data));
|
|
348
259
|
res.json(devices);
|
|
349
260
|
});
|
|
350
|
-
// Endpoint to provide the cluster servers of the devices
|
|
351
261
|
this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
|
|
352
262
|
const selectedPluginName = req.params.selectedPluginName;
|
|
353
263
|
const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
|
|
@@ -420,7 +330,6 @@ export class Frontend {
|
|
|
420
330
|
});
|
|
421
331
|
res.json(data);
|
|
422
332
|
});
|
|
423
|
-
// Endpoint to view the log
|
|
424
333
|
this.expressApp.get('/api/view-log', async (req, res) => {
|
|
425
334
|
this.log.debug('The frontend sent /api/log');
|
|
426
335
|
try {
|
|
@@ -433,12 +342,10 @@ export class Frontend {
|
|
|
433
342
|
res.status(500).send('Error reading log file');
|
|
434
343
|
}
|
|
435
344
|
});
|
|
436
|
-
// Endpoint to download the matterbridge log
|
|
437
345
|
this.expressApp.get('/api/download-mblog', async (req, res) => {
|
|
438
346
|
this.log.debug('The frontend sent /api/download-mblog');
|
|
439
347
|
try {
|
|
440
348
|
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
349
|
}
|
|
443
350
|
catch (error) {
|
|
444
351
|
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 +357,10 @@ export class Frontend {
|
|
|
450
357
|
}
|
|
451
358
|
});
|
|
452
359
|
});
|
|
453
|
-
// Endpoint to download the matter log
|
|
454
360
|
this.expressApp.get('/api/download-mjlog', async (req, res) => {
|
|
455
361
|
this.log.debug('The frontend sent /api/download-mjlog');
|
|
456
362
|
try {
|
|
457
363
|
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
364
|
}
|
|
460
365
|
catch (error) {
|
|
461
366
|
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 +372,6 @@ export class Frontend {
|
|
|
467
372
|
}
|
|
468
373
|
});
|
|
469
374
|
});
|
|
470
|
-
// Endpoint to download the matter storage file
|
|
471
375
|
this.expressApp.get('/api/download-mjstorage', async (req, res) => {
|
|
472
376
|
this.log.debug('The frontend sent /api/download-mjstorage');
|
|
473
377
|
await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.matterStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterStorageName));
|
|
@@ -478,7 +382,6 @@ export class Frontend {
|
|
|
478
382
|
}
|
|
479
383
|
});
|
|
480
384
|
});
|
|
481
|
-
// Endpoint to download the matterbridge storage directory
|
|
482
385
|
this.expressApp.get('/api/download-mbstorage', async (req, res) => {
|
|
483
386
|
this.log.debug('The frontend sent /api/download-mbstorage');
|
|
484
387
|
await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.nodeStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.nodeStorageName));
|
|
@@ -489,7 +392,6 @@ export class Frontend {
|
|
|
489
392
|
}
|
|
490
393
|
});
|
|
491
394
|
});
|
|
492
|
-
// Endpoint to download the matterbridge plugin directory
|
|
493
395
|
this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
|
|
494
396
|
this.log.debug('The frontend sent /api/download-pluginstorage');
|
|
495
397
|
await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridge.matterbridgePluginDirectory);
|
|
@@ -500,11 +402,9 @@ export class Frontend {
|
|
|
500
402
|
}
|
|
501
403
|
});
|
|
502
404
|
});
|
|
503
|
-
// Endpoint to download the matterbridge plugin config files
|
|
504
405
|
this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
|
|
505
406
|
this.log.debug('The frontend sent /api/download-pluginconfig');
|
|
506
407
|
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
408
|
res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
|
|
509
409
|
if (error) {
|
|
510
410
|
this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
|
|
@@ -512,7 +412,6 @@ export class Frontend {
|
|
|
512
412
|
}
|
|
513
413
|
});
|
|
514
414
|
});
|
|
515
|
-
// Endpoint to download the matterbridge plugin config files
|
|
516
415
|
this.expressApp.get('/api/download-backup', async (req, res) => {
|
|
517
416
|
this.log.debug('The frontend sent /api/download-backup');
|
|
518
417
|
res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
|
|
@@ -522,7 +421,6 @@ export class Frontend {
|
|
|
522
421
|
}
|
|
523
422
|
});
|
|
524
423
|
});
|
|
525
|
-
// Endpoint to receive commands
|
|
526
424
|
this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
|
|
527
425
|
const command = req.params.command;
|
|
528
426
|
let param = req.params.param;
|
|
@@ -532,15 +430,13 @@ export class Frontend {
|
|
|
532
430
|
return;
|
|
533
431
|
}
|
|
534
432
|
this.log.debug(`Received frontend command: ${command}:${param}`);
|
|
535
|
-
// Handle the command setpassword from Settings
|
|
536
433
|
if (command === 'setpassword') {
|
|
537
|
-
const password = param.slice(1, -1);
|
|
434
|
+
const password = param.slice(1, -1);
|
|
538
435
|
this.log.debug('setpassword', param, password);
|
|
539
436
|
await this.matterbridge.nodeContext?.set('password', password);
|
|
540
437
|
res.json({ message: 'Command received' });
|
|
541
438
|
return;
|
|
542
439
|
}
|
|
543
|
-
// Handle the command setbridgemode from Settings
|
|
544
440
|
if (command === 'setbridgemode') {
|
|
545
441
|
this.log.debug(`setbridgemode: ${param}`);
|
|
546
442
|
this.wssSendRestartRequired();
|
|
@@ -548,7 +444,6 @@ export class Frontend {
|
|
|
548
444
|
res.json({ message: 'Command received' });
|
|
549
445
|
return;
|
|
550
446
|
}
|
|
551
|
-
// Handle the command backup from Settings
|
|
552
447
|
if (command === 'backup') {
|
|
553
448
|
this.log.notice(`Prepairing the backup...`);
|
|
554
449
|
await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridge.matterbridgeDirectory), path.join(this.matterbridge.matterbridgePluginDirectory));
|
|
@@ -556,26 +451,25 @@ export class Frontend {
|
|
|
556
451
|
res.json({ message: 'Command received' });
|
|
557
452
|
return;
|
|
558
453
|
}
|
|
559
|
-
// Handle the command setmbloglevel from Settings
|
|
560
454
|
if (command === 'setmbloglevel') {
|
|
561
455
|
this.log.debug('Matterbridge log level:', param);
|
|
562
456
|
if (param === 'Debug') {
|
|
563
|
-
this.log.logLevel = "debug"
|
|
457
|
+
this.log.logLevel = "debug";
|
|
564
458
|
}
|
|
565
459
|
else if (param === 'Info') {
|
|
566
|
-
this.log.logLevel = "info"
|
|
460
|
+
this.log.logLevel = "info";
|
|
567
461
|
}
|
|
568
462
|
else if (param === 'Notice') {
|
|
569
|
-
this.log.logLevel = "notice"
|
|
463
|
+
this.log.logLevel = "notice";
|
|
570
464
|
}
|
|
571
465
|
else if (param === 'Warn') {
|
|
572
|
-
this.log.logLevel = "warn"
|
|
466
|
+
this.log.logLevel = "warn";
|
|
573
467
|
}
|
|
574
468
|
else if (param === 'Error') {
|
|
575
|
-
this.log.logLevel = "error"
|
|
469
|
+
this.log.logLevel = "error";
|
|
576
470
|
}
|
|
577
471
|
else if (param === 'Fatal') {
|
|
578
|
-
this.log.logLevel = "fatal"
|
|
472
|
+
this.log.logLevel = "fatal";
|
|
579
473
|
}
|
|
580
474
|
await this.matterbridge.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
|
|
581
475
|
MatterbridgeEndpoint.logLevel = this.log.logLevel;
|
|
@@ -583,13 +477,12 @@ export class Frontend {
|
|
|
583
477
|
for (const plugin of this.matterbridge.plugins) {
|
|
584
478
|
if (!plugin.platform || !plugin.platform.config)
|
|
585
479
|
continue;
|
|
586
|
-
plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug"
|
|
587
|
-
await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug"
|
|
480
|
+
plugin.platform.log.logLevel = plugin.platform.config.debug ? "debug" : this.log.logLevel;
|
|
481
|
+
await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug ? "debug" : this.log.logLevel);
|
|
588
482
|
}
|
|
589
483
|
res.json({ message: 'Command received' });
|
|
590
484
|
return;
|
|
591
485
|
}
|
|
592
|
-
// Handle the command setmbloglevel from Settings
|
|
593
486
|
if (command === 'setmjloglevel') {
|
|
594
487
|
this.log.debug('Matter.js log level:', param);
|
|
595
488
|
if (param === 'Debug') {
|
|
@@ -614,34 +507,30 @@ export class Frontend {
|
|
|
614
507
|
res.json({ message: 'Command received' });
|
|
615
508
|
return;
|
|
616
509
|
}
|
|
617
|
-
// Handle the command setmdnsinterface from Settings
|
|
618
510
|
if (command === 'setmdnsinterface') {
|
|
619
|
-
param = param.slice(1, -1);
|
|
511
|
+
param = param.slice(1, -1);
|
|
620
512
|
this.matterbridge.matterbridgeInformation.mattermdnsinterface = param;
|
|
621
513
|
this.log.debug('Matter.js mdns interface:', param === '' ? 'All interfaces' : param);
|
|
622
514
|
await this.matterbridge.nodeContext?.set('mattermdnsinterface', param);
|
|
623
515
|
res.json({ message: 'Command received' });
|
|
624
516
|
return;
|
|
625
517
|
}
|
|
626
|
-
// Handle the command setipv4address from Settings
|
|
627
518
|
if (command === 'setipv4address') {
|
|
628
|
-
param = param.slice(1, -1);
|
|
519
|
+
param = param.slice(1, -1);
|
|
629
520
|
this.matterbridge.matterbridgeInformation.matteripv4address = param;
|
|
630
521
|
this.log.debug('Matter.js ipv4 address:', param === '' ? 'All ipv4 addresses' : param);
|
|
631
522
|
await this.matterbridge.nodeContext?.set('matteripv4address', param);
|
|
632
523
|
res.json({ message: 'Command received' });
|
|
633
524
|
return;
|
|
634
525
|
}
|
|
635
|
-
// Handle the command setipv6address from Settings
|
|
636
526
|
if (command === 'setipv6address') {
|
|
637
|
-
param = param.slice(1, -1);
|
|
527
|
+
param = param.slice(1, -1);
|
|
638
528
|
this.matterbridge.matterbridgeInformation.matteripv6address = param;
|
|
639
529
|
this.log.debug('Matter.js ipv6 address:', param === '' ? 'All ipv6 addresses' : param);
|
|
640
530
|
await this.matterbridge.nodeContext?.set('matteripv6address', param);
|
|
641
531
|
res.json({ message: 'Command received' });
|
|
642
532
|
return;
|
|
643
533
|
}
|
|
644
|
-
// Handle the command setmatterport from Settings
|
|
645
534
|
if (command === 'setmatterport') {
|
|
646
535
|
const port = Math.min(Math.max(parseInt(param), 5540), 5560);
|
|
647
536
|
this.matterbridge.matterbridgeInformation.matterPort = port;
|
|
@@ -650,7 +539,6 @@ export class Frontend {
|
|
|
650
539
|
res.json({ message: 'Command received' });
|
|
651
540
|
return;
|
|
652
541
|
}
|
|
653
|
-
// Handle the command setmatterdiscriminator from Settings
|
|
654
542
|
if (command === 'setmatterdiscriminator') {
|
|
655
543
|
const discriminator = Math.min(Math.max(parseInt(param), 1000), 4095);
|
|
656
544
|
this.matterbridge.matterbridgeInformation.matterDiscriminator = discriminator;
|
|
@@ -659,7 +547,6 @@ export class Frontend {
|
|
|
659
547
|
res.json({ message: 'Command received' });
|
|
660
548
|
return;
|
|
661
549
|
}
|
|
662
|
-
// Handle the command setmatterpasscode from Settings
|
|
663
550
|
if (command === 'setmatterpasscode') {
|
|
664
551
|
const passcode = Math.min(Math.max(parseInt(param), 10000000), 90000000);
|
|
665
552
|
this.matterbridge.matterbridgeInformation.matterPasscode = passcode;
|
|
@@ -668,20 +555,17 @@ export class Frontend {
|
|
|
668
555
|
res.json({ message: 'Command received' });
|
|
669
556
|
return;
|
|
670
557
|
}
|
|
671
|
-
// Handle the command setmbloglevel from Settings
|
|
672
558
|
if (command === 'setmblogfile') {
|
|
673
559
|
this.log.debug('Matterbridge file log:', param);
|
|
674
560
|
this.matterbridge.matterbridgeInformation.fileLogger = param === 'true';
|
|
675
561
|
await this.matterbridge.nodeContext?.set('matterbridgeFileLog', param === 'true');
|
|
676
|
-
// Create the file logger for matterbridge
|
|
677
562
|
if (param === 'true')
|
|
678
|
-
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug"
|
|
563
|
+
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug", true);
|
|
679
564
|
else
|
|
680
565
|
AnsiLogger.setGlobalLogfile(undefined);
|
|
681
566
|
res.json({ message: 'Command received' });
|
|
682
567
|
return;
|
|
683
568
|
}
|
|
684
|
-
// Handle the command setmbloglevel from Settings
|
|
685
569
|
if (command === 'setmjlogfile') {
|
|
686
570
|
this.log.debug('Matter file log:', param);
|
|
687
571
|
this.matterbridge.matterbridgeInformation.matterFileLogger = param === 'true';
|
|
@@ -708,43 +592,36 @@ export class Frontend {
|
|
|
708
592
|
res.json({ message: 'Command received' });
|
|
709
593
|
return;
|
|
710
594
|
}
|
|
711
|
-
// Handle the command unregister from Settings
|
|
712
595
|
if (command === 'unregister') {
|
|
713
596
|
await this.matterbridge.unregisterAndShutdownProcess();
|
|
714
597
|
res.json({ message: 'Command received' });
|
|
715
598
|
return;
|
|
716
599
|
}
|
|
717
|
-
// Handle the command reset from Settings
|
|
718
600
|
if (command === 'reset') {
|
|
719
601
|
await this.matterbridge.shutdownProcessAndReset();
|
|
720
602
|
res.json({ message: 'Command received' });
|
|
721
603
|
return;
|
|
722
604
|
}
|
|
723
|
-
// Handle the command factoryreset from Settings
|
|
724
605
|
if (command === 'factoryreset') {
|
|
725
606
|
await this.matterbridge.shutdownProcessAndFactoryReset();
|
|
726
607
|
res.json({ message: 'Command received' });
|
|
727
608
|
return;
|
|
728
609
|
}
|
|
729
|
-
// Handle the command shutdown from Header
|
|
730
610
|
if (command === 'shutdown') {
|
|
731
611
|
await this.matterbridge.shutdownProcess();
|
|
732
612
|
res.json({ message: 'Command received' });
|
|
733
613
|
return;
|
|
734
614
|
}
|
|
735
|
-
// Handle the command restart from Header
|
|
736
615
|
if (command === 'restart') {
|
|
737
616
|
await this.matterbridge.restartProcess();
|
|
738
617
|
res.json({ message: 'Command received' });
|
|
739
618
|
return;
|
|
740
619
|
}
|
|
741
|
-
// Handle the command update from Header
|
|
742
620
|
if (command === 'update') {
|
|
743
621
|
this.log.info('Updating matterbridge...');
|
|
744
622
|
try {
|
|
745
623
|
await this.matterbridge.spawnCommand('npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose']);
|
|
746
624
|
this.log.info('Matterbridge has been updated. Full restart required.');
|
|
747
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
748
625
|
}
|
|
749
626
|
catch (error) {
|
|
750
627
|
this.log.error('Error updating matterbridge');
|
|
@@ -754,11 +631,9 @@ export class Frontend {
|
|
|
754
631
|
res.json({ message: 'Command received' });
|
|
755
632
|
return;
|
|
756
633
|
}
|
|
757
|
-
// Handle the command saveconfig from Home
|
|
758
634
|
if (command === 'saveconfig') {
|
|
759
635
|
param = param.replace(/\*/g, '\\');
|
|
760
636
|
this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
|
|
761
|
-
// console.log('Req.body:', JSON.stringify(req.body, null, 2));
|
|
762
637
|
if (!this.matterbridge.plugins.has(param)) {
|
|
763
638
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
764
639
|
}
|
|
@@ -772,58 +647,49 @@ export class Frontend {
|
|
|
772
647
|
res.json({ message: 'Command received' });
|
|
773
648
|
return;
|
|
774
649
|
}
|
|
775
|
-
// Handle the command installplugin from Home
|
|
776
650
|
if (command === 'installplugin') {
|
|
777
651
|
param = param.replace(/\*/g, '\\');
|
|
778
652
|
this.log.info(`Installing plugin ${plg}${param}${nf}...`);
|
|
779
653
|
try {
|
|
780
654
|
await this.matterbridge.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
|
|
781
655
|
this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
|
|
782
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
783
656
|
}
|
|
784
657
|
catch (error) {
|
|
785
658
|
this.log.error(`Error installing plugin ${plg}${param}${er}`);
|
|
786
659
|
}
|
|
787
660
|
this.wssSendRestartRequired();
|
|
788
661
|
param = param.split('@')[0];
|
|
789
|
-
// Also add the plugin to matterbridge so no return!
|
|
790
662
|
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
663
|
res.json({ message: 'Command received' });
|
|
793
664
|
return;
|
|
794
665
|
}
|
|
795
666
|
}
|
|
796
|
-
// Handle the command addplugin from Home
|
|
797
667
|
if (command === 'addplugin' || command === 'installplugin') {
|
|
798
668
|
param = param.replace(/\*/g, '\\');
|
|
799
669
|
const plugin = await this.matterbridge.plugins.add(param);
|
|
800
670
|
if (plugin) {
|
|
801
671
|
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
672
|
this.matterbridge.createDynamicPlugin(plugin, true);
|
|
805
673
|
}
|
|
806
|
-
this.matterbridge.plugins.load(plugin, true, 'The plugin has been added', true);
|
|
674
|
+
this.matterbridge.plugins.load(plugin, true, 'The plugin has been added', true);
|
|
807
675
|
}
|
|
808
676
|
res.json({ message: 'Command received' });
|
|
809
677
|
this.wssSendRefreshRequired();
|
|
810
678
|
return;
|
|
811
679
|
}
|
|
812
|
-
// Handle the command removeplugin from Home
|
|
813
680
|
if (command === 'removeplugin') {
|
|
814
681
|
if (!this.matterbridge.plugins.has(param)) {
|
|
815
682
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
816
683
|
}
|
|
817
684
|
else {
|
|
818
685
|
const plugin = this.matterbridge.plugins.get(param);
|
|
819
|
-
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true);
|
|
686
|
+
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true);
|
|
820
687
|
await this.matterbridge.plugins.remove(param);
|
|
821
688
|
}
|
|
822
689
|
res.json({ message: 'Command received' });
|
|
823
690
|
this.wssSendRefreshRequired();
|
|
824
691
|
return;
|
|
825
692
|
}
|
|
826
|
-
// Handle the command enableplugin from Home
|
|
827
693
|
if (command === 'enableplugin') {
|
|
828
694
|
if (!this.matterbridge.plugins.has(param)) {
|
|
829
695
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
@@ -841,17 +707,15 @@ export class Frontend {
|
|
|
841
707
|
plugin.addedDevices = undefined;
|
|
842
708
|
await this.matterbridge.plugins.enable(param);
|
|
843
709
|
if (this.matterbridge.bridgeMode === 'childbridge' && plugin.type === 'DynamicPlatform') {
|
|
844
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
845
710
|
this.matterbridge.createDynamicPlugin(plugin, true);
|
|
846
711
|
}
|
|
847
|
-
this.matterbridge.plugins.load(plugin, true, 'The plugin has been enabled', true);
|
|
712
|
+
this.matterbridge.plugins.load(plugin, true, 'The plugin has been enabled', true);
|
|
848
713
|
}
|
|
849
714
|
}
|
|
850
715
|
res.json({ message: 'Command received' });
|
|
851
716
|
this.wssSendRefreshRequired();
|
|
852
717
|
return;
|
|
853
718
|
}
|
|
854
|
-
// Handle the command disableplugin from Home
|
|
855
719
|
if (command === 'disableplugin') {
|
|
856
720
|
if (!this.matterbridge.plugins.has(param)) {
|
|
857
721
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
@@ -859,7 +723,7 @@ export class Frontend {
|
|
|
859
723
|
else {
|
|
860
724
|
const plugin = this.matterbridge.plugins.get(param);
|
|
861
725
|
if (plugin && plugin.enabled) {
|
|
862
|
-
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true);
|
|
726
|
+
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true);
|
|
863
727
|
await this.matterbridge.plugins.disable(param);
|
|
864
728
|
}
|
|
865
729
|
}
|
|
@@ -868,7 +732,6 @@ export class Frontend {
|
|
|
868
732
|
return;
|
|
869
733
|
}
|
|
870
734
|
});
|
|
871
|
-
// Fallback for routing (must be the last route)
|
|
872
735
|
this.expressApp.get('*', (req, res) => {
|
|
873
736
|
this.log.debug('The frontend sent:', req.url);
|
|
874
737
|
this.log.debug('Response send file:', path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
|
|
@@ -877,29 +740,24 @@ export class Frontend {
|
|
|
877
740
|
this.log.debug(`Frontend initialized on port ${YELLOW}${this.port}${db} static ${UNDERLINE}${path.join(this.matterbridge.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
|
|
878
741
|
}
|
|
879
742
|
async stop() {
|
|
880
|
-
// Close the http server
|
|
881
743
|
if (this.httpServer) {
|
|
882
744
|
this.httpServer.close();
|
|
883
745
|
this.httpServer.removeAllListeners();
|
|
884
746
|
this.httpServer = undefined;
|
|
885
747
|
this.log.debug('Frontend http server closed successfully');
|
|
886
748
|
}
|
|
887
|
-
// Close the https server
|
|
888
749
|
if (this.httpsServer) {
|
|
889
750
|
this.httpsServer.close();
|
|
890
751
|
this.httpsServer.removeAllListeners();
|
|
891
752
|
this.httpsServer = undefined;
|
|
892
753
|
this.log.debug('Frontend https server closed successfully');
|
|
893
754
|
}
|
|
894
|
-
// Remove listeners from the express app
|
|
895
755
|
if (this.expressApp) {
|
|
896
756
|
this.expressApp.removeAllListeners();
|
|
897
757
|
this.expressApp = undefined;
|
|
898
758
|
this.log.debug('Frontend app closed successfully');
|
|
899
759
|
}
|
|
900
|
-
// Close the WebSocket server
|
|
901
760
|
if (this.webSocketServer) {
|
|
902
|
-
// Close all active connections
|
|
903
761
|
this.webSocketServer.clients.forEach((client) => {
|
|
904
762
|
if (client.readyState === WebSocket.OPEN) {
|
|
905
763
|
client.close();
|
|
@@ -916,11 +774,25 @@ export class Frontend {
|
|
|
916
774
|
this.webSocketServer = undefined;
|
|
917
775
|
}
|
|
918
776
|
}
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
777
|
+
async getApiSettings() {
|
|
778
|
+
this.matterbridge.matterbridgeInformation.bridgeMode = this.matterbridge.bridgeMode;
|
|
779
|
+
this.matterbridge.matterbridgeInformation.restartMode = this.matterbridge.restartMode;
|
|
780
|
+
this.matterbridge.matterbridgeInformation.loggerLevel = this.log.logLevel;
|
|
781
|
+
this.matterbridge.matterbridgeInformation.matterLoggerLevel = Logger.defaultLogLevel;
|
|
782
|
+
this.matterbridge.matterbridgeInformation.mattermdnsinterface = this.matterbridge.mdnsInterface;
|
|
783
|
+
this.matterbridge.matterbridgeInformation.matteripv4address = this.matterbridge.ipv4address;
|
|
784
|
+
this.matterbridge.matterbridgeInformation.matteripv6address = this.matterbridge.ipv6address;
|
|
785
|
+
this.matterbridge.matterbridgeInformation.matterPort = (await this.matterbridge.nodeContext?.get('matterport', 5540)) ?? 5540;
|
|
786
|
+
this.matterbridge.matterbridgeInformation.matterDiscriminator = await this.matterbridge.nodeContext?.get('matterdiscriminator');
|
|
787
|
+
this.matterbridge.matterbridgeInformation.matterPasscode = await this.matterbridge.nodeContext?.get('matterpasscode');
|
|
788
|
+
this.matterbridge.matterbridgeInformation.matterbridgePaired = this.matterbridge.matterbridgePaired;
|
|
789
|
+
this.matterbridge.matterbridgeInformation.matterbridgeQrPairingCode = this.matterbridge.matterbridgeQrPairingCode;
|
|
790
|
+
this.matterbridge.matterbridgeInformation.matterbridgeManualPairingCode = this.matterbridge.matterbridgeManualPairingCode;
|
|
791
|
+
this.matterbridge.matterbridgeInformation.matterbridgeFabricInformations = this.matterbridge.matterbridgeFabricInformations;
|
|
792
|
+
this.matterbridge.matterbridgeInformation.matterbridgeSessionInformations = this.matterbridge.matterbridgeSessionInformations;
|
|
793
|
+
this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
|
|
794
|
+
return { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: this.matterbridge.matterbridgeInformation };
|
|
795
|
+
}
|
|
924
796
|
getClusterTextFromDevice(device) {
|
|
925
797
|
const getAttribute = (device, cluster, attribute) => {
|
|
926
798
|
let value = undefined;
|
|
@@ -958,10 +830,10 @@ export class Frontend {
|
|
|
958
830
|
return '';
|
|
959
831
|
};
|
|
960
832
|
let attributes = '';
|
|
961
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
962
833
|
Object.entries(device.state).forEach(([clusterName, clusterAttributes]) => {
|
|
963
834
|
Object.entries(clusterAttributes).forEach(([attributeName, attributeValue]) => {
|
|
964
|
-
|
|
835
|
+
if (typeof attributeValue === 'undefined')
|
|
836
|
+
return;
|
|
965
837
|
if (clusterName === 'onOff' && attributeName === 'onOff')
|
|
966
838
|
attributes += `OnOff: ${attributeValue} `;
|
|
967
839
|
if (clusterName === 'switch' && attributeName === 'currentPosition')
|
|
@@ -1032,11 +904,7 @@ export class Frontend {
|
|
|
1032
904
|
});
|
|
1033
905
|
return attributes.trimStart().trimEnd();
|
|
1034
906
|
}
|
|
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() {
|
|
907
|
+
getBaseRegisteredPlugins() {
|
|
1040
908
|
const baseRegisteredPlugins = [];
|
|
1041
909
|
for (const plugin of this.matterbridge.plugins) {
|
|
1042
910
|
baseRegisteredPlugins.push({
|
|
@@ -1066,14 +934,6 @@ export class Frontend {
|
|
|
1066
934
|
}
|
|
1067
935
|
return baseRegisteredPlugins;
|
|
1068
936
|
}
|
|
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
937
|
async wsMessageHandler(client, message) {
|
|
1078
938
|
let data;
|
|
1079
939
|
try {
|
|
@@ -1144,39 +1004,25 @@ export class Frontend {
|
|
|
1144
1004
|
await this.matterbridge.shutdownProcess();
|
|
1145
1005
|
return;
|
|
1146
1006
|
}
|
|
1007
|
+
else if (data.method === '/api/advertise') {
|
|
1008
|
+
const pairingCodes = await this.matterbridge.advertiseServerNode(this.matterbridge.serverNode);
|
|
1009
|
+
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: pairingCodes }));
|
|
1010
|
+
return;
|
|
1011
|
+
}
|
|
1147
1012
|
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 }));
|
|
1013
|
+
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response: await this.getApiSettings() }));
|
|
1166
1014
|
return;
|
|
1167
1015
|
}
|
|
1168
1016
|
else if (data.method === '/api/plugins') {
|
|
1169
|
-
const response =
|
|
1017
|
+
const response = this.getBaseRegisteredPlugins();
|
|
1170
1018
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response }));
|
|
1171
1019
|
return;
|
|
1172
1020
|
}
|
|
1173
1021
|
else if (data.method === '/api/devices') {
|
|
1174
1022
|
const devices = [];
|
|
1175
1023
|
this.matterbridge.devices.forEach(async (device) => {
|
|
1176
|
-
// Filter by pluginName if provided
|
|
1177
1024
|
if (data.params.pluginName && data.params.pluginName !== device.plugin)
|
|
1178
1025
|
return;
|
|
1179
|
-
// Check if the device has the required properties
|
|
1180
1026
|
if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId)
|
|
1181
1027
|
return;
|
|
1182
1028
|
const cluster = this.getClusterTextFromDevice(device);
|
|
@@ -1256,7 +1102,6 @@ export class Frontend {
|
|
|
1256
1102
|
});
|
|
1257
1103
|
endpointServer.getChildEndpoints().forEach((childEndpoint) => {
|
|
1258
1104
|
deviceTypes = [];
|
|
1259
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1260
1105
|
const name = childEndpoint.endpoint?.id;
|
|
1261
1106
|
const clusterServers = childEndpoint.getAllClusterServers();
|
|
1262
1107
|
clusterServers.forEach((clusterServer) => {
|
|
@@ -1339,73 +1184,44 @@ export class Frontend {
|
|
|
1339
1184
|
return;
|
|
1340
1185
|
}
|
|
1341
1186
|
}
|
|
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
1187
|
wssSendMessage(level, time, name, message) {
|
|
1351
1188
|
if (!level || !time || !name || !message)
|
|
1352
1189
|
return;
|
|
1353
|
-
// Remove ANSI escape codes from the message
|
|
1354
|
-
// eslint-disable-next-line no-control-regex
|
|
1355
1190
|
message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
|
|
1356
|
-
// Remove leading asterisks from the message
|
|
1357
1191
|
message = message.replace(/^\*+/, '');
|
|
1358
|
-
// Replace all occurrences of \t and \n
|
|
1359
1192
|
message = message.replace(/[\t\n]/g, '');
|
|
1360
|
-
// Remove non-printable characters
|
|
1361
|
-
// eslint-disable-next-line no-control-regex
|
|
1362
1193
|
message = message.replace(/[\x00-\x1F\x7F]/g, '');
|
|
1363
|
-
// Replace all occurrences of \" with "
|
|
1364
1194
|
message = message.replace(/\\"/g, '"');
|
|
1365
|
-
// Define the maximum allowed length for continuous characters without a space
|
|
1366
1195
|
const maxContinuousLength = 100;
|
|
1367
1196
|
const keepStartLength = 20;
|
|
1368
1197
|
const keepEndLength = 20;
|
|
1369
|
-
// Split the message into words
|
|
1370
1198
|
message = message
|
|
1371
1199
|
.split(' ')
|
|
1372
1200
|
.map((word) => {
|
|
1373
|
-
// If the word length exceeds the max continuous length, insert spaces and truncate
|
|
1374
1201
|
if (word.length > maxContinuousLength) {
|
|
1375
1202
|
return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
|
|
1376
1203
|
}
|
|
1377
1204
|
return word;
|
|
1378
1205
|
})
|
|
1379
1206
|
.join(' ');
|
|
1380
|
-
// Send the message to all connected clients
|
|
1381
1207
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1382
1208
|
if (client.readyState === WebSocket.OPEN) {
|
|
1383
1209
|
client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
|
|
1384
1210
|
}
|
|
1385
1211
|
});
|
|
1386
1212
|
}
|
|
1387
|
-
/**
|
|
1388
|
-
* Sends a need to refresh WebSocket message to all connected clients.
|
|
1389
|
-
*
|
|
1390
|
-
*/
|
|
1391
1213
|
wssSendRefreshRequired() {
|
|
1392
1214
|
this.log.debug('Sending a refresh required message to all connected clients');
|
|
1393
1215
|
this.matterbridge.matterbridgeInformation.refreshRequired = true;
|
|
1394
|
-
// Send the message to all connected clients
|
|
1395
1216
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1396
1217
|
if (client.readyState === WebSocket.OPEN) {
|
|
1397
1218
|
client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', params: {} }));
|
|
1398
1219
|
}
|
|
1399
1220
|
});
|
|
1400
1221
|
}
|
|
1401
|
-
/**
|
|
1402
|
-
* Sends a need to restart WebSocket message to all connected clients.
|
|
1403
|
-
*
|
|
1404
|
-
*/
|
|
1405
1222
|
wssSendRestartRequired() {
|
|
1406
1223
|
this.log.debug('Sending a restart required message to all connected clients');
|
|
1407
1224
|
this.matterbridge.matterbridgeInformation.restartRequired = true;
|
|
1408
|
-
// Send the message to all connected clients
|
|
1409
1225
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1410
1226
|
if (client.readyState === WebSocket.OPEN) {
|
|
1411
1227
|
client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', params: {} }));
|
|
@@ -1413,4 +1229,3 @@ export class Frontend {
|
|
|
1413
1229
|
});
|
|
1414
1230
|
}
|
|
1415
1231
|
}
|
|
1416
|
-
//# sourceMappingURL=frontend.js.map
|