matterbridge 2.2.0-dev.5 → 2.2.0-dev.6
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/dist/cli.js +2 -37
- package/dist/cluster/export.js +0 -2
- package/dist/defaultConfigSchema.js +0 -23
- package/dist/deviceManager.js +1 -94
- package/dist/frontend.js +22 -265
- package/dist/index.js +2 -29
- package/dist/logger/export.js +0 -1
- package/dist/matter/behaviors.js +0 -2
- package/dist/matter/clusters.js +0 -2
- package/dist/matter/devices.js +0 -2
- package/dist/matter/endpoints.js +0 -2
- package/dist/matter/export.js +0 -2
- package/dist/matter/types.js +1 -3
- package/dist/matterbridge.js +47 -718
- package/dist/matterbridgeAccessoryPlatform.js +0 -33
- package/dist/matterbridgeBehaviors.js +1 -32
- package/dist/matterbridgeDeviceTypes.js +11 -112
- package/dist/matterbridgeDynamicPlatform.js +0 -33
- package/dist/matterbridgeEndpoint.js +6 -690
- package/dist/matterbridgeEndpointHelpers.js +9 -118
- package/dist/matterbridgePlatform.js +7 -140
- package/dist/matterbridgeTypes.js +0 -24
- package/dist/pluginManager.js +3 -229
- package/dist/shelly.js +4 -131
- package/dist/storage/export.js +0 -1
- package/dist/update.js +0 -45
- package/dist/utils/colorUtils.js +2 -205
- package/dist/utils/copyDirectory.js +1 -37
- package/dist/utils/createZip.js +2 -42
- package/dist/utils/deepCopy.js +0 -40
- package/dist/utils/deepEqual.js +1 -65
- package/dist/utils/export.js +0 -1
- package/dist/utils/isvalid.js +0 -86
- package/dist/utils/network.js +5 -77
- package/dist/utils/parameter.js +0 -41
- package/dist/utils/wait.js +5 -48
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/dist/cli.d.ts +0 -28
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cluster/export.d.ts.map +0 -1
- package/dist/cluster/export.js.map +0 -1
- package/dist/defaultConfigSchema.d.ts.map +0 -1
- package/dist/defaultConfigSchema.js.map +0 -1
- package/dist/deviceManager.d.ts +0 -109
- package/dist/deviceManager.d.ts.map +0 -1
- package/dist/deviceManager.js.map +0 -1
- package/dist/frontend.d.ts +0 -172
- package/dist/frontend.d.ts.map +0 -1
- package/dist/frontend.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/logger/export.d.ts.map +0 -1
- package/dist/logger/export.js.map +0 -1
- package/dist/matter/behaviors.d.ts.map +0 -1
- package/dist/matter/behaviors.js.map +0 -1
- package/dist/matter/clusters.d.ts.map +0 -1
- package/dist/matter/clusters.js.map +0 -1
- package/dist/matter/devices.d.ts.map +0 -1
- package/dist/matter/devices.js.map +0 -1
- package/dist/matter/endpoints.d.ts.map +0 -1
- package/dist/matter/endpoints.js.map +0 -1
- package/dist/matter/export.d.ts.map +0 -1
- package/dist/matter/export.js.map +0 -1
- package/dist/matter/types.d.ts.map +0 -1
- package/dist/matter/types.js.map +0 -1
- package/dist/matterbridge.d.ts +0 -410
- package/dist/matterbridge.d.ts.map +0 -1
- package/dist/matterbridge.js.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
- package/dist/matterbridgeBehaviors.d.ts +0 -148
- package/dist/matterbridgeBehaviors.d.ts.map +0 -1
- package/dist/matterbridgeBehaviors.js.map +0 -1
- package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
- package/dist/matterbridgeDeviceTypes.js.map +0 -1
- package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
- package/dist/matterbridgeDynamicPlatform.js.map +0 -1
- package/dist/matterbridgeEndpoint.d.ts +0 -827
- package/dist/matterbridgeEndpoint.d.ts.map +0 -1
- package/dist/matterbridgeEndpoint.js.map +0 -1
- package/dist/matterbridgeEndpointHelpers.d.ts +0 -123
- package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
- package/dist/matterbridgeEndpointHelpers.js.map +0 -1
- package/dist/matterbridgePlatform.d.ts +0 -159
- package/dist/matterbridgePlatform.d.ts.map +0 -1
- package/dist/matterbridgePlatform.js.map +0 -1
- package/dist/matterbridgeTypes.d.ts.map +0 -1
- package/dist/matterbridgeTypes.js.map +0 -1
- package/dist/pluginManager.d.ts +0 -236
- package/dist/pluginManager.d.ts.map +0 -1
- package/dist/pluginManager.js.map +0 -1
- package/dist/shelly.d.ts.map +0 -1
- package/dist/shelly.js.map +0 -1
- package/dist/storage/export.d.ts.map +0 -1
- package/dist/storage/export.js.map +0 -1
- package/dist/update.d.ts.map +0 -1
- package/dist/update.js.map +0 -1
- package/dist/utils/colorUtils.d.ts.map +0 -1
- package/dist/utils/colorUtils.js.map +0 -1
- package/dist/utils/copyDirectory.d.ts.map +0 -1
- package/dist/utils/copyDirectory.js.map +0 -1
- package/dist/utils/createZip.d.ts.map +0 -1
- package/dist/utils/createZip.js.map +0 -1
- package/dist/utils/deepCopy.d.ts.map +0 -1
- package/dist/utils/deepCopy.js.map +0 -1
- package/dist/utils/deepEqual.d.ts.map +0 -1
- package/dist/utils/deepEqual.js.map +0 -1
- package/dist/utils/export.d.ts.map +0 -1
- package/dist/utils/export.js.map +0 -1
- package/dist/utils/isvalid.d.ts.map +0 -1
- package/dist/utils/isvalid.js.map +0 -1
- package/dist/utils/network.d.ts.map +0 -1
- package/dist/utils/network.js.map +0 -1
- package/dist/utils/parameter.d.ts.map +0 -1
- package/dist/utils/parameter.js.map +0 -1
- package/dist/utils/wait.d.ts +0 -43
- package/dist/utils/wait.d.ts.map +0 -1
- package/dist/utils/wait.js.map +0 -1
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.2
|
|
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 'node:http';
|
|
27
3
|
import https from 'https';
|
|
28
4
|
import express from 'express';
|
|
@@ -30,70 +6,19 @@ import WebSocket, { WebSocketServer } from 'ws';
|
|
|
30
6
|
import os from 'node:os';
|
|
31
7
|
import path from 'node:path';
|
|
32
8
|
import { promises as fs } from 'node:fs';
|
|
33
|
-
// AnsiLogger module
|
|
34
9
|
import { AnsiLogger, stringify, debugStringify, CYAN, db, er, nf, rs, UNDERLINE, UNDERLINEOFF, wr, YELLOW } from './logger/export.js';
|
|
35
|
-
// Matterbridge
|
|
36
10
|
import { createZip, deepCopy, isValidNumber, isValidObject, isValidString } from './utils/export.js';
|
|
37
11
|
import { plg } from './matterbridgeTypes.js';
|
|
38
12
|
import { hasParameter } from './utils/export.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
|
-
* Websocket message ID indicating a cpu update.
|
|
56
|
-
* @constant {number}
|
|
57
|
-
*/
|
|
58
16
|
export const WS_ID_CPU_UPDATE = 3;
|
|
59
|
-
/**
|
|
60
|
-
* Websocket message ID indicating a memory update.
|
|
61
|
-
* @constant {number}
|
|
62
|
-
*/
|
|
63
17
|
export const WS_ID_MEMORY_UPDATE = 4;
|
|
64
|
-
/**
|
|
65
|
-
* Websocket message ID indicating an uptime update.
|
|
66
|
-
* @constant {number}
|
|
67
|
-
*/
|
|
68
18
|
export const WS_ID_UPTIME_UPDATE = 5;
|
|
69
|
-
/**
|
|
70
|
-
* Websocket message ID indicating a memory update.
|
|
71
|
-
* @constant {number}
|
|
72
|
-
*/
|
|
73
19
|
export const WS_ID_SNACKBAR = 6;
|
|
74
|
-
/**
|
|
75
|
-
* Websocket message ID indicating a shelly system update.
|
|
76
|
-
* check:
|
|
77
|
-
* curl -k http://127.0.0.1:8101/api/updates/sys/check
|
|
78
|
-
* perform:
|
|
79
|
-
* curl -k http://127.0.0.1:8101/api/updates/sys/perform
|
|
80
|
-
* @constant {number}
|
|
81
|
-
*/
|
|
82
20
|
export const WS_ID_SHELLY_SYS_UPDATE = 100;
|
|
83
|
-
/**
|
|
84
|
-
* Websocket message ID indicating a shelly main update.
|
|
85
|
-
* check:
|
|
86
|
-
* curl -k http://127.0.0.1:8101/api/updates/main/check
|
|
87
|
-
* perform:
|
|
88
|
-
* curl -k http://127.0.0.1:8101/api/updates/main/perform
|
|
89
|
-
* @constant {number}
|
|
90
|
-
*/
|
|
91
21
|
export const WS_ID_SHELLY_MAIN_UPDATE = 101;
|
|
92
|
-
/**
|
|
93
|
-
* Initializes the frontend of Matterbridge.
|
|
94
|
-
*
|
|
95
|
-
* @param port The port number to run the frontend server on. Default is 8283.
|
|
96
|
-
*/
|
|
97
22
|
export class Frontend {
|
|
98
23
|
matterbridge;
|
|
99
24
|
log;
|
|
@@ -110,7 +35,7 @@ export class Frontend {
|
|
|
110
35
|
memoryTimeout;
|
|
111
36
|
constructor(matterbridge) {
|
|
112
37
|
this.matterbridge = matterbridge;
|
|
113
|
-
this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4
|
|
38
|
+
this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
|
|
114
39
|
}
|
|
115
40
|
set logLevel(logLevel) {
|
|
116
41
|
this.log.logLevel = logLevel;
|
|
@@ -118,21 +43,10 @@ export class Frontend {
|
|
|
118
43
|
async start(port = 8283) {
|
|
119
44
|
this.port = port;
|
|
120
45
|
this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${this.port}${db}`);
|
|
121
|
-
// Create the express app that serves the frontend
|
|
122
46
|
this.expressApp = express();
|
|
123
|
-
// Log all requests to the server for debugging
|
|
124
|
-
/*
|
|
125
|
-
this.expressApp.use((req, res, next) => {
|
|
126
|
-
this.log.debug(`Received request on expressApp: ${req.method} ${req.url}`);
|
|
127
|
-
next();
|
|
128
|
-
});
|
|
129
|
-
*/
|
|
130
|
-
// Serve static files from '/static' endpoint
|
|
131
47
|
this.expressApp.use(express.static(path.join(this.matterbridge.rootDirectory, 'frontend/build')));
|
|
132
48
|
if (!hasParameter('ssl')) {
|
|
133
|
-
// Create an HTTP server and attach the express app
|
|
134
49
|
this.httpServer = createServer(this.expressApp);
|
|
135
|
-
// Listen on the specified port
|
|
136
50
|
if (hasParameter('ingress')) {
|
|
137
51
|
this.httpServer.listen(this.port, '0.0.0.0', () => {
|
|
138
52
|
this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
|
|
@@ -146,7 +60,6 @@ export class Frontend {
|
|
|
146
60
|
this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
|
|
147
61
|
});
|
|
148
62
|
}
|
|
149
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
150
63
|
this.httpServer.on('error', (error) => {
|
|
151
64
|
this.log.error(`Frontend http server error listening on ${this.port}`);
|
|
152
65
|
switch (error.code) {
|
|
@@ -162,7 +75,6 @@ export class Frontend {
|
|
|
162
75
|
});
|
|
163
76
|
}
|
|
164
77
|
else {
|
|
165
|
-
// Load the SSL certificate, the private key and optionally the CA certificate
|
|
166
78
|
let cert;
|
|
167
79
|
try {
|
|
168
80
|
cert = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
|
|
@@ -190,9 +102,7 @@ export class Frontend {
|
|
|
190
102
|
this.log.info(`CA certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
|
|
191
103
|
}
|
|
192
104
|
const serverOptions = { cert, key, ca };
|
|
193
|
-
// Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
|
|
194
105
|
this.httpsServer = https.createServer(serverOptions, this.expressApp);
|
|
195
|
-
// Listen on the specified port
|
|
196
106
|
if (hasParameter('ingress')) {
|
|
197
107
|
this.httpsServer.listen(this.port, '0.0.0.0', () => {
|
|
198
108
|
this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
|
|
@@ -206,7 +116,6 @@ export class Frontend {
|
|
|
206
116
|
this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
|
|
207
117
|
});
|
|
208
118
|
}
|
|
209
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
210
119
|
this.httpsServer.on('error', (error) => {
|
|
211
120
|
this.log.error(`Frontend https server error listening on ${this.port}`);
|
|
212
121
|
switch (error.code) {
|
|
@@ -223,18 +132,16 @@ export class Frontend {
|
|
|
223
132
|
}
|
|
224
133
|
if (this.initializeError)
|
|
225
134
|
return;
|
|
226
|
-
// Create a WebSocket server and attach it to the http or https server
|
|
227
135
|
const wssPort = this.port;
|
|
228
136
|
const wssHost = hasParameter('ssl') ? `wss://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}`;
|
|
229
137
|
this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
|
|
230
138
|
this.webSocketServer.on('connection', (ws, request) => {
|
|
231
139
|
const clientIp = request.socket.remoteAddress;
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
callbackLogLevel = "debug" /* LogLevel.DEBUG */;
|
|
140
|
+
let callbackLogLevel = "notice";
|
|
141
|
+
if (this.matterbridge.matterbridgeInformation.loggerLevel === "info" || this.matterbridge.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
|
|
142
|
+
callbackLogLevel = "info";
|
|
143
|
+
if (this.matterbridge.matterbridgeInformation.loggerLevel === "debug" || this.matterbridge.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
|
|
144
|
+
callbackLogLevel = "debug";
|
|
238
145
|
AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), callbackLogLevel);
|
|
239
146
|
this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
|
|
240
147
|
this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
|
|
@@ -268,7 +175,6 @@ export class Frontend {
|
|
|
268
175
|
this.webSocketServer.on('error', (ws, error) => {
|
|
269
176
|
this.log.error(`WebSocketServer error: ${error}`);
|
|
270
177
|
});
|
|
271
|
-
// Subscribe to cli events
|
|
272
178
|
const { cliEmitter } = await import('./cli.js');
|
|
273
179
|
cliEmitter.on('uptime', (systemUptime, processUptime) => {
|
|
274
180
|
this.wssSendUptimeUpdate(systemUptime, processUptime);
|
|
@@ -279,7 +185,6 @@ export class Frontend {
|
|
|
279
185
|
cliEmitter.on('cpu', (cpuUsage) => {
|
|
280
186
|
this.wssSendCpuUpdate(cpuUsage);
|
|
281
187
|
});
|
|
282
|
-
// Endpoint to validate login code
|
|
283
188
|
this.expressApp.post('/api/login', express.json(), async (req, res) => {
|
|
284
189
|
const { password } = req.body;
|
|
285
190
|
this.log.debug('The frontend sent /api/login', password);
|
|
@@ -298,27 +203,23 @@ export class Frontend {
|
|
|
298
203
|
this.log.warn('/api/login error wrong password');
|
|
299
204
|
res.json({ valid: false });
|
|
300
205
|
}
|
|
301
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
302
206
|
}
|
|
303
207
|
catch (error) {
|
|
304
208
|
this.log.error('/api/login error getting password');
|
|
305
209
|
res.json({ valid: false });
|
|
306
210
|
}
|
|
307
211
|
});
|
|
308
|
-
// Endpoint to provide health check
|
|
309
212
|
this.expressApp.get('/health', (req, res) => {
|
|
310
213
|
this.log.debug('Express received /health');
|
|
311
214
|
const healthStatus = {
|
|
312
|
-
status: 'ok',
|
|
313
|
-
uptime: process.uptime(),
|
|
314
|
-
timestamp: new Date().toISOString(),
|
|
215
|
+
status: 'ok',
|
|
216
|
+
uptime: process.uptime(),
|
|
217
|
+
timestamp: new Date().toISOString(),
|
|
315
218
|
};
|
|
316
219
|
res.status(200).json(healthStatus);
|
|
317
220
|
});
|
|
318
|
-
// Endpoint to provide memory usage details
|
|
319
221
|
this.expressApp.get('/memory', async (req, res) => {
|
|
320
222
|
this.log.debug('Express received /memory');
|
|
321
|
-
// Memory usage from process
|
|
322
223
|
const memoryUsageRaw = process.memoryUsage();
|
|
323
224
|
const memoryUsage = {
|
|
324
225
|
rss: this.formatMemoryUsage(memoryUsageRaw.rss),
|
|
@@ -327,13 +228,10 @@ export class Frontend {
|
|
|
327
228
|
external: this.formatMemoryUsage(memoryUsageRaw.external),
|
|
328
229
|
arrayBuffers: this.formatMemoryUsage(memoryUsageRaw.arrayBuffers),
|
|
329
230
|
};
|
|
330
|
-
// V8 heap statistics
|
|
331
231
|
const { default: v8 } = await import('node:v8');
|
|
332
232
|
const heapStatsRaw = v8.getHeapStatistics();
|
|
333
233
|
const heapSpacesRaw = v8.getHeapSpaceStatistics();
|
|
334
|
-
// Format heapStats
|
|
335
234
|
const heapStats = Object.fromEntries(Object.entries(heapStatsRaw).map(([key, value]) => [key, this.formatMemoryUsage(value)]));
|
|
336
|
-
// Format heapSpaces
|
|
337
235
|
const heapSpaces = heapSpacesRaw.map((space) => ({
|
|
338
236
|
...space,
|
|
339
237
|
space_size: this.formatMemoryUsage(space.space_size),
|
|
@@ -351,7 +249,6 @@ export class Frontend {
|
|
|
351
249
|
};
|
|
352
250
|
res.status(200).json(memoryReport);
|
|
353
251
|
});
|
|
354
|
-
// Endpoint to start advertising the server node
|
|
355
252
|
this.expressApp.get('/api/advertise', express.json(), async (req, res) => {
|
|
356
253
|
const pairingCodes = await this.matterbridge.advertiseServerNode(this.matterbridge.serverNode);
|
|
357
254
|
if (pairingCodes) {
|
|
@@ -362,22 +259,18 @@ export class Frontend {
|
|
|
362
259
|
res.status(500).json({ error: 'Failed to generate pairing codes' });
|
|
363
260
|
}
|
|
364
261
|
});
|
|
365
|
-
// Endpoint to provide settings
|
|
366
262
|
this.expressApp.get('/api/settings', express.json(), async (req, res) => {
|
|
367
263
|
this.log.debug('The frontend sent /api/settings');
|
|
368
264
|
res.json(await this.getApiSettings());
|
|
369
265
|
});
|
|
370
|
-
// Endpoint to provide plugins
|
|
371
266
|
this.expressApp.get('/api/plugins', async (req, res) => {
|
|
372
267
|
this.log.debug('The frontend sent /api/plugins');
|
|
373
268
|
res.json(this.getBaseRegisteredPlugins());
|
|
374
269
|
});
|
|
375
|
-
// Endpoint to provide devices
|
|
376
270
|
this.expressApp.get('/api/devices', (req, res) => {
|
|
377
271
|
this.log.debug('The frontend sent /api/devices');
|
|
378
272
|
const devices = [];
|
|
379
273
|
this.matterbridge.devices.forEach(async (device) => {
|
|
380
|
-
// Check if the device has the required properties
|
|
381
274
|
if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
|
|
382
275
|
return;
|
|
383
276
|
const cluster = this.getClusterTextFromDevice(device);
|
|
@@ -395,7 +288,6 @@ export class Frontend {
|
|
|
395
288
|
});
|
|
396
289
|
res.json(devices);
|
|
397
290
|
});
|
|
398
|
-
// Endpoint to provide the cluster servers of the devices
|
|
399
291
|
this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
|
|
400
292
|
const selectedPluginName = req.params.selectedPluginName;
|
|
401
293
|
const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
|
|
@@ -468,7 +360,6 @@ export class Frontend {
|
|
|
468
360
|
});
|
|
469
361
|
res.json(data);
|
|
470
362
|
});
|
|
471
|
-
// Endpoint to view the log
|
|
472
363
|
this.expressApp.get('/api/view-log', async (req, res) => {
|
|
473
364
|
this.log.debug('The frontend sent /api/log');
|
|
474
365
|
try {
|
|
@@ -481,12 +372,10 @@ export class Frontend {
|
|
|
481
372
|
res.status(500).send('Error reading log file');
|
|
482
373
|
}
|
|
483
374
|
});
|
|
484
|
-
// Endpoint to download the matterbridge log
|
|
485
375
|
this.expressApp.get('/api/download-mblog', async (req, res) => {
|
|
486
376
|
this.log.debug('The frontend sent /api/download-mblog');
|
|
487
377
|
try {
|
|
488
378
|
await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), fs.constants.F_OK);
|
|
489
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
490
379
|
}
|
|
491
380
|
catch (error) {
|
|
492
381
|
fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
|
|
@@ -498,12 +387,10 @@ export class Frontend {
|
|
|
498
387
|
}
|
|
499
388
|
});
|
|
500
389
|
});
|
|
501
|
-
// Endpoint to download the matter log
|
|
502
390
|
this.expressApp.get('/api/download-mjlog', async (req, res) => {
|
|
503
391
|
this.log.debug('The frontend sent /api/download-mjlog');
|
|
504
392
|
try {
|
|
505
393
|
await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), fs.constants.F_OK);
|
|
506
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
507
394
|
}
|
|
508
395
|
catch (error) {
|
|
509
396
|
fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
|
|
@@ -515,7 +402,6 @@ export class Frontend {
|
|
|
515
402
|
}
|
|
516
403
|
});
|
|
517
404
|
});
|
|
518
|
-
// Endpoint to download the matter storage file
|
|
519
405
|
this.expressApp.get('/api/download-mjstorage', async (req, res) => {
|
|
520
406
|
this.log.debug('The frontend sent /api/download-mjstorage');
|
|
521
407
|
await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.matterStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterStorageName));
|
|
@@ -526,7 +412,6 @@ export class Frontend {
|
|
|
526
412
|
}
|
|
527
413
|
});
|
|
528
414
|
});
|
|
529
|
-
// Endpoint to download the matterbridge storage directory
|
|
530
415
|
this.expressApp.get('/api/download-mbstorage', async (req, res) => {
|
|
531
416
|
this.log.debug('The frontend sent /api/download-mbstorage');
|
|
532
417
|
await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.nodeStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.nodeStorageName));
|
|
@@ -537,7 +422,6 @@ export class Frontend {
|
|
|
537
422
|
}
|
|
538
423
|
});
|
|
539
424
|
});
|
|
540
|
-
// Endpoint to download the matterbridge plugin directory
|
|
541
425
|
this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
|
|
542
426
|
this.log.debug('The frontend sent /api/download-pluginstorage');
|
|
543
427
|
await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridge.matterbridgePluginDirectory);
|
|
@@ -548,11 +432,9 @@ export class Frontend {
|
|
|
548
432
|
}
|
|
549
433
|
});
|
|
550
434
|
});
|
|
551
|
-
// Endpoint to download the matterbridge plugin config files
|
|
552
435
|
this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
|
|
553
436
|
this.log.debug('The frontend sent /api/download-pluginconfig');
|
|
554
437
|
await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, '*.config.json')));
|
|
555
|
-
// 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')));
|
|
556
438
|
res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
|
|
557
439
|
if (error) {
|
|
558
440
|
this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
|
|
@@ -560,7 +442,6 @@ export class Frontend {
|
|
|
560
442
|
}
|
|
561
443
|
});
|
|
562
444
|
});
|
|
563
|
-
// Endpoint to download the matterbridge plugin config files
|
|
564
445
|
this.expressApp.get('/api/download-backup', async (req, res) => {
|
|
565
446
|
this.log.debug('The frontend sent /api/download-backup');
|
|
566
447
|
res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
|
|
@@ -570,7 +451,6 @@ export class Frontend {
|
|
|
570
451
|
}
|
|
571
452
|
});
|
|
572
453
|
});
|
|
573
|
-
// Endpoint to receive commands
|
|
574
454
|
this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
|
|
575
455
|
const command = req.params.command;
|
|
576
456
|
let param = req.params.param;
|
|
@@ -580,15 +460,13 @@ export class Frontend {
|
|
|
580
460
|
return;
|
|
581
461
|
}
|
|
582
462
|
this.log.debug(`Received frontend command: ${command}:${param}`);
|
|
583
|
-
// Handle the command setpassword from Settings
|
|
584
463
|
if (command === 'setpassword') {
|
|
585
|
-
const password = param.slice(1, -1);
|
|
464
|
+
const password = param.slice(1, -1);
|
|
586
465
|
this.log.debug('setpassword', param, password);
|
|
587
466
|
await this.matterbridge.nodeContext?.set('password', password);
|
|
588
467
|
res.json({ message: 'Command received' });
|
|
589
468
|
return;
|
|
590
469
|
}
|
|
591
|
-
// Handle the command setbridgemode from Settings
|
|
592
470
|
if (command === 'setbridgemode') {
|
|
593
471
|
this.log.debug(`setbridgemode: ${param}`);
|
|
594
472
|
this.wssSendRestartRequired();
|
|
@@ -596,7 +474,6 @@ export class Frontend {
|
|
|
596
474
|
res.json({ message: 'Command received' });
|
|
597
475
|
return;
|
|
598
476
|
}
|
|
599
|
-
// Handle the command backup from Settings
|
|
600
477
|
if (command === 'backup') {
|
|
601
478
|
this.log.notice(`Prepairing the backup...`);
|
|
602
479
|
await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridge.matterbridgeDirectory), path.join(this.matterbridge.matterbridgePluginDirectory));
|
|
@@ -605,33 +482,31 @@ export class Frontend {
|
|
|
605
482
|
res.json({ message: 'Command received' });
|
|
606
483
|
return;
|
|
607
484
|
}
|
|
608
|
-
// Handle the command setmbloglevel from Settings
|
|
609
485
|
if (command === 'setmbloglevel') {
|
|
610
486
|
this.log.debug('Matterbridge log level:', param);
|
|
611
487
|
if (param === 'Debug') {
|
|
612
|
-
this.log.logLevel = "debug"
|
|
488
|
+
this.log.logLevel = "debug";
|
|
613
489
|
}
|
|
614
490
|
else if (param === 'Info') {
|
|
615
|
-
this.log.logLevel = "info"
|
|
491
|
+
this.log.logLevel = "info";
|
|
616
492
|
}
|
|
617
493
|
else if (param === 'Notice') {
|
|
618
|
-
this.log.logLevel = "notice"
|
|
494
|
+
this.log.logLevel = "notice";
|
|
619
495
|
}
|
|
620
496
|
else if (param === 'Warn') {
|
|
621
|
-
this.log.logLevel = "warn"
|
|
497
|
+
this.log.logLevel = "warn";
|
|
622
498
|
}
|
|
623
499
|
else if (param === 'Error') {
|
|
624
|
-
this.log.logLevel = "error"
|
|
500
|
+
this.log.logLevel = "error";
|
|
625
501
|
}
|
|
626
502
|
else if (param === 'Fatal') {
|
|
627
|
-
this.log.logLevel = "fatal"
|
|
503
|
+
this.log.logLevel = "fatal";
|
|
628
504
|
}
|
|
629
505
|
await this.matterbridge.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
|
|
630
506
|
await this.matterbridge.setLogLevel(this.log.logLevel);
|
|
631
507
|
res.json({ message: 'Command received' });
|
|
632
508
|
return;
|
|
633
509
|
}
|
|
634
|
-
// Handle the command setmbloglevel from Settings
|
|
635
510
|
if (command === 'setmjloglevel') {
|
|
636
511
|
this.log.debug('Matter.js log level:', param);
|
|
637
512
|
if (param === 'Debug') {
|
|
@@ -656,34 +531,30 @@ export class Frontend {
|
|
|
656
531
|
res.json({ message: 'Command received' });
|
|
657
532
|
return;
|
|
658
533
|
}
|
|
659
|
-
// Handle the command setmdnsinterface from Settings
|
|
660
534
|
if (command === 'setmdnsinterface') {
|
|
661
|
-
param = param.slice(1, -1);
|
|
535
|
+
param = param.slice(1, -1);
|
|
662
536
|
this.matterbridge.matterbridgeInformation.mattermdnsinterface = param;
|
|
663
537
|
this.log.debug('Matter.js mdns interface:', param === '' ? 'All interfaces' : param);
|
|
664
538
|
await this.matterbridge.nodeContext?.set('mattermdnsinterface', param);
|
|
665
539
|
res.json({ message: 'Command received' });
|
|
666
540
|
return;
|
|
667
541
|
}
|
|
668
|
-
// Handle the command setipv4address from Settings
|
|
669
542
|
if (command === 'setipv4address') {
|
|
670
|
-
param = param.slice(1, -1);
|
|
543
|
+
param = param.slice(1, -1);
|
|
671
544
|
this.matterbridge.matterbridgeInformation.matteripv4address = param;
|
|
672
545
|
this.log.debug('Matter.js ipv4 address:', param === '' ? 'All ipv4 addresses' : param);
|
|
673
546
|
await this.matterbridge.nodeContext?.set('matteripv4address', param);
|
|
674
547
|
res.json({ message: 'Command received' });
|
|
675
548
|
return;
|
|
676
549
|
}
|
|
677
|
-
// Handle the command setipv6address from Settings
|
|
678
550
|
if (command === 'setipv6address') {
|
|
679
|
-
param = param.slice(1, -1);
|
|
551
|
+
param = param.slice(1, -1);
|
|
680
552
|
this.matterbridge.matterbridgeInformation.matteripv6address = param;
|
|
681
553
|
this.log.debug('Matter.js ipv6 address:', param === '' ? 'All ipv6 addresses' : param);
|
|
682
554
|
await this.matterbridge.nodeContext?.set('matteripv6address', param);
|
|
683
555
|
res.json({ message: 'Command received' });
|
|
684
556
|
return;
|
|
685
557
|
}
|
|
686
|
-
// Handle the command setmatterport from Settings
|
|
687
558
|
if (command === 'setmatterport') {
|
|
688
559
|
const port = Math.min(Math.max(parseInt(param), 5540), 5560);
|
|
689
560
|
this.matterbridge.matterbridgeInformation.matterPort = port;
|
|
@@ -692,7 +563,6 @@ export class Frontend {
|
|
|
692
563
|
res.json({ message: 'Command received' });
|
|
693
564
|
return;
|
|
694
565
|
}
|
|
695
|
-
// Handle the command setmatterdiscriminator from Settings
|
|
696
566
|
if (command === 'setmatterdiscriminator') {
|
|
697
567
|
const discriminator = Math.min(Math.max(parseInt(param), 1000), 4095);
|
|
698
568
|
this.matterbridge.matterbridgeInformation.matterDiscriminator = discriminator;
|
|
@@ -701,7 +571,6 @@ export class Frontend {
|
|
|
701
571
|
res.json({ message: 'Command received' });
|
|
702
572
|
return;
|
|
703
573
|
}
|
|
704
|
-
// Handle the command setmatterpasscode from Settings
|
|
705
574
|
if (command === 'setmatterpasscode') {
|
|
706
575
|
const passcode = Math.min(Math.max(parseInt(param), 10000000), 90000000);
|
|
707
576
|
this.matterbridge.matterbridgeInformation.matterPasscode = passcode;
|
|
@@ -710,20 +579,17 @@ export class Frontend {
|
|
|
710
579
|
res.json({ message: 'Command received' });
|
|
711
580
|
return;
|
|
712
581
|
}
|
|
713
|
-
// Handle the command setmbloglevel from Settings
|
|
714
582
|
if (command === 'setmblogfile') {
|
|
715
583
|
this.log.debug('Matterbridge file log:', param);
|
|
716
584
|
this.matterbridge.matterbridgeInformation.fileLogger = param === 'true';
|
|
717
585
|
await this.matterbridge.nodeContext?.set('matterbridgeFileLog', param === 'true');
|
|
718
|
-
// Create the file logger for matterbridge
|
|
719
586
|
if (param === 'true')
|
|
720
|
-
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug"
|
|
587
|
+
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug", true);
|
|
721
588
|
else
|
|
722
589
|
AnsiLogger.setGlobalLogfile(undefined);
|
|
723
590
|
res.json({ message: 'Command received' });
|
|
724
591
|
return;
|
|
725
592
|
}
|
|
726
|
-
// Handle the command setmbloglevel from Settings
|
|
727
593
|
if (command === 'setmjlogfile') {
|
|
728
594
|
this.log.debug('Matter file log:', param);
|
|
729
595
|
this.matterbridge.matterbridgeInformation.matterFileLogger = param === 'true';
|
|
@@ -750,48 +616,40 @@ export class Frontend {
|
|
|
750
616
|
res.json({ message: 'Command received' });
|
|
751
617
|
return;
|
|
752
618
|
}
|
|
753
|
-
// Handle the command unregister from Settings
|
|
754
619
|
if (command === 'unregister') {
|
|
755
620
|
await this.matterbridge.unregisterAndShutdownProcess();
|
|
756
621
|
res.json({ message: 'Command received' });
|
|
757
622
|
return;
|
|
758
623
|
}
|
|
759
|
-
// Handle the command reset from Settings
|
|
760
624
|
if (command === 'reset') {
|
|
761
625
|
await this.matterbridge.shutdownProcessAndReset();
|
|
762
626
|
res.json({ message: 'Command received' });
|
|
763
627
|
return;
|
|
764
628
|
}
|
|
765
|
-
// Handle the command factoryreset from Settings
|
|
766
629
|
if (command === 'factoryreset') {
|
|
767
630
|
await this.matterbridge.shutdownProcessAndFactoryReset();
|
|
768
631
|
res.json({ message: 'Command received' });
|
|
769
632
|
return;
|
|
770
633
|
}
|
|
771
|
-
// Handle the command shutdown from Header
|
|
772
634
|
if (command === 'shutdown') {
|
|
773
635
|
await this.matterbridge.shutdownProcess();
|
|
774
636
|
res.json({ message: 'Command received' });
|
|
775
637
|
return;
|
|
776
638
|
}
|
|
777
|
-
// Handle the command restart from Header
|
|
778
639
|
if (command === 'restart') {
|
|
779
640
|
await this.matterbridge.restartProcess();
|
|
780
641
|
res.json({ message: 'Command received' });
|
|
781
642
|
return;
|
|
782
643
|
}
|
|
783
|
-
// Handle the command update from Header
|
|
784
644
|
if (command === 'update') {
|
|
785
645
|
await this.matterbridge.updateProcess();
|
|
786
646
|
this.wssSendRestartRequired();
|
|
787
647
|
res.json({ message: 'Command received' });
|
|
788
648
|
return;
|
|
789
649
|
}
|
|
790
|
-
// Handle the command saveconfig from Home
|
|
791
650
|
if (command === 'saveconfig') {
|
|
792
651
|
param = param.replace(/\*/g, '\\');
|
|
793
652
|
this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
|
|
794
|
-
// console.log('Req.body:', JSON.stringify(req.body, null, 2));
|
|
795
653
|
if (!this.matterbridge.plugins.has(param)) {
|
|
796
654
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
797
655
|
}
|
|
@@ -806,7 +664,6 @@ export class Frontend {
|
|
|
806
664
|
res.json({ message: 'Command received' });
|
|
807
665
|
return;
|
|
808
666
|
}
|
|
809
|
-
// Handle the command installplugin from Home
|
|
810
667
|
if (command === 'installplugin') {
|
|
811
668
|
param = param.replace(/\*/g, '\\');
|
|
812
669
|
this.log.info(`Installing plugin ${plg}${param}${nf}...`);
|
|
@@ -815,7 +672,6 @@ export class Frontend {
|
|
|
815
672
|
await this.matterbridge.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
|
|
816
673
|
this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
|
|
817
674
|
this.wssSendSnackbarMessage(`Installed package ${param}`);
|
|
818
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
819
675
|
}
|
|
820
676
|
catch (error) {
|
|
821
677
|
this.log.error(`Error installing plugin ${plg}${param}${er}`);
|
|
@@ -824,21 +680,16 @@ export class Frontend {
|
|
|
824
680
|
this.wssSendSnackbarMessage(`Restart required`, 0);
|
|
825
681
|
this.wssSendRestartRequired();
|
|
826
682
|
param = param.split('@')[0];
|
|
827
|
-
// Also add the plugin to matterbridge so no return!
|
|
828
683
|
if (param === 'matterbridge') {
|
|
829
|
-
// 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
|
|
830
684
|
res.json({ message: 'Command received' });
|
|
831
685
|
return;
|
|
832
686
|
}
|
|
833
687
|
}
|
|
834
|
-
// Handle the command addplugin from Home
|
|
835
688
|
if (command === 'addplugin' || command === 'installplugin') {
|
|
836
689
|
param = param.replace(/\*/g, '\\');
|
|
837
690
|
const plugin = await this.matterbridge.plugins.add(param);
|
|
838
691
|
if (plugin) {
|
|
839
692
|
if (this.matterbridge.bridgeMode === 'childbridge') {
|
|
840
|
-
// 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
|
|
841
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
842
693
|
this.matterbridge.createDynamicPlugin(plugin, true);
|
|
843
694
|
}
|
|
844
695
|
this.matterbridge.plugins.load(plugin, true, 'The plugin has been added', true).then(() => {
|
|
@@ -848,21 +699,19 @@ export class Frontend {
|
|
|
848
699
|
res.json({ message: 'Command received' });
|
|
849
700
|
return;
|
|
850
701
|
}
|
|
851
|
-
// Handle the command removeplugin from Home
|
|
852
702
|
if (command === 'removeplugin') {
|
|
853
703
|
if (!this.matterbridge.plugins.has(param)) {
|
|
854
704
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
855
705
|
}
|
|
856
706
|
else {
|
|
857
707
|
const plugin = this.matterbridge.plugins.get(param);
|
|
858
|
-
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true);
|
|
708
|
+
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true);
|
|
859
709
|
await this.matterbridge.plugins.remove(param);
|
|
860
710
|
}
|
|
861
711
|
res.json({ message: 'Command received' });
|
|
862
712
|
this.wssSendRefreshRequired();
|
|
863
713
|
return;
|
|
864
714
|
}
|
|
865
|
-
// Handle the command enableplugin from Home
|
|
866
715
|
if (command === 'enableplugin') {
|
|
867
716
|
if (!this.matterbridge.plugins.has(param)) {
|
|
868
717
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
@@ -880,7 +729,6 @@ export class Frontend {
|
|
|
880
729
|
plugin.addedDevices = undefined;
|
|
881
730
|
await this.matterbridge.plugins.enable(param);
|
|
882
731
|
if (this.matterbridge.bridgeMode === 'childbridge' && plugin.type === 'DynamicPlatform') {
|
|
883
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
884
732
|
this.matterbridge.createDynamicPlugin(plugin, true);
|
|
885
733
|
}
|
|
886
734
|
this.matterbridge.plugins.load(plugin, true, 'The plugin has been enabled', true).then(() => {
|
|
@@ -892,7 +740,6 @@ export class Frontend {
|
|
|
892
740
|
this.wssSendRefreshRequired();
|
|
893
741
|
return;
|
|
894
742
|
}
|
|
895
|
-
// Handle the command disableplugin from Home
|
|
896
743
|
if (command === 'disableplugin') {
|
|
897
744
|
if (!this.matterbridge.plugins.has(param)) {
|
|
898
745
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
@@ -900,7 +747,7 @@ export class Frontend {
|
|
|
900
747
|
else {
|
|
901
748
|
const plugin = this.matterbridge.plugins.get(param);
|
|
902
749
|
if (plugin && plugin.enabled) {
|
|
903
|
-
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true);
|
|
750
|
+
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true);
|
|
904
751
|
await this.matterbridge.plugins.disable(param);
|
|
905
752
|
}
|
|
906
753
|
}
|
|
@@ -909,7 +756,6 @@ export class Frontend {
|
|
|
909
756
|
return;
|
|
910
757
|
}
|
|
911
758
|
});
|
|
912
|
-
// Fallback for routing (must be the last route)
|
|
913
759
|
this.expressApp.get('*', (req, res) => {
|
|
914
760
|
this.log.debug('The frontend sent:', req.url);
|
|
915
761
|
this.log.debug('Response send file:', path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
|
|
@@ -918,29 +764,24 @@ export class Frontend {
|
|
|
918
764
|
this.log.debug(`Frontend initialized on port ${YELLOW}${this.port}${db} static ${UNDERLINE}${path.join(this.matterbridge.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
|
|
919
765
|
}
|
|
920
766
|
async stop() {
|
|
921
|
-
// Close the http server
|
|
922
767
|
if (this.httpServer) {
|
|
923
768
|
this.httpServer.close();
|
|
924
769
|
this.httpServer.removeAllListeners();
|
|
925
770
|
this.httpServer = undefined;
|
|
926
771
|
this.log.debug('Frontend http server closed successfully');
|
|
927
772
|
}
|
|
928
|
-
// Close the https server
|
|
929
773
|
if (this.httpsServer) {
|
|
930
774
|
this.httpsServer.close();
|
|
931
775
|
this.httpsServer.removeAllListeners();
|
|
932
776
|
this.httpsServer = undefined;
|
|
933
777
|
this.log.debug('Frontend https server closed successfully');
|
|
934
778
|
}
|
|
935
|
-
// Remove listeners from the express app
|
|
936
779
|
if (this.expressApp) {
|
|
937
780
|
this.expressApp.removeAllListeners();
|
|
938
781
|
this.expressApp = undefined;
|
|
939
782
|
this.log.debug('Frontend app closed successfully');
|
|
940
783
|
}
|
|
941
|
-
// Close the WebSocket server
|
|
942
784
|
if (this.webSocketServer) {
|
|
943
|
-
// Close all active connections
|
|
944
785
|
this.webSocketServer.clients.forEach((client) => {
|
|
945
786
|
if (client.readyState === WebSocket.OPEN) {
|
|
946
787
|
client.close();
|
|
@@ -957,7 +798,6 @@ export class Frontend {
|
|
|
957
798
|
this.webSocketServer = undefined;
|
|
958
799
|
}
|
|
959
800
|
}
|
|
960
|
-
// Function to format bytes to KB, MB, or GB
|
|
961
801
|
formatMemoryUsage = (bytes) => {
|
|
962
802
|
if (bytes >= 1024 ** 3) {
|
|
963
803
|
return `${(bytes / 1024 ** 3).toFixed(2)} GB`;
|
|
@@ -969,7 +809,6 @@ export class Frontend {
|
|
|
969
809
|
return `${(bytes / 1024).toFixed(2)} KB`;
|
|
970
810
|
}
|
|
971
811
|
};
|
|
972
|
-
// Function to format system uptime with only the most significant unit
|
|
973
812
|
formatOsUpTime = (seconds) => {
|
|
974
813
|
if (seconds >= 86400) {
|
|
975
814
|
const days = Math.floor(seconds / 86400);
|
|
@@ -985,13 +824,8 @@ export class Frontend {
|
|
|
985
824
|
}
|
|
986
825
|
return `${seconds} second${seconds !== 1 ? 's' : ''}`;
|
|
987
826
|
};
|
|
988
|
-
/**
|
|
989
|
-
* Retrieves the api settings data.
|
|
990
|
-
* @returns {Promise<object>} A promise that resolve in the api settings object.
|
|
991
|
-
*/
|
|
992
827
|
async getApiSettings() {
|
|
993
828
|
const { lastCpuUsage } = await import('./cli.js');
|
|
994
|
-
// Update the system information
|
|
995
829
|
this.matterbridge.systemInformation.totalMemory = this.formatMemoryUsage(os.totalmem());
|
|
996
830
|
this.matterbridge.systemInformation.freeMemory = this.formatMemoryUsage(os.freemem());
|
|
997
831
|
this.matterbridge.systemInformation.systemUptime = this.formatOsUpTime(os.uptime());
|
|
@@ -1000,7 +834,6 @@ export class Frontend {
|
|
|
1000
834
|
this.matterbridge.systemInformation.rss = this.formatMemoryUsage(process.memoryUsage().rss);
|
|
1001
835
|
this.matterbridge.systemInformation.heapTotal = this.formatMemoryUsage(process.memoryUsage().heapTotal);
|
|
1002
836
|
this.matterbridge.systemInformation.heapUsed = this.formatMemoryUsage(process.memoryUsage().heapUsed);
|
|
1003
|
-
// Update the matterbridge information
|
|
1004
837
|
this.matterbridge.matterbridgeInformation.bridgeMode = this.matterbridge.bridgeMode;
|
|
1005
838
|
this.matterbridge.matterbridgeInformation.restartMode = this.matterbridge.restartMode;
|
|
1006
839
|
this.matterbridge.matterbridgeInformation.loggerLevel = this.matterbridge.log.logLevel;
|
|
@@ -1019,11 +852,6 @@ export class Frontend {
|
|
|
1019
852
|
this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
|
|
1020
853
|
return { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: this.matterbridge.matterbridgeInformation };
|
|
1021
854
|
}
|
|
1022
|
-
/**
|
|
1023
|
-
* Retrieves the cluster text description from a given device.
|
|
1024
|
-
* @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
|
|
1025
|
-
* @returns {string} The attributes description of the cluster servers in the device.
|
|
1026
|
-
*/
|
|
1027
855
|
getClusterTextFromDevice(device) {
|
|
1028
856
|
const getAttribute = (device, cluster, attribute) => {
|
|
1029
857
|
let value = undefined;
|
|
@@ -1062,7 +890,6 @@ export class Frontend {
|
|
|
1062
890
|
};
|
|
1063
891
|
let attributes = '';
|
|
1064
892
|
device.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
|
|
1065
|
-
// console.log(`${device.deviceName} => Cluster: ${clusterName}-${clusterId} Attribute: ${attributeName}-${attributeId} Value(${typeof attributeValue}): ${attributeValue}`);
|
|
1066
893
|
if (typeof attributeValue === 'undefined')
|
|
1067
894
|
return;
|
|
1068
895
|
if (clusterName === 'onOff' && attributeName === 'onOff')
|
|
@@ -1140,13 +967,8 @@ export class Frontend {
|
|
|
1140
967
|
if (clusterName === 'userLabel' && attributeName === 'labelList')
|
|
1141
968
|
attributes += `${getUserLabel(device)} `;
|
|
1142
969
|
});
|
|
1143
|
-
// console.log(`${device.deviceName}.forEachAttribute: ${attributes}`);
|
|
1144
970
|
return attributes.trimStart().trimEnd();
|
|
1145
971
|
}
|
|
1146
|
-
/**
|
|
1147
|
-
* Retrieves the base registered plugins sanitized for res.json().
|
|
1148
|
-
* @returns {BaseRegisteredPlugin[]} An array of BaseRegisteredPlugin.
|
|
1149
|
-
*/
|
|
1150
972
|
getBaseRegisteredPlugins() {
|
|
1151
973
|
const baseRegisteredPlugins = [];
|
|
1152
974
|
for (const plugin of this.matterbridge.plugins) {
|
|
@@ -1177,13 +999,6 @@ export class Frontend {
|
|
|
1177
999
|
}
|
|
1178
1000
|
return baseRegisteredPlugins;
|
|
1179
1001
|
}
|
|
1180
|
-
/**
|
|
1181
|
-
* Handles incoming websocket messages for the Matterbridge frontend.
|
|
1182
|
-
*
|
|
1183
|
-
* @param {WebSocket} client - The websocket client that sent the message.
|
|
1184
|
-
* @param {WebSocket.RawData} message - The raw data of the message received from the client.
|
|
1185
|
-
* @returns {Promise<void>} A promise that resolves when the message has been handled.
|
|
1186
|
-
*/
|
|
1187
1002
|
async wsMessageHandler(client, message) {
|
|
1188
1003
|
let data;
|
|
1189
1004
|
try {
|
|
@@ -1324,10 +1139,8 @@ export class Frontend {
|
|
|
1324
1139
|
else if (data.method === '/api/devices') {
|
|
1325
1140
|
const devices = [];
|
|
1326
1141
|
this.matterbridge.devices.forEach(async (device) => {
|
|
1327
|
-
// Filter by pluginName if provided
|
|
1328
1142
|
if (data.params.pluginName && data.params.pluginName !== device.plugin)
|
|
1329
1143
|
return;
|
|
1330
|
-
// Check if the device has the required properties
|
|
1331
1144
|
if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
|
|
1332
1145
|
return;
|
|
1333
1146
|
const cluster = this.getClusterTextFromDevice(device);
|
|
@@ -1410,7 +1223,6 @@ export class Frontend {
|
|
|
1410
1223
|
});
|
|
1411
1224
|
endpointServer.getChildEndpoints().forEach((childEndpoint) => {
|
|
1412
1225
|
deviceTypes = [];
|
|
1413
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1414
1226
|
const name = childEndpoint.endpoint?.id;
|
|
1415
1227
|
const clusterServers = childEndpoint.getAllClusterServers();
|
|
1416
1228
|
clusterServers.forEach((clusterServer) => {
|
|
@@ -1493,139 +1305,85 @@ export class Frontend {
|
|
|
1493
1305
|
return;
|
|
1494
1306
|
}
|
|
1495
1307
|
}
|
|
1496
|
-
/**
|
|
1497
|
-
* Sends a WebSocket message to all connected clients. The function is called by AnsiLogger.setGlobalCallback.
|
|
1498
|
-
*
|
|
1499
|
-
* @param {string} level - The logger level of the message: debug info notice warn error fatal...
|
|
1500
|
-
* @param {string} time - The time string of the message
|
|
1501
|
-
* @param {string} name - The logger name of the message
|
|
1502
|
-
* @param {string} message - The content of the message.
|
|
1503
|
-
*/
|
|
1504
1308
|
wssSendMessage(level, time, name, message) {
|
|
1505
1309
|
if (!level || !time || !name || !message)
|
|
1506
1310
|
return;
|
|
1507
|
-
// Remove ANSI escape codes from the message
|
|
1508
|
-
// eslint-disable-next-line no-control-regex
|
|
1509
1311
|
message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
|
|
1510
|
-
// Remove leading asterisks from the message
|
|
1511
1312
|
message = message.replace(/^\*+/, '');
|
|
1512
|
-
// Replace all occurrences of \t and \n
|
|
1513
1313
|
message = message.replace(/[\t\n]/g, '');
|
|
1514
|
-
// Remove non-printable characters
|
|
1515
|
-
// eslint-disable-next-line no-control-regex
|
|
1516
1314
|
message = message.replace(/[\x00-\x1F\x7F]/g, '');
|
|
1517
|
-
// Replace all occurrences of \" with "
|
|
1518
1315
|
message = message.replace(/\\"/g, '"');
|
|
1519
|
-
// Define the maximum allowed length for continuous characters without a space
|
|
1520
1316
|
const maxContinuousLength = 100;
|
|
1521
1317
|
const keepStartLength = 20;
|
|
1522
1318
|
const keepEndLength = 20;
|
|
1523
|
-
// Split the message into words
|
|
1524
1319
|
message = message
|
|
1525
1320
|
.split(' ')
|
|
1526
1321
|
.map((word) => {
|
|
1527
|
-
// If the word length exceeds the max continuous length, insert spaces and truncate
|
|
1528
1322
|
if (word.length > maxContinuousLength) {
|
|
1529
1323
|
return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
|
|
1530
1324
|
}
|
|
1531
1325
|
return word;
|
|
1532
1326
|
})
|
|
1533
1327
|
.join(' ');
|
|
1534
|
-
// Send the message to all connected clients
|
|
1535
1328
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1536
1329
|
if (client.readyState === WebSocket.OPEN) {
|
|
1537
1330
|
client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
|
|
1538
1331
|
}
|
|
1539
1332
|
});
|
|
1540
1333
|
}
|
|
1541
|
-
/**
|
|
1542
|
-
* Sends a need to refresh WebSocket message to all connected clients.
|
|
1543
|
-
*
|
|
1544
|
-
*/
|
|
1545
1334
|
wssSendRefreshRequired() {
|
|
1546
1335
|
this.log.debug('Sending a refresh required message to all connected clients');
|
|
1547
1336
|
this.matterbridge.matterbridgeInformation.refreshRequired = true;
|
|
1548
|
-
// Send the message to all connected clients
|
|
1549
1337
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1550
1338
|
if (client.readyState === WebSocket.OPEN) {
|
|
1551
1339
|
client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', params: {} }));
|
|
1552
1340
|
}
|
|
1553
1341
|
});
|
|
1554
1342
|
}
|
|
1555
|
-
/**
|
|
1556
|
-
* Sends a need to restart WebSocket message to all connected clients.
|
|
1557
|
-
*
|
|
1558
|
-
*/
|
|
1559
1343
|
wssSendRestartRequired() {
|
|
1560
1344
|
this.log.debug('Sending a restart required message to all connected clients');
|
|
1561
1345
|
this.matterbridge.matterbridgeInformation.restartRequired = true;
|
|
1562
1346
|
this.wssSendSnackbarMessage(`Restart required`, 0);
|
|
1563
|
-
// Send the message to all connected clients
|
|
1564
1347
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1565
1348
|
if (client.readyState === WebSocket.OPEN) {
|
|
1566
1349
|
client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', params: {} }));
|
|
1567
1350
|
}
|
|
1568
1351
|
});
|
|
1569
1352
|
}
|
|
1570
|
-
/**
|
|
1571
|
-
* Sends a memory update message to all connected clients.
|
|
1572
|
-
*
|
|
1573
|
-
*/
|
|
1574
1353
|
wssSendCpuUpdate(cpuUsage) {
|
|
1575
1354
|
this.log.debug('Sending a cpu update message to all connected clients');
|
|
1576
|
-
// Send the message to all connected clients
|
|
1577
1355
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1578
1356
|
if (client.readyState === WebSocket.OPEN) {
|
|
1579
1357
|
client.send(JSON.stringify({ id: WS_ID_CPU_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'cpu_update', params: { cpuUsage } }));
|
|
1580
1358
|
}
|
|
1581
1359
|
});
|
|
1582
1360
|
}
|
|
1583
|
-
/**
|
|
1584
|
-
* Sends a cpu update message to all connected clients.
|
|
1585
|
-
*
|
|
1586
|
-
*/
|
|
1587
1361
|
wssSendMemoryUpdate(totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers) {
|
|
1588
1362
|
this.log.debug('Sending a memory update message to all connected clients');
|
|
1589
|
-
// Send the message to all connected clients
|
|
1590
1363
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1591
1364
|
if (client.readyState === WebSocket.OPEN) {
|
|
1592
1365
|
client.send(JSON.stringify({ id: WS_ID_MEMORY_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', params: { totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers } }));
|
|
1593
1366
|
}
|
|
1594
1367
|
});
|
|
1595
1368
|
}
|
|
1596
|
-
/**
|
|
1597
|
-
* Sends a memory update message to all connected clients.
|
|
1598
|
-
*
|
|
1599
|
-
*/
|
|
1600
1369
|
wssSendUptimeUpdate(systemUptime, processUptime) {
|
|
1601
1370
|
this.log.debug('Sending a uptime update message to all connected clients');
|
|
1602
|
-
// Send the message to all connected clients
|
|
1603
1371
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1604
1372
|
if (client.readyState === WebSocket.OPEN) {
|
|
1605
1373
|
client.send(JSON.stringify({ id: WS_ID_UPTIME_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'uptime_update', params: { systemUptime, processUptime } }));
|
|
1606
1374
|
}
|
|
1607
1375
|
});
|
|
1608
1376
|
}
|
|
1609
|
-
/**
|
|
1610
|
-
* Sends a cpu update message to all connected clients.
|
|
1611
|
-
*
|
|
1612
|
-
*/
|
|
1613
1377
|
wssSendSnackbarMessage(message, timeout = 5) {
|
|
1614
1378
|
this.log.debug('Sending a snackbar message to all connected clients');
|
|
1615
|
-
// Send the message to all connected clients
|
|
1616
1379
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1617
1380
|
if (client.readyState === WebSocket.OPEN) {
|
|
1618
1381
|
client.send(JSON.stringify({ id: WS_ID_SNACKBAR, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', params: { message, timeout } }));
|
|
1619
1382
|
}
|
|
1620
1383
|
});
|
|
1621
1384
|
}
|
|
1622
|
-
/**
|
|
1623
|
-
* Sends a message to all connected clients.
|
|
1624
|
-
*
|
|
1625
|
-
*/
|
|
1626
1385
|
wssBroadcastMessage(id, method, params) {
|
|
1627
1386
|
this.log.debug(`Sending a broadcast message id ${id} method ${method} params ${debugStringify(params ?? {})} to all connected clients`);
|
|
1628
|
-
// Send the message to all connected clients
|
|
1629
1387
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1630
1388
|
if (client.readyState === WebSocket.OPEN) {
|
|
1631
1389
|
client.send(JSON.stringify({ id, src: 'Matterbridge', dst: 'Frontend', method, params }));
|
|
@@ -1633,4 +1391,3 @@ export class Frontend {
|
|
|
1633
1391
|
});
|
|
1634
1392
|
}
|
|
1635
1393
|
}
|
|
1636
|
-
//# sourceMappingURL=frontend.js.map
|