matterbridge 2.2.3 → 2.2.4-dev.2
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 +15 -0
- 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 +33 -306
- package/dist/index.js +1 -28
- 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 +0 -2
- package/dist/matterbridge.js +65 -725
- 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 -185
- package/dist/matterbridgeTypes.js +0 -24
- package/dist/pluginManager.js +3 -229
- package/dist/shelly.js +6 -121
- 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/frontend/build/asset-manifest.json +3 -3
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/js/{main.6ffd2c31.js → main.819c0908.js} +4 -4
- package/frontend/build/static/js/{main.6ffd2c31.js.map → main.819c0908.js.map} +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -2
- package/dist/cli.d.ts +0 -29
- 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 -114
- package/dist/deviceManager.d.ts.map +0 -1
- package/dist/deviceManager.js.map +0 -1
- package/dist/frontend.d.ts +0 -201
- package/dist/frontend.d.ts.map +0 -1
- package/dist/frontend.js.map +0 -1
- package/dist/index.d.ts +0 -35
- 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/behaviors.d.ts +0 -2
- package/dist/matter/behaviors.d.ts.map +0 -1
- package/dist/matter/behaviors.js.map +0 -1
- package/dist/matter/clusters.d.ts +0 -2
- package/dist/matter/clusters.d.ts.map +0 -1
- package/dist/matter/clusters.js.map +0 -1
- package/dist/matter/devices.d.ts +0 -2
- package/dist/matter/devices.d.ts.map +0 -1
- package/dist/matter/devices.js.map +0 -1
- package/dist/matter/endpoints.d.ts +0 -2
- package/dist/matter/endpoints.d.ts.map +0 -1
- package/dist/matter/endpoints.js.map +0 -1
- package/dist/matter/export.d.ts +0 -5
- package/dist/matter/export.d.ts.map +0 -1
- package/dist/matter/export.js.map +0 -1
- package/dist/matter/types.d.ts +0 -3
- package/dist/matter/types.d.ts.map +0 -1
- package/dist/matter/types.js.map +0 -1
- package/dist/matterbridge.d.ts +0 -412
- 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 -1056
- 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 -835
- package/dist/matterbridgeEndpoint.d.ts.map +0 -1
- package/dist/matterbridgeEndpoint.js.map +0 -1
- package/dist/matterbridgeEndpointHelpers.d.ts +0 -2275
- package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
- package/dist/matterbridgeEndpointHelpers.js.map +0 -1
- package/dist/matterbridgePlatform.d.ts +0 -251
- package/dist/matterbridgePlatform.d.ts.map +0 -1
- package/dist/matterbridgePlatform.js.map +0 -1
- package/dist/matterbridgeTypes.d.ts +0 -178
- 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 +0 -77
- package/dist/shelly.d.ts.map +0 -1
- package/dist/shelly.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/update.d.ts +0 -32
- package/dist/update.d.ts.map +0 -1
- package/dist/update.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/copyDirectory.d.ts +0 -32
- package/dist/utils/copyDirectory.d.ts.map +0 -1
- package/dist/utils/copyDirectory.js.map +0 -1
- package/dist/utils/createZip.d.ts +0 -38
- package/dist/utils/createZip.d.ts.map +0 -1
- package/dist/utils/createZip.js.map +0 -1
- package/dist/utils/deepCopy.d.ts +0 -31
- package/dist/utils/deepCopy.d.ts.map +0 -1
- package/dist/utils/deepCopy.js.map +0 -1
- package/dist/utils/deepEqual.d.ts +0 -53
- package/dist/utils/deepEqual.d.ts.map +0 -1
- package/dist/utils/deepEqual.js.map +0 -1
- package/dist/utils/export.d.ts +0 -10
- package/dist/utils/export.d.ts.map +0 -1
- package/dist/utils/export.js.map +0 -1
- package/dist/utils/isvalid.d.ts +0 -87
- package/dist/utils/isvalid.d.ts.map +0 -1
- package/dist/utils/isvalid.js.map +0 -1
- package/dist/utils/network.d.ts +0 -70
- package/dist/utils/network.d.ts.map +0 -1
- package/dist/utils/network.js.map +0 -1
- package/dist/utils/parameter.d.ts +0 -44
- 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/frontend/build/static/js/{main.6ffd2c31.js.LICENSE.txt → main.819c0908.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.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, Lifecycle } from '@matter/main';
|
|
25
|
-
// Node modules
|
|
26
2
|
import { createServer } from 'node:http';
|
|
27
3
|
import os from 'node:os';
|
|
28
4
|
import path from 'node:path';
|
|
@@ -31,70 +7,21 @@ import https from 'https';
|
|
|
31
7
|
import express from 'express';
|
|
32
8
|
import WebSocket, { WebSocketServer } from 'ws';
|
|
33
9
|
import multer from 'multer';
|
|
34
|
-
// AnsiLogger module
|
|
35
10
|
import { AnsiLogger, stringify, debugStringify, CYAN, db, er, nf, rs, UNDERLINE, UNDERLINEOFF, wr, YELLOW } from './logger/export.js';
|
|
36
|
-
// Matterbridge
|
|
37
11
|
import { createZip, deepCopy, isValidArray, isValidNumber, isValidObject, isValidString } from './utils/export.js';
|
|
38
12
|
import { plg } from './matterbridgeTypes.js';
|
|
39
13
|
import { hasParameter } from './utils/export.js';
|
|
40
14
|
import { BridgedDeviceBasicInformation } from '@matter/main/clusters';
|
|
41
|
-
/**
|
|
42
|
-
* Websocket message ID for logging.
|
|
43
|
-
* @constant {number}
|
|
44
|
-
*/
|
|
45
15
|
export const WS_ID_LOG = 0;
|
|
46
|
-
/**
|
|
47
|
-
* Websocket message ID indicating a refresh is needed.
|
|
48
|
-
* @constant {number}
|
|
49
|
-
*/
|
|
50
16
|
export const WS_ID_REFRESH_NEEDED = 1;
|
|
51
|
-
/**
|
|
52
|
-
* Websocket message ID indicating a restart is needed.
|
|
53
|
-
* @constant {number}
|
|
54
|
-
*/
|
|
55
17
|
export const WS_ID_RESTART_NEEDED = 2;
|
|
56
|
-
/**
|
|
57
|
-
* Websocket message ID indicating a cpu update.
|
|
58
|
-
* @constant {number}
|
|
59
|
-
*/
|
|
60
18
|
export const WS_ID_CPU_UPDATE = 3;
|
|
61
|
-
/**
|
|
62
|
-
* Websocket message ID indicating a memory update.
|
|
63
|
-
* @constant {number}
|
|
64
|
-
*/
|
|
65
19
|
export const WS_ID_MEMORY_UPDATE = 4;
|
|
66
|
-
/**
|
|
67
|
-
* Websocket message ID indicating an uptime update.
|
|
68
|
-
* @constant {number}
|
|
69
|
-
*/
|
|
70
20
|
export const WS_ID_UPTIME_UPDATE = 5;
|
|
71
|
-
/**
|
|
72
|
-
* Websocket message ID indicating a memory update.
|
|
73
|
-
* @constant {number}
|
|
74
|
-
*/
|
|
75
21
|
export const WS_ID_SNACKBAR = 6;
|
|
76
|
-
/**
|
|
77
|
-
* Websocket message ID indicating a memory update.
|
|
78
|
-
* @constant {number}
|
|
79
|
-
*/
|
|
80
22
|
export const WS_ID_UPDATE_NEEDED = 7;
|
|
81
|
-
|
|
82
|
-
* Websocket message ID indicating a shelly system update.
|
|
83
|
-
* check:
|
|
84
|
-
* curl -k http://127.0.0.1:8101/api/updates/sys/check
|
|
85
|
-
* perform:
|
|
86
|
-
* curl -k http://127.0.0.1:8101/api/updates/sys/perform
|
|
87
|
-
* @constant {number}
|
|
88
|
-
*/
|
|
23
|
+
export const WS_ID_STATEUPDATE = 8;
|
|
89
24
|
export const WS_ID_SHELLY_SYS_UPDATE = 100;
|
|
90
|
-
/**
|
|
91
|
-
* Websocket message ID indicating a shelly main update.
|
|
92
|
-
* check:
|
|
93
|
-
* curl -k http://127.0.0.1:8101/api/updates/main/check
|
|
94
|
-
* perform:
|
|
95
|
-
* curl -k http://127.0.0.1:8101/api/updates/main/perform
|
|
96
|
-
* @constant {number}
|
|
97
|
-
*/
|
|
98
25
|
export const WS_ID_SHELLY_MAIN_UPDATE = 101;
|
|
99
26
|
export class Frontend {
|
|
100
27
|
matterbridge;
|
|
@@ -112,7 +39,7 @@ export class Frontend {
|
|
|
112
39
|
memoryTimeout;
|
|
113
40
|
constructor(matterbridge) {
|
|
114
41
|
this.matterbridge = matterbridge;
|
|
115
|
-
this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4
|
|
42
|
+
this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
|
|
116
43
|
}
|
|
117
44
|
set logLevel(logLevel) {
|
|
118
45
|
this.log.logLevel = logLevel;
|
|
@@ -120,25 +47,13 @@ export class Frontend {
|
|
|
120
47
|
async start(port = 8283) {
|
|
121
48
|
this.port = port;
|
|
122
49
|
this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${this.port}${db}`);
|
|
123
|
-
// Initialize multer with the upload directory
|
|
124
50
|
const uploadDir = path.join(this.matterbridge.matterbridgeDirectory, 'uploads');
|
|
125
51
|
await fs.mkdir(uploadDir, { recursive: true });
|
|
126
52
|
const upload = multer({ dest: uploadDir });
|
|
127
|
-
// Create the express app that serves the frontend
|
|
128
53
|
this.expressApp = express();
|
|
129
|
-
// Log all requests to the server for debugging
|
|
130
|
-
/*
|
|
131
|
-
this.expressApp.use((req, res, next) => {
|
|
132
|
-
this.log.debug(`Received request on expressApp: ${req.method} ${req.url}`);
|
|
133
|
-
next();
|
|
134
|
-
});
|
|
135
|
-
*/
|
|
136
|
-
// Serve static files from '/static' endpoint
|
|
137
54
|
this.expressApp.use(express.static(path.join(this.matterbridge.rootDirectory, 'frontend/build')));
|
|
138
55
|
if (!hasParameter('ssl')) {
|
|
139
|
-
// Create an HTTP server and attach the express app
|
|
140
56
|
this.httpServer = createServer(this.expressApp);
|
|
141
|
-
// Listen on the specified port
|
|
142
57
|
if (hasParameter('ingress')) {
|
|
143
58
|
this.httpServer.listen(this.port, '0.0.0.0', () => {
|
|
144
59
|
this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
|
|
@@ -152,7 +67,6 @@ export class Frontend {
|
|
|
152
67
|
this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
|
|
153
68
|
});
|
|
154
69
|
}
|
|
155
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
156
70
|
this.httpServer.on('error', (error) => {
|
|
157
71
|
this.log.error(`Frontend http server error listening on ${this.port}`);
|
|
158
72
|
switch (error.code) {
|
|
@@ -168,7 +82,6 @@ export class Frontend {
|
|
|
168
82
|
});
|
|
169
83
|
}
|
|
170
84
|
else {
|
|
171
|
-
// Load the SSL certificate, the private key and optionally the CA certificate
|
|
172
85
|
let cert;
|
|
173
86
|
try {
|
|
174
87
|
cert = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
|
|
@@ -196,9 +109,7 @@ export class Frontend {
|
|
|
196
109
|
this.log.info(`CA certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
|
|
197
110
|
}
|
|
198
111
|
const serverOptions = { cert, key, ca };
|
|
199
|
-
// Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
|
|
200
112
|
this.httpsServer = https.createServer(serverOptions, this.expressApp);
|
|
201
|
-
// Listen on the specified port
|
|
202
113
|
if (hasParameter('ingress')) {
|
|
203
114
|
this.httpsServer.listen(this.port, '0.0.0.0', () => {
|
|
204
115
|
this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
|
|
@@ -212,7 +123,6 @@ export class Frontend {
|
|
|
212
123
|
this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
|
|
213
124
|
});
|
|
214
125
|
}
|
|
215
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
216
126
|
this.httpsServer.on('error', (error) => {
|
|
217
127
|
this.log.error(`Frontend https server error listening on ${this.port}`);
|
|
218
128
|
switch (error.code) {
|
|
@@ -229,18 +139,16 @@ export class Frontend {
|
|
|
229
139
|
}
|
|
230
140
|
if (this.initializeError)
|
|
231
141
|
return;
|
|
232
|
-
// Create a WebSocket server and attach it to the http or https server
|
|
233
142
|
const wssPort = this.port;
|
|
234
143
|
const wssHost = hasParameter('ssl') ? `wss://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}`;
|
|
235
144
|
this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
|
|
236
145
|
this.webSocketServer.on('connection', (ws, request) => {
|
|
237
146
|
const clientIp = request.socket.remoteAddress;
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
callbackLogLevel = "debug" /* LogLevel.DEBUG */;
|
|
147
|
+
let callbackLogLevel = "notice";
|
|
148
|
+
if (this.matterbridge.matterbridgeInformation.loggerLevel === "info" || this.matterbridge.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.INFO)
|
|
149
|
+
callbackLogLevel = "info";
|
|
150
|
+
if (this.matterbridge.matterbridgeInformation.loggerLevel === "debug" || this.matterbridge.matterbridgeInformation.matterLoggerLevel === MatterLogLevel.DEBUG)
|
|
151
|
+
callbackLogLevel = "debug";
|
|
244
152
|
AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), callbackLogLevel);
|
|
245
153
|
this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
|
|
246
154
|
this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
|
|
@@ -274,8 +182,8 @@ export class Frontend {
|
|
|
274
182
|
this.webSocketServer.on('error', (ws, error) => {
|
|
275
183
|
this.log.error(`WebSocketServer error: ${error}`);
|
|
276
184
|
});
|
|
277
|
-
// Subscribe to cli events
|
|
278
185
|
const { cliEmitter } = await import('./cli.js');
|
|
186
|
+
cliEmitter.removeAllListeners();
|
|
279
187
|
cliEmitter.on('uptime', (systemUptime, processUptime) => {
|
|
280
188
|
this.wssSendUptimeUpdate(systemUptime, processUptime);
|
|
281
189
|
});
|
|
@@ -285,7 +193,6 @@ export class Frontend {
|
|
|
285
193
|
cliEmitter.on('cpu', (cpuUsage) => {
|
|
286
194
|
this.wssSendCpuUpdate(cpuUsage);
|
|
287
195
|
});
|
|
288
|
-
// Endpoint to validate login code
|
|
289
196
|
this.expressApp.post('/api/login', express.json(), async (req, res) => {
|
|
290
197
|
const { password } = req.body;
|
|
291
198
|
this.log.debug('The frontend sent /api/login', password);
|
|
@@ -304,27 +211,23 @@ export class Frontend {
|
|
|
304
211
|
this.log.warn('/api/login error wrong password');
|
|
305
212
|
res.json({ valid: false });
|
|
306
213
|
}
|
|
307
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
308
214
|
}
|
|
309
215
|
catch (error) {
|
|
310
216
|
this.log.error('/api/login error getting password');
|
|
311
217
|
res.json({ valid: false });
|
|
312
218
|
}
|
|
313
219
|
});
|
|
314
|
-
// Endpoint to provide health check
|
|
315
220
|
this.expressApp.get('/health', (req, res) => {
|
|
316
221
|
this.log.debug('Express received /health');
|
|
317
222
|
const healthStatus = {
|
|
318
|
-
status: 'ok',
|
|
319
|
-
uptime: process.uptime(),
|
|
320
|
-
timestamp: new Date().toISOString(),
|
|
223
|
+
status: 'ok',
|
|
224
|
+
uptime: process.uptime(),
|
|
225
|
+
timestamp: new Date().toISOString(),
|
|
321
226
|
};
|
|
322
227
|
res.status(200).json(healthStatus);
|
|
323
228
|
});
|
|
324
|
-
// Endpoint to provide memory usage details
|
|
325
229
|
this.expressApp.get('/memory', async (req, res) => {
|
|
326
230
|
this.log.debug('Express received /memory');
|
|
327
|
-
// Memory usage from process
|
|
328
231
|
const memoryUsageRaw = process.memoryUsage();
|
|
329
232
|
const memoryUsage = {
|
|
330
233
|
rss: this.formatMemoryUsage(memoryUsageRaw.rss),
|
|
@@ -333,13 +236,10 @@ export class Frontend {
|
|
|
333
236
|
external: this.formatMemoryUsage(memoryUsageRaw.external),
|
|
334
237
|
arrayBuffers: this.formatMemoryUsage(memoryUsageRaw.arrayBuffers),
|
|
335
238
|
};
|
|
336
|
-
// V8 heap statistics
|
|
337
239
|
const { default: v8 } = await import('node:v8');
|
|
338
240
|
const heapStatsRaw = v8.getHeapStatistics();
|
|
339
241
|
const heapSpacesRaw = v8.getHeapSpaceStatistics();
|
|
340
|
-
// Format heapStats
|
|
341
242
|
const heapStats = Object.fromEntries(Object.entries(heapStatsRaw).map(([key, value]) => [key, this.formatMemoryUsage(value)]));
|
|
342
|
-
// Format heapSpaces
|
|
343
243
|
const heapSpaces = heapSpacesRaw.map((space) => ({
|
|
344
244
|
...space,
|
|
345
245
|
space_size: this.formatMemoryUsage(space.space_size),
|
|
@@ -357,7 +257,6 @@ export class Frontend {
|
|
|
357
257
|
};
|
|
358
258
|
res.status(200).json(memoryReport);
|
|
359
259
|
});
|
|
360
|
-
// Endpoint to start advertising the server node
|
|
361
260
|
this.expressApp.get('/api/advertise', express.json(), async (req, res) => {
|
|
362
261
|
const pairingCodes = await this.matterbridge.advertiseServerNode(this.matterbridge.serverNode);
|
|
363
262
|
if (pairingCodes) {
|
|
@@ -368,22 +267,18 @@ export class Frontend {
|
|
|
368
267
|
res.status(500).json({ error: 'Failed to generate pairing codes' });
|
|
369
268
|
}
|
|
370
269
|
});
|
|
371
|
-
// Endpoint to provide settings
|
|
372
270
|
this.expressApp.get('/api/settings', express.json(), async (req, res) => {
|
|
373
271
|
this.log.debug('The frontend sent /api/settings');
|
|
374
272
|
res.json(await this.getApiSettings());
|
|
375
273
|
});
|
|
376
|
-
// Endpoint to provide plugins
|
|
377
274
|
this.expressApp.get('/api/plugins', async (req, res) => {
|
|
378
275
|
this.log.debug('The frontend sent /api/plugins');
|
|
379
276
|
res.json(this.getBaseRegisteredPlugins());
|
|
380
277
|
});
|
|
381
|
-
// Endpoint to provide devices
|
|
382
278
|
this.expressApp.get('/api/devices', (req, res) => {
|
|
383
279
|
this.log.debug('The frontend sent /api/devices');
|
|
384
280
|
const devices = [];
|
|
385
281
|
this.matterbridge.devices.forEach(async (device) => {
|
|
386
|
-
// Check if the device has the required properties
|
|
387
282
|
if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
|
|
388
283
|
return;
|
|
389
284
|
const cluster = this.getClusterTextFromDevice(device);
|
|
@@ -402,7 +297,6 @@ export class Frontend {
|
|
|
402
297
|
});
|
|
403
298
|
res.json(devices);
|
|
404
299
|
});
|
|
405
|
-
// Endpoint to provide the cluster servers of the devices
|
|
406
300
|
this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
|
|
407
301
|
const selectedPluginName = req.params.selectedPluginName;
|
|
408
302
|
const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
|
|
@@ -475,7 +369,6 @@ export class Frontend {
|
|
|
475
369
|
});
|
|
476
370
|
res.json(data);
|
|
477
371
|
});
|
|
478
|
-
// Endpoint to view the log
|
|
479
372
|
this.expressApp.get('/api/view-log', async (req, res) => {
|
|
480
373
|
this.log.debug('The frontend sent /api/log');
|
|
481
374
|
try {
|
|
@@ -488,12 +381,10 @@ export class Frontend {
|
|
|
488
381
|
res.status(500).send('Error reading log file');
|
|
489
382
|
}
|
|
490
383
|
});
|
|
491
|
-
// Endpoint to download the matterbridge log
|
|
492
384
|
this.expressApp.get('/api/download-mblog', async (req, res) => {
|
|
493
385
|
this.log.debug('The frontend sent /api/download-mblog');
|
|
494
386
|
try {
|
|
495
387
|
await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), fs.constants.F_OK);
|
|
496
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
497
388
|
}
|
|
498
389
|
catch (error) {
|
|
499
390
|
fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
|
|
@@ -505,12 +396,10 @@ export class Frontend {
|
|
|
505
396
|
}
|
|
506
397
|
});
|
|
507
398
|
});
|
|
508
|
-
// Endpoint to download the matter log
|
|
509
399
|
this.expressApp.get('/api/download-mjlog', async (req, res) => {
|
|
510
400
|
this.log.debug('The frontend sent /api/download-mjlog');
|
|
511
401
|
try {
|
|
512
402
|
await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), fs.constants.F_OK);
|
|
513
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
514
403
|
}
|
|
515
404
|
catch (error) {
|
|
516
405
|
fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
|
|
@@ -522,12 +411,10 @@ export class Frontend {
|
|
|
522
411
|
}
|
|
523
412
|
});
|
|
524
413
|
});
|
|
525
|
-
// Endpoint to download the matter log
|
|
526
414
|
this.expressApp.get('/api/shellydownloadsystemlog', async (req, res) => {
|
|
527
415
|
this.log.debug('The frontend sent /api/shellydownloadsystemlog');
|
|
528
416
|
try {
|
|
529
417
|
await fs.access(path.join(this.matterbridge.matterbridgeDirectory, 'shelly.log'), fs.constants.F_OK);
|
|
530
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
531
418
|
}
|
|
532
419
|
catch (error) {
|
|
533
420
|
fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, 'shelly.log'), 'Create the Shelly system log before downloading it.');
|
|
@@ -539,7 +426,6 @@ export class Frontend {
|
|
|
539
426
|
}
|
|
540
427
|
});
|
|
541
428
|
});
|
|
542
|
-
// Endpoint to download the matter storage file
|
|
543
429
|
this.expressApp.get('/api/download-mjstorage', async (req, res) => {
|
|
544
430
|
this.log.debug('The frontend sent /api/download-mjstorage');
|
|
545
431
|
await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.matterStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterStorageName));
|
|
@@ -550,7 +436,6 @@ export class Frontend {
|
|
|
550
436
|
}
|
|
551
437
|
});
|
|
552
438
|
});
|
|
553
|
-
// Endpoint to download the matterbridge storage directory
|
|
554
439
|
this.expressApp.get('/api/download-mbstorage', async (req, res) => {
|
|
555
440
|
this.log.debug('The frontend sent /api/download-mbstorage');
|
|
556
441
|
await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.nodeStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.nodeStorageName));
|
|
@@ -561,7 +446,6 @@ export class Frontend {
|
|
|
561
446
|
}
|
|
562
447
|
});
|
|
563
448
|
});
|
|
564
|
-
// Endpoint to download the matterbridge plugin directory
|
|
565
449
|
this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
|
|
566
450
|
this.log.debug('The frontend sent /api/download-pluginstorage');
|
|
567
451
|
await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridge.matterbridgePluginDirectory);
|
|
@@ -572,11 +456,9 @@ export class Frontend {
|
|
|
572
456
|
}
|
|
573
457
|
});
|
|
574
458
|
});
|
|
575
|
-
// Endpoint to download the matterbridge plugin config files
|
|
576
459
|
this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
|
|
577
460
|
this.log.debug('The frontend sent /api/download-pluginconfig');
|
|
578
461
|
await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, '*.config.json')));
|
|
579
|
-
// 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')));
|
|
580
462
|
res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
|
|
581
463
|
if (error) {
|
|
582
464
|
this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
|
|
@@ -584,7 +466,6 @@ export class Frontend {
|
|
|
584
466
|
}
|
|
585
467
|
});
|
|
586
468
|
});
|
|
587
|
-
// Endpoint to download the matterbridge plugin config files
|
|
588
469
|
this.expressApp.get('/api/download-backup', async (req, res) => {
|
|
589
470
|
this.log.debug('The frontend sent /api/download-backup');
|
|
590
471
|
res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
|
|
@@ -594,7 +475,6 @@ export class Frontend {
|
|
|
594
475
|
}
|
|
595
476
|
});
|
|
596
477
|
});
|
|
597
|
-
// Endpoint to receive commands
|
|
598
478
|
this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
|
|
599
479
|
const command = req.params.command;
|
|
600
480
|
let param = req.params.param;
|
|
@@ -604,15 +484,13 @@ export class Frontend {
|
|
|
604
484
|
return;
|
|
605
485
|
}
|
|
606
486
|
this.log.debug(`Received frontend command: ${command}:${param}`);
|
|
607
|
-
// Handle the command setpassword from Settings
|
|
608
487
|
if (command === 'setpassword') {
|
|
609
|
-
const password = param.slice(1, -1);
|
|
488
|
+
const password = param.slice(1, -1);
|
|
610
489
|
this.log.debug('setpassword', param, password);
|
|
611
490
|
await this.matterbridge.nodeContext?.set('password', password);
|
|
612
491
|
res.json({ message: 'Command received' });
|
|
613
492
|
return;
|
|
614
493
|
}
|
|
615
|
-
// Handle the command setbridgemode from Settings
|
|
616
494
|
if (command === 'setbridgemode') {
|
|
617
495
|
this.log.debug(`setbridgemode: ${param}`);
|
|
618
496
|
this.wssSendRestartRequired();
|
|
@@ -620,7 +498,6 @@ export class Frontend {
|
|
|
620
498
|
res.json({ message: 'Command received' });
|
|
621
499
|
return;
|
|
622
500
|
}
|
|
623
|
-
// Handle the command backup from Settings
|
|
624
501
|
if (command === 'backup') {
|
|
625
502
|
this.log.notice(`Prepairing the backup...`);
|
|
626
503
|
await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridge.matterbridgeDirectory), path.join(this.matterbridge.matterbridgePluginDirectory));
|
|
@@ -629,33 +506,31 @@ export class Frontend {
|
|
|
629
506
|
res.json({ message: 'Command received' });
|
|
630
507
|
return;
|
|
631
508
|
}
|
|
632
|
-
// Handle the command setmbloglevel from Settings
|
|
633
509
|
if (command === 'setmbloglevel') {
|
|
634
510
|
this.log.debug('Matterbridge log level:', param);
|
|
635
511
|
if (param === 'Debug') {
|
|
636
|
-
this.log.logLevel = "debug"
|
|
512
|
+
this.log.logLevel = "debug";
|
|
637
513
|
}
|
|
638
514
|
else if (param === 'Info') {
|
|
639
|
-
this.log.logLevel = "info"
|
|
515
|
+
this.log.logLevel = "info";
|
|
640
516
|
}
|
|
641
517
|
else if (param === 'Notice') {
|
|
642
|
-
this.log.logLevel = "notice"
|
|
518
|
+
this.log.logLevel = "notice";
|
|
643
519
|
}
|
|
644
520
|
else if (param === 'Warn') {
|
|
645
|
-
this.log.logLevel = "warn"
|
|
521
|
+
this.log.logLevel = "warn";
|
|
646
522
|
}
|
|
647
523
|
else if (param === 'Error') {
|
|
648
|
-
this.log.logLevel = "error"
|
|
524
|
+
this.log.logLevel = "error";
|
|
649
525
|
}
|
|
650
526
|
else if (param === 'Fatal') {
|
|
651
|
-
this.log.logLevel = "fatal"
|
|
527
|
+
this.log.logLevel = "fatal";
|
|
652
528
|
}
|
|
653
529
|
await this.matterbridge.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
|
|
654
530
|
await this.matterbridge.setLogLevel(this.log.logLevel);
|
|
655
531
|
res.json({ message: 'Command received' });
|
|
656
532
|
return;
|
|
657
533
|
}
|
|
658
|
-
// Handle the command setmbloglevel from Settings
|
|
659
534
|
if (command === 'setmjloglevel') {
|
|
660
535
|
this.log.debug('Matter.js log level:', param);
|
|
661
536
|
if (param === 'Debug') {
|
|
@@ -680,34 +555,30 @@ export class Frontend {
|
|
|
680
555
|
res.json({ message: 'Command received' });
|
|
681
556
|
return;
|
|
682
557
|
}
|
|
683
|
-
// Handle the command setmdnsinterface from Settings
|
|
684
558
|
if (command === 'setmdnsinterface') {
|
|
685
|
-
param = param.slice(1, -1);
|
|
559
|
+
param = param.slice(1, -1);
|
|
686
560
|
this.matterbridge.matterbridgeInformation.mattermdnsinterface = param;
|
|
687
561
|
this.log.debug('Matter.js mdns interface:', param === '' ? 'All interfaces' : param);
|
|
688
562
|
await this.matterbridge.nodeContext?.set('mattermdnsinterface', param);
|
|
689
563
|
res.json({ message: 'Command received' });
|
|
690
564
|
return;
|
|
691
565
|
}
|
|
692
|
-
// Handle the command setipv4address from Settings
|
|
693
566
|
if (command === 'setipv4address') {
|
|
694
|
-
param = param.slice(1, -1);
|
|
567
|
+
param = param.slice(1, -1);
|
|
695
568
|
this.matterbridge.matterbridgeInformation.matteripv4address = param;
|
|
696
569
|
this.log.debug('Matter.js ipv4 address:', param === '' ? 'All ipv4 addresses' : param);
|
|
697
570
|
await this.matterbridge.nodeContext?.set('matteripv4address', param);
|
|
698
571
|
res.json({ message: 'Command received' });
|
|
699
572
|
return;
|
|
700
573
|
}
|
|
701
|
-
// Handle the command setipv6address from Settings
|
|
702
574
|
if (command === 'setipv6address') {
|
|
703
|
-
param = param.slice(1, -1);
|
|
575
|
+
param = param.slice(1, -1);
|
|
704
576
|
this.matterbridge.matterbridgeInformation.matteripv6address = param;
|
|
705
577
|
this.log.debug('Matter.js ipv6 address:', param === '' ? 'All ipv6 addresses' : param);
|
|
706
578
|
await this.matterbridge.nodeContext?.set('matteripv6address', param);
|
|
707
579
|
res.json({ message: 'Command received' });
|
|
708
580
|
return;
|
|
709
581
|
}
|
|
710
|
-
// Handle the command setmatterport from Settings
|
|
711
582
|
if (command === 'setmatterport') {
|
|
712
583
|
const port = Math.min(Math.max(parseInt(param), 5540), 5560);
|
|
713
584
|
this.matterbridge.matterbridgeInformation.matterPort = port;
|
|
@@ -716,7 +587,6 @@ export class Frontend {
|
|
|
716
587
|
res.json({ message: 'Command received' });
|
|
717
588
|
return;
|
|
718
589
|
}
|
|
719
|
-
// Handle the command setmatterdiscriminator from Settings
|
|
720
590
|
if (command === 'setmatterdiscriminator') {
|
|
721
591
|
const discriminator = Math.min(Math.max(parseInt(param), 1000), 4095);
|
|
722
592
|
this.matterbridge.matterbridgeInformation.matterDiscriminator = discriminator;
|
|
@@ -725,7 +595,6 @@ export class Frontend {
|
|
|
725
595
|
res.json({ message: 'Command received' });
|
|
726
596
|
return;
|
|
727
597
|
}
|
|
728
|
-
// Handle the command setmatterpasscode from Settings
|
|
729
598
|
if (command === 'setmatterpasscode') {
|
|
730
599
|
const passcode = Math.min(Math.max(parseInt(param), 10000000), 90000000);
|
|
731
600
|
this.matterbridge.matterbridgeInformation.matterPasscode = passcode;
|
|
@@ -734,20 +603,17 @@ export class Frontend {
|
|
|
734
603
|
res.json({ message: 'Command received' });
|
|
735
604
|
return;
|
|
736
605
|
}
|
|
737
|
-
// Handle the command setmbloglevel from Settings
|
|
738
606
|
if (command === 'setmblogfile') {
|
|
739
607
|
this.log.debug('Matterbridge file log:', param);
|
|
740
608
|
this.matterbridge.matterbridgeInformation.fileLogger = param === 'true';
|
|
741
609
|
await this.matterbridge.nodeContext?.set('matterbridgeFileLog', param === 'true');
|
|
742
|
-
// Create the file logger for matterbridge
|
|
743
610
|
if (param === 'true')
|
|
744
|
-
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug"
|
|
611
|
+
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug", true);
|
|
745
612
|
else
|
|
746
613
|
AnsiLogger.setGlobalLogfile(undefined);
|
|
747
614
|
res.json({ message: 'Command received' });
|
|
748
615
|
return;
|
|
749
616
|
}
|
|
750
|
-
// Handle the command setmbloglevel from Settings
|
|
751
617
|
if (command === 'setmjlogfile') {
|
|
752
618
|
this.log.debug('Matter file log:', param);
|
|
753
619
|
this.matterbridge.matterbridgeInformation.matterFileLogger = param === 'true';
|
|
@@ -774,48 +640,40 @@ export class Frontend {
|
|
|
774
640
|
res.json({ message: 'Command received' });
|
|
775
641
|
return;
|
|
776
642
|
}
|
|
777
|
-
// Handle the command unregister from Settings
|
|
778
643
|
if (command === 'unregister') {
|
|
779
644
|
await this.matterbridge.unregisterAndShutdownProcess();
|
|
780
645
|
res.json({ message: 'Command received' });
|
|
781
646
|
return;
|
|
782
647
|
}
|
|
783
|
-
// Handle the command reset from Settings
|
|
784
648
|
if (command === 'reset') {
|
|
785
649
|
await this.matterbridge.shutdownProcessAndReset();
|
|
786
650
|
res.json({ message: 'Command received' });
|
|
787
651
|
return;
|
|
788
652
|
}
|
|
789
|
-
// Handle the command factoryreset from Settings
|
|
790
653
|
if (command === 'factoryreset') {
|
|
791
654
|
await this.matterbridge.shutdownProcessAndFactoryReset();
|
|
792
655
|
res.json({ message: 'Command received' });
|
|
793
656
|
return;
|
|
794
657
|
}
|
|
795
|
-
// Handle the command shutdown from Header
|
|
796
658
|
if (command === 'shutdown') {
|
|
797
659
|
await this.matterbridge.shutdownProcess();
|
|
798
660
|
res.json({ message: 'Command received' });
|
|
799
661
|
return;
|
|
800
662
|
}
|
|
801
|
-
// Handle the command restart from Header
|
|
802
663
|
if (command === 'restart') {
|
|
803
664
|
await this.matterbridge.restartProcess();
|
|
804
665
|
res.json({ message: 'Command received' });
|
|
805
666
|
return;
|
|
806
667
|
}
|
|
807
|
-
// Handle the command update from Header
|
|
808
668
|
if (command === 'update') {
|
|
809
669
|
await this.matterbridge.updateProcess();
|
|
810
670
|
this.wssSendRestartRequired();
|
|
811
671
|
res.json({ message: 'Command received' });
|
|
812
672
|
return;
|
|
813
673
|
}
|
|
814
|
-
// Handle the command saveconfig from Home
|
|
815
674
|
if (command === 'saveconfig') {
|
|
816
675
|
param = param.replace(/\*/g, '\\');
|
|
817
676
|
this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
|
|
818
|
-
// console.log('Req.body:', JSON.stringify(req.body, null, 2));
|
|
819
677
|
if (!this.matterbridge.plugins.has(param)) {
|
|
820
678
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
821
679
|
}
|
|
@@ -830,7 +688,6 @@ export class Frontend {
|
|
|
830
688
|
res.json({ message: 'Command received' });
|
|
831
689
|
return;
|
|
832
690
|
}
|
|
833
|
-
// Handle the command installplugin from Home
|
|
834
691
|
if (command === 'installplugin') {
|
|
835
692
|
param = param.replace(/\*/g, '\\');
|
|
836
693
|
this.log.info(`Installing plugin ${plg}${param}${nf}...`);
|
|
@@ -839,7 +696,6 @@ export class Frontend {
|
|
|
839
696
|
await this.matterbridge.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
|
|
840
697
|
this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
|
|
841
698
|
this.wssSendSnackbarMessage(`Installed package ${param}`);
|
|
842
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
843
699
|
}
|
|
844
700
|
catch (error) {
|
|
845
701
|
this.log.error(`Error installing plugin ${plg}${param}${er}`);
|
|
@@ -847,22 +703,17 @@ export class Frontend {
|
|
|
847
703
|
}
|
|
848
704
|
this.wssSendRestartRequired();
|
|
849
705
|
param = param.split('@')[0];
|
|
850
|
-
// Also add the plugin to matterbridge so no return!
|
|
851
706
|
if (param === 'matterbridge') {
|
|
852
|
-
// 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
|
|
853
707
|
res.json({ message: 'Command received' });
|
|
854
708
|
return;
|
|
855
709
|
}
|
|
856
710
|
}
|
|
857
|
-
// Handle the command addplugin from Home
|
|
858
711
|
if (command === 'addplugin' || command === 'installplugin') {
|
|
859
712
|
param = param.replace(/\*/g, '\\');
|
|
860
713
|
const plugin = await this.matterbridge.plugins.add(param);
|
|
861
714
|
if (plugin) {
|
|
862
715
|
this.wssSendSnackbarMessage(`Added plugin ${param}`);
|
|
863
716
|
if (this.matterbridge.bridgeMode === 'childbridge') {
|
|
864
|
-
// 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
|
|
865
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
866
717
|
this.matterbridge.createDynamicPlugin(plugin, true);
|
|
867
718
|
}
|
|
868
719
|
this.matterbridge.plugins.load(plugin, true, 'The plugin has been added', true).then(() => {
|
|
@@ -872,14 +723,13 @@ export class Frontend {
|
|
|
872
723
|
res.json({ message: 'Command received' });
|
|
873
724
|
return;
|
|
874
725
|
}
|
|
875
|
-
// Handle the command removeplugin from Home
|
|
876
726
|
if (command === 'removeplugin') {
|
|
877
727
|
if (!this.matterbridge.plugins.has(param)) {
|
|
878
728
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
879
729
|
}
|
|
880
730
|
else {
|
|
881
731
|
const plugin = this.matterbridge.plugins.get(param);
|
|
882
|
-
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true);
|
|
732
|
+
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true);
|
|
883
733
|
await this.matterbridge.plugins.remove(param);
|
|
884
734
|
this.wssSendSnackbarMessage(`Removed plugin ${param}`);
|
|
885
735
|
this.wssSendRefreshRequired('plugins');
|
|
@@ -887,7 +737,6 @@ export class Frontend {
|
|
|
887
737
|
res.json({ message: 'Command received' });
|
|
888
738
|
return;
|
|
889
739
|
}
|
|
890
|
-
// Handle the command enableplugin from Home
|
|
891
740
|
if (command === 'enableplugin') {
|
|
892
741
|
if (!this.matterbridge.plugins.has(param)) {
|
|
893
742
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
@@ -906,7 +755,6 @@ export class Frontend {
|
|
|
906
755
|
await this.matterbridge.plugins.enable(param);
|
|
907
756
|
this.wssSendSnackbarMessage(`Enabled plugin ${param}`);
|
|
908
757
|
if (this.matterbridge.bridgeMode === 'childbridge' && plugin.type === 'DynamicPlatform') {
|
|
909
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
910
758
|
this.matterbridge.createDynamicPlugin(plugin, true);
|
|
911
759
|
}
|
|
912
760
|
this.matterbridge.plugins.load(plugin, true, 'The plugin has been enabled', true).then(() => {
|
|
@@ -917,7 +765,6 @@ export class Frontend {
|
|
|
917
765
|
res.json({ message: 'Command received' });
|
|
918
766
|
return;
|
|
919
767
|
}
|
|
920
|
-
// Handle the command disableplugin from Home
|
|
921
768
|
if (command === 'disableplugin') {
|
|
922
769
|
if (!this.matterbridge.plugins.has(param)) {
|
|
923
770
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
@@ -925,7 +772,7 @@ export class Frontend {
|
|
|
925
772
|
else {
|
|
926
773
|
const plugin = this.matterbridge.plugins.get(param);
|
|
927
774
|
if (plugin && plugin.enabled) {
|
|
928
|
-
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true);
|
|
775
|
+
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true);
|
|
929
776
|
await this.matterbridge.plugins.disable(param);
|
|
930
777
|
this.wssSendSnackbarMessage(`Disabled plugin ${param}`);
|
|
931
778
|
this.wssSendRefreshRequired('plugins');
|
|
@@ -943,13 +790,11 @@ export class Frontend {
|
|
|
943
790
|
res.status(400).send('Invalid request: file and filename are required');
|
|
944
791
|
return;
|
|
945
792
|
}
|
|
946
|
-
|
|
793
|
+
this.wssSendSnackbarMessage(`Installing package ${filename}...`);
|
|
947
794
|
const filePath = path.join(this.matterbridge.matterbridgeDirectory, 'uploads', filename);
|
|
948
795
|
try {
|
|
949
|
-
// Move the uploaded file to the specified path
|
|
950
796
|
await fs.rename(file.path, filePath);
|
|
951
797
|
this.log.info(`File ${plg}${filename}${nf} uploaded successfully`);
|
|
952
|
-
// Install the plugin package
|
|
953
798
|
if (filename.endsWith('.tgz')) {
|
|
954
799
|
await this.matterbridge.spawnCommand('npm', ['install', '-g', filePath, '--omit=dev', '--verbose']);
|
|
955
800
|
this.log.info(`Plugin package ${plg}${filename}${nf} installed successfully. Full restart required.`);
|
|
@@ -965,7 +810,6 @@ export class Frontend {
|
|
|
965
810
|
res.status(500).send(`Error uploading or installing plugin package ${filename}`);
|
|
966
811
|
}
|
|
967
812
|
});
|
|
968
|
-
// Fallback for routing (must be the last route)
|
|
969
813
|
this.expressApp.get('*', (req, res) => {
|
|
970
814
|
this.log.debug('The frontend sent:', req.url);
|
|
971
815
|
this.log.debug('Response send file:', path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
|
|
@@ -974,31 +818,24 @@ export class Frontend {
|
|
|
974
818
|
this.log.debug(`Frontend initialized on port ${YELLOW}${this.port}${db} static ${UNDERLINE}${path.join(this.matterbridge.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
|
|
975
819
|
}
|
|
976
820
|
async stop() {
|
|
977
|
-
// Remove all listeners from the cliEmitter
|
|
978
|
-
// cliEmitter.removeAllListeners();
|
|
979
|
-
// Close the http server
|
|
980
821
|
if (this.httpServer) {
|
|
981
822
|
this.httpServer.close();
|
|
982
823
|
this.httpServer.removeAllListeners();
|
|
983
824
|
this.httpServer = undefined;
|
|
984
825
|
this.log.debug('Frontend http server closed successfully');
|
|
985
826
|
}
|
|
986
|
-
// Close the https server
|
|
987
827
|
if (this.httpsServer) {
|
|
988
828
|
this.httpsServer.close();
|
|
989
829
|
this.httpsServer.removeAllListeners();
|
|
990
830
|
this.httpsServer = undefined;
|
|
991
831
|
this.log.debug('Frontend https server closed successfully');
|
|
992
832
|
}
|
|
993
|
-
// Remove listeners from the express app
|
|
994
833
|
if (this.expressApp) {
|
|
995
834
|
this.expressApp.removeAllListeners();
|
|
996
835
|
this.expressApp = undefined;
|
|
997
836
|
this.log.debug('Frontend app closed successfully');
|
|
998
837
|
}
|
|
999
|
-
// Close the WebSocket server
|
|
1000
838
|
if (this.webSocketServer) {
|
|
1001
|
-
// Close all active connections
|
|
1002
839
|
this.webSocketServer.clients.forEach((client) => {
|
|
1003
840
|
if (client.readyState === WebSocket.OPEN) {
|
|
1004
841
|
client.close();
|
|
@@ -1015,7 +852,6 @@ export class Frontend {
|
|
|
1015
852
|
this.webSocketServer = undefined;
|
|
1016
853
|
}
|
|
1017
854
|
}
|
|
1018
|
-
// Function to format bytes to KB, MB, or GB
|
|
1019
855
|
formatMemoryUsage = (bytes) => {
|
|
1020
856
|
if (bytes >= 1024 ** 3) {
|
|
1021
857
|
return `${(bytes / 1024 ** 3).toFixed(2)} GB`;
|
|
@@ -1027,7 +863,6 @@ export class Frontend {
|
|
|
1027
863
|
return `${(bytes / 1024).toFixed(2)} KB`;
|
|
1028
864
|
}
|
|
1029
865
|
};
|
|
1030
|
-
// Function to format system uptime with only the most significant unit
|
|
1031
866
|
formatOsUpTime = (seconds) => {
|
|
1032
867
|
if (seconds >= 86400) {
|
|
1033
868
|
const days = Math.floor(seconds / 86400);
|
|
@@ -1043,13 +878,8 @@ export class Frontend {
|
|
|
1043
878
|
}
|
|
1044
879
|
return `${seconds} second${seconds !== 1 ? 's' : ''}`;
|
|
1045
880
|
};
|
|
1046
|
-
/**
|
|
1047
|
-
* Retrieves the api settings data.
|
|
1048
|
-
* @returns {Promise<object>} A promise that resolve in the api settings object.
|
|
1049
|
-
*/
|
|
1050
881
|
async getApiSettings() {
|
|
1051
882
|
const { lastCpuUsage } = await import('./cli.js');
|
|
1052
|
-
// Update the system information
|
|
1053
883
|
this.matterbridge.systemInformation.totalMemory = this.formatMemoryUsage(os.totalmem());
|
|
1054
884
|
this.matterbridge.systemInformation.freeMemory = this.formatMemoryUsage(os.freemem());
|
|
1055
885
|
this.matterbridge.systemInformation.systemUptime = this.formatOsUpTime(os.uptime());
|
|
@@ -1058,7 +888,6 @@ export class Frontend {
|
|
|
1058
888
|
this.matterbridge.systemInformation.rss = this.formatMemoryUsage(process.memoryUsage().rss);
|
|
1059
889
|
this.matterbridge.systemInformation.heapTotal = this.formatMemoryUsage(process.memoryUsage().heapTotal);
|
|
1060
890
|
this.matterbridge.systemInformation.heapUsed = this.formatMemoryUsage(process.memoryUsage().heapUsed);
|
|
1061
|
-
// Update the matterbridge information
|
|
1062
891
|
this.matterbridge.matterbridgeInformation.bridgeMode = this.matterbridge.bridgeMode;
|
|
1063
892
|
this.matterbridge.matterbridgeInformation.restartMode = this.matterbridge.restartMode;
|
|
1064
893
|
this.matterbridge.matterbridgeInformation.loggerLevel = this.matterbridge.log.logLevel;
|
|
@@ -1077,11 +906,6 @@ export class Frontend {
|
|
|
1077
906
|
this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
|
|
1078
907
|
return { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: this.matterbridge.matterbridgeInformation };
|
|
1079
908
|
}
|
|
1080
|
-
/**
|
|
1081
|
-
* Retrieves the reachable attribute.
|
|
1082
|
-
* @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
|
|
1083
|
-
* @returns {boolean} The reachable attribute.
|
|
1084
|
-
*/
|
|
1085
909
|
getReachability(device) {
|
|
1086
910
|
if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
|
|
1087
911
|
return false;
|
|
@@ -1091,11 +915,6 @@ export class Frontend {
|
|
|
1091
915
|
return true;
|
|
1092
916
|
return false;
|
|
1093
917
|
}
|
|
1094
|
-
/**
|
|
1095
|
-
* Retrieves the cluster text description from a given device.
|
|
1096
|
-
* @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
|
|
1097
|
-
* @returns {string} The attributes description of the cluster servers in the device.
|
|
1098
|
-
*/
|
|
1099
918
|
getClusterTextFromDevice(device) {
|
|
1100
919
|
if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
|
|
1101
920
|
return '';
|
|
@@ -1136,7 +955,6 @@ export class Frontend {
|
|
|
1136
955
|
};
|
|
1137
956
|
let attributes = '';
|
|
1138
957
|
device.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
|
|
1139
|
-
// console.log(`${device.deviceName} => Cluster: ${clusterName}-${clusterId} Attribute: ${attributeName}-${attributeId} Value(${typeof attributeValue}): ${attributeValue}`);
|
|
1140
958
|
if (typeof attributeValue === 'undefined')
|
|
1141
959
|
return;
|
|
1142
960
|
if (clusterName === 'onOff' && attributeName === 'onOff')
|
|
@@ -1214,13 +1032,8 @@ export class Frontend {
|
|
|
1214
1032
|
if (clusterName === 'userLabel' && attributeName === 'labelList')
|
|
1215
1033
|
attributes += `${getUserLabel(device)} `;
|
|
1216
1034
|
});
|
|
1217
|
-
// console.log(`${device.deviceName}.forEachAttribute: ${attributes}`);
|
|
1218
1035
|
return attributes.trimStart().trimEnd();
|
|
1219
1036
|
}
|
|
1220
|
-
/**
|
|
1221
|
-
* Retrieves the base registered plugins sanitized for res.json().
|
|
1222
|
-
* @returns {BaseRegisteredPlugin[]} An array of BaseRegisteredPlugin.
|
|
1223
|
-
*/
|
|
1224
1037
|
getBaseRegisteredPlugins() {
|
|
1225
1038
|
const baseRegisteredPlugins = [];
|
|
1226
1039
|
for (const plugin of this.matterbridge.plugins) {
|
|
@@ -1253,13 +1066,6 @@ export class Frontend {
|
|
|
1253
1066
|
}
|
|
1254
1067
|
return baseRegisteredPlugins;
|
|
1255
1068
|
}
|
|
1256
|
-
/**
|
|
1257
|
-
* Handles incoming websocket messages for the Matterbridge frontend.
|
|
1258
|
-
*
|
|
1259
|
-
* @param {WebSocket} client - The websocket client that sent the message.
|
|
1260
|
-
* @param {WebSocket.RawData} message - The raw data of the message received from the client.
|
|
1261
|
-
* @returns {Promise<void>} A promise that resolves when the message has been handled.
|
|
1262
|
-
*/
|
|
1263
1069
|
async wsMessageHandler(client, message) {
|
|
1264
1070
|
let data;
|
|
1265
1071
|
try {
|
|
@@ -1405,10 +1211,8 @@ export class Frontend {
|
|
|
1405
1211
|
else if (data.method === '/api/devices') {
|
|
1406
1212
|
const devices = [];
|
|
1407
1213
|
this.matterbridge.devices.forEach(async (device) => {
|
|
1408
|
-
// Filter by pluginName if provided
|
|
1409
1214
|
if (data.params.pluginName && data.params.pluginName !== device.plugin)
|
|
1410
1215
|
return;
|
|
1411
|
-
// Check if the device has the required properties
|
|
1412
1216
|
if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
|
|
1413
1217
|
return;
|
|
1414
1218
|
const cluster = this.getClusterTextFromDevice(device);
|
|
@@ -1492,7 +1296,6 @@ export class Frontend {
|
|
|
1492
1296
|
});
|
|
1493
1297
|
endpointServer.getChildEndpoints().forEach((childEndpoint) => {
|
|
1494
1298
|
deviceTypes = [];
|
|
1495
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1496
1299
|
const name = childEndpoint.endpoint?.id;
|
|
1497
1300
|
const clusterServers = childEndpoint.getAllClusterServers();
|
|
1498
1301
|
clusterServers.forEach((clusterServer) => {
|
|
@@ -1546,7 +1349,6 @@ export class Frontend {
|
|
|
1546
1349
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Plugin not found in /api/select' }));
|
|
1547
1350
|
return;
|
|
1548
1351
|
}
|
|
1549
|
-
// const selectDeviceValues = plugin.platform?.selectDevice ? Array.from(plugin.platform.selectDevice.values()).sort((keyA, keyB) => keyA.name.localeCompare(keyB.name)) : [];
|
|
1550
1352
|
const selectDeviceValues = plugin.platform?.getSelectDevices().sort((keyA, keyB) => keyA.name.localeCompare(keyB.name));
|
|
1551
1353
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, plugin: data.params.plugin, response: selectDeviceValues }));
|
|
1552
1354
|
return;
|
|
@@ -1561,7 +1363,6 @@ export class Frontend {
|
|
|
1561
1363
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Plugin not found in /api/select/entities' }));
|
|
1562
1364
|
return;
|
|
1563
1365
|
}
|
|
1564
|
-
// const selectEntityValues = plugin.platform?.selectDevice ? Array.from(plugin.platform.selectEntity.values()).sort((keyA, keyB) => keyA.name.localeCompare(keyB.name)) : [];
|
|
1565
1366
|
const selectEntityValues = plugin.platform?.getSelectEntities().sort((keyA, keyB) => keyA.name.localeCompare(keyB.name));
|
|
1566
1367
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, plugin: data.params.plugin, response: selectEntityValues }));
|
|
1567
1368
|
return;
|
|
@@ -1582,13 +1383,11 @@ export class Frontend {
|
|
|
1582
1383
|
if (config.postfix) {
|
|
1583
1384
|
data.params.serial = data.params.serial.replace('-' + config.postfix, '');
|
|
1584
1385
|
}
|
|
1585
|
-
// Add the serial to the whiteList if the whiteList exists and the serial is not already in it
|
|
1586
1386
|
if (isValidArray(config.whiteList, 1)) {
|
|
1587
1387
|
if (!config.whiteList.includes(data.params.serial)) {
|
|
1588
1388
|
config.whiteList.push(data.params.serial);
|
|
1589
1389
|
}
|
|
1590
1390
|
}
|
|
1591
|
-
// Remove the serial from the blackList if the blackList exists and the serial is in it
|
|
1592
1391
|
if (isValidArray(config.blackList, 1)) {
|
|
1593
1392
|
if (config.blackList.includes(data.params.serial)) {
|
|
1594
1393
|
config.blackList = config.blackList.filter((serial) => serial !== data.params.serial);
|
|
@@ -1611,13 +1410,11 @@ export class Frontend {
|
|
|
1611
1410
|
if (config.postfix) {
|
|
1612
1411
|
data.params.serial = data.params.serial.replace('-' + config.postfix, '');
|
|
1613
1412
|
}
|
|
1614
|
-
// Remove the serial from the whiteList if the whiteList exists and the serial is in it
|
|
1615
1413
|
if (isValidArray(config.whiteList, 1)) {
|
|
1616
1414
|
if (config.whiteList.includes(data.params.serial)) {
|
|
1617
1415
|
config.whiteList = config.whiteList.filter((serial) => serial !== data.params.serial);
|
|
1618
1416
|
}
|
|
1619
1417
|
}
|
|
1620
|
-
// Add the serial to the blackList
|
|
1621
1418
|
if (isValidArray(config.blackList)) {
|
|
1622
1419
|
if (!config.blackList.includes(data.params.serial)) {
|
|
1623
1420
|
config.blackList.push(data.params.serial);
|
|
@@ -1641,171 +1438,102 @@ export class Frontend {
|
|
|
1641
1438
|
return;
|
|
1642
1439
|
}
|
|
1643
1440
|
}
|
|
1644
|
-
/**
|
|
1645
|
-
* Sends a WebSocket message to all connected clients. The function is called by AnsiLogger.setGlobalCallback.
|
|
1646
|
-
*
|
|
1647
|
-
* @param {string} level - The logger level of the message: debug info notice warn error fatal...
|
|
1648
|
-
* @param {string} time - The time string of the message
|
|
1649
|
-
* @param {string} name - The logger name of the message
|
|
1650
|
-
* @param {string} message - The content of the message.
|
|
1651
|
-
*/
|
|
1652
1441
|
wssSendMessage(level, time, name, message) {
|
|
1653
1442
|
if (!level || !time || !name || !message)
|
|
1654
1443
|
return;
|
|
1655
|
-
// Remove ANSI escape codes from the message
|
|
1656
|
-
// eslint-disable-next-line no-control-regex
|
|
1657
1444
|
message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
|
|
1658
|
-
// Remove leading asterisks from the message
|
|
1659
1445
|
message = message.replace(/^\*+/, '');
|
|
1660
|
-
// Replace all occurrences of \t and \n
|
|
1661
1446
|
message = message.replace(/[\t\n]/g, '');
|
|
1662
|
-
// Remove non-printable characters
|
|
1663
|
-
// eslint-disable-next-line no-control-regex
|
|
1664
1447
|
message = message.replace(/[\x00-\x1F\x7F]/g, '');
|
|
1665
|
-
// Replace all occurrences of \" with "
|
|
1666
1448
|
message = message.replace(/\\"/g, '"');
|
|
1667
|
-
// Define the maximum allowed length for continuous characters without a space
|
|
1668
1449
|
const maxContinuousLength = 100;
|
|
1669
1450
|
const keepStartLength = 20;
|
|
1670
1451
|
const keepEndLength = 20;
|
|
1671
|
-
// Split the message into words
|
|
1672
1452
|
message = message
|
|
1673
1453
|
.split(' ')
|
|
1674
1454
|
.map((word) => {
|
|
1675
|
-
// If the word length exceeds the max continuous length, insert spaces and truncate
|
|
1676
1455
|
if (word.length > maxContinuousLength) {
|
|
1677
1456
|
return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
|
|
1678
1457
|
}
|
|
1679
1458
|
return word;
|
|
1680
1459
|
})
|
|
1681
1460
|
.join(' ');
|
|
1682
|
-
// Send the message to all connected clients
|
|
1683
1461
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1684
1462
|
if (client.readyState === WebSocket.OPEN) {
|
|
1685
1463
|
client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
|
|
1686
1464
|
}
|
|
1687
1465
|
});
|
|
1688
1466
|
}
|
|
1689
|
-
/**
|
|
1690
|
-
* Sends a need to refresh WebSocket message to all connected clients.
|
|
1691
|
-
*
|
|
1692
|
-
* @param {string} changed - The changed value. If null, the whole page will be refreshed.
|
|
1693
|
-
* possible values:
|
|
1694
|
-
* - 'matterbridgeLatestVersion'
|
|
1695
|
-
* - 'matterbridgeAdvertise'
|
|
1696
|
-
* - 'online'
|
|
1697
|
-
* - 'offline'
|
|
1698
|
-
* - 'reachability'
|
|
1699
|
-
* - 'settings'
|
|
1700
|
-
* - 'plugins'
|
|
1701
|
-
* - 'devices'
|
|
1702
|
-
* - 'fabrics'
|
|
1703
|
-
* - 'sessions'
|
|
1704
|
-
*/
|
|
1705
1467
|
wssSendRefreshRequired(changed = null) {
|
|
1706
1468
|
this.log.debug('Sending a refresh required message to all connected clients');
|
|
1707
|
-
// Send the message to all connected clients
|
|
1708
1469
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1709
1470
|
if (client.readyState === WebSocket.OPEN) {
|
|
1710
1471
|
client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', params: { changed: changed } }));
|
|
1711
1472
|
}
|
|
1712
1473
|
});
|
|
1713
1474
|
}
|
|
1714
|
-
/**
|
|
1715
|
-
* Sends a need to restart WebSocket message to all connected clients.
|
|
1716
|
-
*
|
|
1717
|
-
*/
|
|
1718
1475
|
wssSendRestartRequired(snackbar = true) {
|
|
1719
1476
|
this.log.debug('Sending a restart required message to all connected clients');
|
|
1720
1477
|
this.matterbridge.matterbridgeInformation.restartRequired = true;
|
|
1721
1478
|
if (snackbar === true)
|
|
1722
1479
|
this.wssSendSnackbarMessage(`Restart required`, 0);
|
|
1723
|
-
// Send the message to all connected clients
|
|
1724
1480
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1725
1481
|
if (client.readyState === WebSocket.OPEN) {
|
|
1726
1482
|
client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', params: {} }));
|
|
1727
1483
|
}
|
|
1728
1484
|
});
|
|
1729
1485
|
}
|
|
1730
|
-
/**
|
|
1731
|
-
* Sends a need to update WebSocket message to all connected clients.
|
|
1732
|
-
*
|
|
1733
|
-
*/
|
|
1734
1486
|
wssSendUpdateRequired() {
|
|
1735
1487
|
this.log.debug('Sending an update required message to all connected clients');
|
|
1736
1488
|
this.matterbridge.matterbridgeInformation.updateRequired = true;
|
|
1737
|
-
// Send the message to all connected clients
|
|
1738
1489
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1739
1490
|
if (client.readyState === WebSocket.OPEN) {
|
|
1740
1491
|
client.send(JSON.stringify({ id: WS_ID_UPDATE_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'update_required', params: {} }));
|
|
1741
1492
|
}
|
|
1742
1493
|
});
|
|
1743
1494
|
}
|
|
1744
|
-
/**
|
|
1745
|
-
* Sends a memory update message to all connected clients.
|
|
1746
|
-
*
|
|
1747
|
-
*/
|
|
1748
1495
|
wssSendCpuUpdate(cpuUsage) {
|
|
1749
1496
|
this.log.debug('Sending a cpu update message to all connected clients');
|
|
1750
|
-
// Send the message to all connected clients
|
|
1751
1497
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1752
1498
|
if (client.readyState === WebSocket.OPEN) {
|
|
1753
1499
|
client.send(JSON.stringify({ id: WS_ID_CPU_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'cpu_update', params: { cpuUsage } }));
|
|
1754
1500
|
}
|
|
1755
1501
|
});
|
|
1756
1502
|
}
|
|
1757
|
-
/**
|
|
1758
|
-
* Sends a cpu update message to all connected clients.
|
|
1759
|
-
*
|
|
1760
|
-
*/
|
|
1761
1503
|
wssSendMemoryUpdate(totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers) {
|
|
1762
1504
|
this.log.debug('Sending a memory update message to all connected clients');
|
|
1763
|
-
// Send the message to all connected clients
|
|
1764
1505
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1765
1506
|
if (client.readyState === WebSocket.OPEN) {
|
|
1766
1507
|
client.send(JSON.stringify({ id: WS_ID_MEMORY_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', params: { totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers } }));
|
|
1767
1508
|
}
|
|
1768
1509
|
});
|
|
1769
1510
|
}
|
|
1770
|
-
/**
|
|
1771
|
-
* Sends a memory update message to all connected clients.
|
|
1772
|
-
*
|
|
1773
|
-
*/
|
|
1774
1511
|
wssSendUptimeUpdate(systemUptime, processUptime) {
|
|
1775
1512
|
this.log.debug('Sending a uptime update message to all connected clients');
|
|
1776
|
-
// Send the message to all connected clients
|
|
1777
1513
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1778
1514
|
if (client.readyState === WebSocket.OPEN) {
|
|
1779
1515
|
client.send(JSON.stringify({ id: WS_ID_UPTIME_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'uptime_update', params: { systemUptime, processUptime } }));
|
|
1780
1516
|
}
|
|
1781
1517
|
});
|
|
1782
1518
|
}
|
|
1783
|
-
/**
|
|
1784
|
-
* Sends a cpu update message to all connected clients.
|
|
1785
|
-
* @param {string} message - The message to send.
|
|
1786
|
-
* @param {number} timeout - The timeout in seconds for the snackbar message.
|
|
1787
|
-
* @param {'info' | 'warning' | 'error' | 'success'} severity - The severity of the snackbar message (default info).
|
|
1788
|
-
*
|
|
1789
|
-
*/
|
|
1790
1519
|
wssSendSnackbarMessage(message, timeout = 5, severity = 'info') {
|
|
1791
1520
|
this.log.debug('Sending a snackbar message to all connected clients');
|
|
1792
|
-
// Send the message to all connected clients
|
|
1793
1521
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1794
1522
|
if (client.readyState === WebSocket.OPEN) {
|
|
1795
1523
|
client.send(JSON.stringify({ id: WS_ID_SNACKBAR, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', params: { message, timeout, severity } }));
|
|
1796
1524
|
}
|
|
1797
1525
|
});
|
|
1798
1526
|
}
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1527
|
+
wssSendAttributeChangedMessage(plugin, serialNumber, uniqueId, cluster, attribute, value) {
|
|
1528
|
+
this.log.debug('Sending an attribute update message to all connected clients');
|
|
1529
|
+
this.webSocketServer?.clients.forEach((client) => {
|
|
1530
|
+
if (client.readyState === WebSocket.OPEN) {
|
|
1531
|
+
client.send(JSON.stringify({ id: WS_ID_STATEUPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'state_update', params: { plugin, serialNumber, uniqueId, cluster, attribute, value } }));
|
|
1532
|
+
}
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1806
1535
|
wssBroadcastMessage(id, method, params) {
|
|
1807
1536
|
this.log.debug(`Sending a broadcast message id ${id} method ${method} params ${debugStringify(params ?? {})} to all connected clients`);
|
|
1808
|
-
// Send the message to all connected clients
|
|
1809
1537
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1810
1538
|
if (client.readyState === WebSocket.OPEN) {
|
|
1811
1539
|
client.send(JSON.stringify({ id, src: 'Matterbridge', dst: 'Frontend', method, params }));
|
|
@@ -1813,4 +1541,3 @@ export class Frontend {
|
|
|
1813
1541
|
});
|
|
1814
1542
|
}
|
|
1815
1543
|
}
|
|
1816
|
-
//# sourceMappingURL=frontend.js.map
|