matterbridge 2.2.7 → 3.0.0-edge.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -0
- package/README-DEV.md +24 -12
- 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 +19 -325
- 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 +89 -760
- package/dist/matterbridgeAccessoryPlatform.js +0 -33
- package/dist/matterbridgeBehaviors.js +15 -41
- package/dist/matterbridgeDeviceTypes.js +151 -228
- package/dist/matterbridgeDynamicPlatform.js +0 -33
- package/dist/matterbridgeEndpoint.js +87 -732
- package/dist/matterbridgeEndpointHelpers.js +30 -136
- package/dist/matterbridgePlatform.js +7 -216
- package/dist/matterbridgeTypes.js +0 -24
- package/dist/pluginManager.js +36 -305
- package/dist/shelly.js +6 -146
- 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 -76
- package/dist/utils/parameter.js +0 -41
- package/dist/utils/wait.js +5 -48
- package/npm-shrinkwrap.json +44 -44
- package/package.json +2 -3
- 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 -221
- 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 -425
- 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 -852
- 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 -285
- package/dist/matterbridgePlatform.d.ts.map +0 -1
- package/dist/matterbridgePlatform.js.map +0 -1
- package/dist/matterbridgeTypes.d.ts +0 -183
- package/dist/matterbridgeTypes.d.ts.map +0 -1
- package/dist/matterbridgeTypes.js.map +0 -1
- package/dist/pluginManager.d.ts +0 -271
- package/dist/pluginManager.d.ts.map +0 -1
- package/dist/pluginManager.js.map +0 -1
- package/dist/shelly.d.ts +0 -92
- 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 -69
- 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/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,75 +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, nt } 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 snackbar message.
|
|
73
|
-
* @constant {number}
|
|
74
|
-
*/
|
|
75
21
|
export const WS_ID_SNACKBAR = 6;
|
|
76
|
-
/**
|
|
77
|
-
* Websocket message ID indicating matterbridge has un update available.
|
|
78
|
-
* @constant {number}
|
|
79
|
-
*/
|
|
80
22
|
export const WS_ID_UPDATE_NEEDED = 7;
|
|
81
|
-
/**
|
|
82
|
-
* Websocket message ID indicating a state update.
|
|
83
|
-
* @constant {number}
|
|
84
|
-
*/
|
|
85
23
|
export const WS_ID_STATEUPDATE = 8;
|
|
86
|
-
/**
|
|
87
|
-
* Websocket message ID indicating a shelly system update.
|
|
88
|
-
* check:
|
|
89
|
-
* curl -k http://127.0.0.1:8101/api/updates/sys/check
|
|
90
|
-
* perform:
|
|
91
|
-
* curl -k http://127.0.0.1:8101/api/updates/sys/perform
|
|
92
|
-
* @constant {number}
|
|
93
|
-
*/
|
|
94
24
|
export const WS_ID_SHELLY_SYS_UPDATE = 100;
|
|
95
|
-
/**
|
|
96
|
-
* Websocket message ID indicating a shelly main update.
|
|
97
|
-
* check:
|
|
98
|
-
* curl -k http://127.0.0.1:8101/api/updates/main/check
|
|
99
|
-
* perform:
|
|
100
|
-
* curl -k http://127.0.0.1:8101/api/updates/main/perform
|
|
101
|
-
* @constant {number}
|
|
102
|
-
*/
|
|
103
25
|
export const WS_ID_SHELLY_MAIN_UPDATE = 101;
|
|
104
26
|
export class Frontend {
|
|
105
27
|
matterbridge;
|
|
@@ -117,7 +39,7 @@ export class Frontend {
|
|
|
117
39
|
memoryTimeout;
|
|
118
40
|
constructor(matterbridge) {
|
|
119
41
|
this.matterbridge = matterbridge;
|
|
120
|
-
this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4
|
|
42
|
+
this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
|
|
121
43
|
}
|
|
122
44
|
set logLevel(logLevel) {
|
|
123
45
|
this.log.logLevel = logLevel;
|
|
@@ -125,25 +47,13 @@ export class Frontend {
|
|
|
125
47
|
async start(port = 8283) {
|
|
126
48
|
this.port = port;
|
|
127
49
|
this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${this.port}${db}`);
|
|
128
|
-
// Initialize multer with the upload directory
|
|
129
50
|
const uploadDir = path.join(this.matterbridge.matterbridgeDirectory, 'uploads');
|
|
130
51
|
await fs.mkdir(uploadDir, { recursive: true });
|
|
131
52
|
const upload = multer({ dest: uploadDir });
|
|
132
|
-
// Create the express app that serves the frontend
|
|
133
53
|
this.expressApp = express();
|
|
134
|
-
// Log all requests to the server for debugging
|
|
135
|
-
/*
|
|
136
|
-
this.expressApp.use((req, res, next) => {
|
|
137
|
-
this.log.debug(`Received request on expressApp: ${req.method} ${req.url}`);
|
|
138
|
-
next();
|
|
139
|
-
});
|
|
140
|
-
*/
|
|
141
|
-
// Serve static files from '/static' endpoint
|
|
142
54
|
this.expressApp.use(express.static(path.join(this.matterbridge.rootDirectory, 'frontend/build')));
|
|
143
55
|
if (!hasParameter('ssl')) {
|
|
144
|
-
// Create an HTTP server and attach the express app
|
|
145
56
|
this.httpServer = createServer(this.expressApp);
|
|
146
|
-
// Listen on the specified port
|
|
147
57
|
if (hasParameter('ingress')) {
|
|
148
58
|
this.httpServer.listen(this.port, '0.0.0.0', () => {
|
|
149
59
|
this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
|
|
@@ -157,7 +67,6 @@ export class Frontend {
|
|
|
157
67
|
this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
|
|
158
68
|
});
|
|
159
69
|
}
|
|
160
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
161
70
|
this.httpServer.on('error', (error) => {
|
|
162
71
|
this.log.error(`Frontend http server error listening on ${this.port}`);
|
|
163
72
|
switch (error.code) {
|
|
@@ -173,7 +82,6 @@ export class Frontend {
|
|
|
173
82
|
});
|
|
174
83
|
}
|
|
175
84
|
else {
|
|
176
|
-
// Load the SSL certificate, the private key and optionally the CA certificate
|
|
177
85
|
let cert;
|
|
178
86
|
try {
|
|
179
87
|
cert = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
|
|
@@ -201,9 +109,7 @@ export class Frontend {
|
|
|
201
109
|
this.log.info(`CA certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
|
|
202
110
|
}
|
|
203
111
|
const serverOptions = { cert, key, ca };
|
|
204
|
-
// Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
|
|
205
112
|
this.httpsServer = https.createServer(serverOptions, this.expressApp);
|
|
206
|
-
// Listen on the specified port
|
|
207
113
|
if (hasParameter('ingress')) {
|
|
208
114
|
this.httpsServer.listen(this.port, '0.0.0.0', () => {
|
|
209
115
|
this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
|
|
@@ -217,7 +123,6 @@ export class Frontend {
|
|
|
217
123
|
this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
|
|
218
124
|
});
|
|
219
125
|
}
|
|
220
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
221
126
|
this.httpsServer.on('error', (error) => {
|
|
222
127
|
this.log.error(`Frontend https server error listening on ${this.port}`);
|
|
223
128
|
switch (error.code) {
|
|
@@ -234,18 +139,16 @@ export class Frontend {
|
|
|
234
139
|
}
|
|
235
140
|
if (this.initializeError)
|
|
236
141
|
return;
|
|
237
|
-
// Create a WebSocket server and attach it to the http or https server
|
|
238
142
|
const wssPort = this.port;
|
|
239
143
|
const wssHost = hasParameter('ssl') ? `wss://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}`;
|
|
240
144
|
this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
|
|
241
145
|
this.webSocketServer.on('connection', (ws, request) => {
|
|
242
146
|
const clientIp = request.socket.remoteAddress;
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
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";
|
|
249
152
|
AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), callbackLogLevel);
|
|
250
153
|
this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
|
|
251
154
|
this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
|
|
@@ -279,7 +182,6 @@ export class Frontend {
|
|
|
279
182
|
this.webSocketServer.on('error', (ws, error) => {
|
|
280
183
|
this.log.error(`WebSocketServer error: ${error}`);
|
|
281
184
|
});
|
|
282
|
-
// Subscribe to cli events
|
|
283
185
|
const { cliEmitter } = await import('./cli.js');
|
|
284
186
|
cliEmitter.removeAllListeners();
|
|
285
187
|
cliEmitter.on('uptime', (systemUptime, processUptime) => {
|
|
@@ -291,7 +193,6 @@ export class Frontend {
|
|
|
291
193
|
cliEmitter.on('cpu', (cpuUsage) => {
|
|
292
194
|
this.wssSendCpuUpdate(cpuUsage);
|
|
293
195
|
});
|
|
294
|
-
// Endpoint to validate login code
|
|
295
196
|
this.expressApp.post('/api/login', express.json(), async (req, res) => {
|
|
296
197
|
const { password } = req.body;
|
|
297
198
|
this.log.debug('The frontend sent /api/login', password);
|
|
@@ -310,27 +211,23 @@ export class Frontend {
|
|
|
310
211
|
this.log.warn('/api/login error wrong password');
|
|
311
212
|
res.json({ valid: false });
|
|
312
213
|
}
|
|
313
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
314
214
|
}
|
|
315
215
|
catch (error) {
|
|
316
216
|
this.log.error('/api/login error getting password');
|
|
317
217
|
res.json({ valid: false });
|
|
318
218
|
}
|
|
319
219
|
});
|
|
320
|
-
// Endpoint to provide health check
|
|
321
220
|
this.expressApp.get('/health', (req, res) => {
|
|
322
221
|
this.log.debug('Express received /health');
|
|
323
222
|
const healthStatus = {
|
|
324
|
-
status: 'ok',
|
|
325
|
-
uptime: process.uptime(),
|
|
326
|
-
timestamp: new Date().toISOString(),
|
|
223
|
+
status: 'ok',
|
|
224
|
+
uptime: process.uptime(),
|
|
225
|
+
timestamp: new Date().toISOString(),
|
|
327
226
|
};
|
|
328
227
|
res.status(200).json(healthStatus);
|
|
329
228
|
});
|
|
330
|
-
// Endpoint to provide memory usage details
|
|
331
229
|
this.expressApp.get('/memory', async (req, res) => {
|
|
332
230
|
this.log.debug('Express received /memory');
|
|
333
|
-
// Memory usage from process
|
|
334
231
|
const memoryUsageRaw = process.memoryUsage();
|
|
335
232
|
const memoryUsage = {
|
|
336
233
|
rss: this.formatMemoryUsage(memoryUsageRaw.rss),
|
|
@@ -339,13 +236,10 @@ export class Frontend {
|
|
|
339
236
|
external: this.formatMemoryUsage(memoryUsageRaw.external),
|
|
340
237
|
arrayBuffers: this.formatMemoryUsage(memoryUsageRaw.arrayBuffers),
|
|
341
238
|
};
|
|
342
|
-
// V8 heap statistics
|
|
343
239
|
const { default: v8 } = await import('node:v8');
|
|
344
240
|
const heapStatsRaw = v8.getHeapStatistics();
|
|
345
241
|
const heapSpacesRaw = v8.getHeapSpaceStatistics();
|
|
346
|
-
// Format heapStats
|
|
347
242
|
const heapStats = Object.fromEntries(Object.entries(heapStatsRaw).map(([key, value]) => [key, this.formatMemoryUsage(value)]));
|
|
348
|
-
// Format heapSpaces
|
|
349
243
|
const heapSpaces = heapSpacesRaw.map((space) => ({
|
|
350
244
|
...space,
|
|
351
245
|
space_size: this.formatMemoryUsage(space.space_size),
|
|
@@ -363,7 +257,6 @@ export class Frontend {
|
|
|
363
257
|
};
|
|
364
258
|
res.status(200).json(memoryReport);
|
|
365
259
|
});
|
|
366
|
-
// Endpoint to start advertising the server node
|
|
367
260
|
this.expressApp.get('/api/advertise', express.json(), async (req, res) => {
|
|
368
261
|
const pairingCodes = await this.matterbridge.advertiseServerNode(this.matterbridge.serverNode);
|
|
369
262
|
if (pairingCodes) {
|
|
@@ -374,22 +267,18 @@ export class Frontend {
|
|
|
374
267
|
res.status(500).json({ error: 'Failed to generate pairing codes' });
|
|
375
268
|
}
|
|
376
269
|
});
|
|
377
|
-
// Endpoint to provide settings
|
|
378
270
|
this.expressApp.get('/api/settings', express.json(), async (req, res) => {
|
|
379
271
|
this.log.debug('The frontend sent /api/settings');
|
|
380
272
|
res.json(await this.getApiSettings());
|
|
381
273
|
});
|
|
382
|
-
// Endpoint to provide plugins
|
|
383
274
|
this.expressApp.get('/api/plugins', async (req, res) => {
|
|
384
275
|
this.log.debug('The frontend sent /api/plugins');
|
|
385
276
|
res.json(this.getBaseRegisteredPlugins());
|
|
386
277
|
});
|
|
387
|
-
// Endpoint to provide devices
|
|
388
278
|
this.expressApp.get('/api/devices', (req, res) => {
|
|
389
279
|
this.log.debug('The frontend sent /api/devices');
|
|
390
280
|
const devices = [];
|
|
391
281
|
this.matterbridge.devices.forEach(async (device) => {
|
|
392
|
-
// Check if the device has the required properties
|
|
393
282
|
if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
|
|
394
283
|
return;
|
|
395
284
|
const cluster = this.getClusterTextFromDevice(device);
|
|
@@ -408,7 +297,6 @@ export class Frontend {
|
|
|
408
297
|
});
|
|
409
298
|
res.json(devices);
|
|
410
299
|
});
|
|
411
|
-
// Endpoint to provide the cluster servers of the devices
|
|
412
300
|
this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
|
|
413
301
|
const selectedPluginName = req.params.selectedPluginName;
|
|
414
302
|
const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
|
|
@@ -481,7 +369,6 @@ export class Frontend {
|
|
|
481
369
|
});
|
|
482
370
|
res.json(data);
|
|
483
371
|
});
|
|
484
|
-
// Endpoint to view the log
|
|
485
372
|
this.expressApp.get('/api/view-log', async (req, res) => {
|
|
486
373
|
this.log.debug('The frontend sent /api/log');
|
|
487
374
|
try {
|
|
@@ -494,12 +381,10 @@ export class Frontend {
|
|
|
494
381
|
res.status(500).send('Error reading log file');
|
|
495
382
|
}
|
|
496
383
|
});
|
|
497
|
-
// Endpoint to download the matterbridge log
|
|
498
384
|
this.expressApp.get('/api/download-mblog', async (req, res) => {
|
|
499
385
|
this.log.debug('The frontend sent /api/download-mblog');
|
|
500
386
|
try {
|
|
501
387
|
await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), fs.constants.F_OK);
|
|
502
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
503
388
|
}
|
|
504
389
|
catch (error) {
|
|
505
390
|
fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
|
|
@@ -511,12 +396,10 @@ export class Frontend {
|
|
|
511
396
|
}
|
|
512
397
|
});
|
|
513
398
|
});
|
|
514
|
-
// Endpoint to download the matter log
|
|
515
399
|
this.expressApp.get('/api/download-mjlog', async (req, res) => {
|
|
516
400
|
this.log.debug('The frontend sent /api/download-mjlog');
|
|
517
401
|
try {
|
|
518
402
|
await fs.access(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), fs.constants.F_OK);
|
|
519
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
520
403
|
}
|
|
521
404
|
catch (error) {
|
|
522
405
|
fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
|
|
@@ -528,12 +411,10 @@ export class Frontend {
|
|
|
528
411
|
}
|
|
529
412
|
});
|
|
530
413
|
});
|
|
531
|
-
// Endpoint to download the matter log
|
|
532
414
|
this.expressApp.get('/api/shellydownloadsystemlog', async (req, res) => {
|
|
533
415
|
this.log.debug('The frontend sent /api/shellydownloadsystemlog');
|
|
534
416
|
try {
|
|
535
417
|
await fs.access(path.join(this.matterbridge.matterbridgeDirectory, 'shelly.log'), fs.constants.F_OK);
|
|
536
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
537
418
|
}
|
|
538
419
|
catch (error) {
|
|
539
420
|
fs.appendFile(path.join(this.matterbridge.matterbridgeDirectory, 'shelly.log'), 'Create the Shelly system log before downloading it.');
|
|
@@ -545,7 +426,6 @@ export class Frontend {
|
|
|
545
426
|
}
|
|
546
427
|
});
|
|
547
428
|
});
|
|
548
|
-
// Endpoint to download the matter storage file
|
|
549
429
|
this.expressApp.get('/api/download-mjstorage', async (req, res) => {
|
|
550
430
|
this.log.debug('The frontend sent /api/download-mjstorage');
|
|
551
431
|
await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.matterStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterStorageName));
|
|
@@ -556,7 +436,6 @@ export class Frontend {
|
|
|
556
436
|
}
|
|
557
437
|
});
|
|
558
438
|
});
|
|
559
|
-
// Endpoint to download the matterbridge storage directory
|
|
560
439
|
this.expressApp.get('/api/download-mbstorage', async (req, res) => {
|
|
561
440
|
this.log.debug('The frontend sent /api/download-mbstorage');
|
|
562
441
|
await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.nodeStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.nodeStorageName));
|
|
@@ -567,7 +446,6 @@ export class Frontend {
|
|
|
567
446
|
}
|
|
568
447
|
});
|
|
569
448
|
});
|
|
570
|
-
// Endpoint to download the matterbridge plugin directory
|
|
571
449
|
this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
|
|
572
450
|
this.log.debug('The frontend sent /api/download-pluginstorage');
|
|
573
451
|
await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridge.matterbridgePluginDirectory);
|
|
@@ -578,11 +456,9 @@ export class Frontend {
|
|
|
578
456
|
}
|
|
579
457
|
});
|
|
580
458
|
});
|
|
581
|
-
// Endpoint to download the matterbridge plugin config files
|
|
582
459
|
this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
|
|
583
460
|
this.log.debug('The frontend sent /api/download-pluginconfig');
|
|
584
461
|
await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, '*.config.json')));
|
|
585
|
-
// 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')));
|
|
586
462
|
res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
|
|
587
463
|
if (error) {
|
|
588
464
|
this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
|
|
@@ -590,7 +466,6 @@ export class Frontend {
|
|
|
590
466
|
}
|
|
591
467
|
});
|
|
592
468
|
});
|
|
593
|
-
// Endpoint to download the matterbridge plugin config files
|
|
594
469
|
this.expressApp.get('/api/download-backup', async (req, res) => {
|
|
595
470
|
this.log.debug('The frontend sent /api/download-backup');
|
|
596
471
|
res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
|
|
@@ -600,7 +475,6 @@ export class Frontend {
|
|
|
600
475
|
}
|
|
601
476
|
});
|
|
602
477
|
});
|
|
603
|
-
// Endpoint to receive commands
|
|
604
478
|
this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
|
|
605
479
|
const command = req.params.command;
|
|
606
480
|
let param = req.params.param;
|
|
@@ -610,15 +484,13 @@ export class Frontend {
|
|
|
610
484
|
return;
|
|
611
485
|
}
|
|
612
486
|
this.log.debug(`Received frontend command: ${command}:${param}`);
|
|
613
|
-
// Handle the command setpassword from Settings
|
|
614
487
|
if (command === 'setpassword') {
|
|
615
|
-
const password = param.slice(1, -1);
|
|
488
|
+
const password = param.slice(1, -1);
|
|
616
489
|
this.log.debug('setpassword', param, password);
|
|
617
490
|
await this.matterbridge.nodeContext?.set('password', password);
|
|
618
491
|
res.json({ message: 'Command received' });
|
|
619
492
|
return;
|
|
620
493
|
}
|
|
621
|
-
// Handle the command setbridgemode from Settings
|
|
622
494
|
if (command === 'setbridgemode') {
|
|
623
495
|
this.log.debug(`setbridgemode: ${param}`);
|
|
624
496
|
this.wssSendRestartRequired();
|
|
@@ -626,7 +498,6 @@ export class Frontend {
|
|
|
626
498
|
res.json({ message: 'Command received' });
|
|
627
499
|
return;
|
|
628
500
|
}
|
|
629
|
-
// Handle the command backup from Settings
|
|
630
501
|
if (command === 'backup') {
|
|
631
502
|
this.log.notice(`Prepairing the backup...`);
|
|
632
503
|
await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridge.matterbridgeDirectory), path.join(this.matterbridge.matterbridgePluginDirectory));
|
|
@@ -635,33 +506,31 @@ export class Frontend {
|
|
|
635
506
|
res.json({ message: 'Command received' });
|
|
636
507
|
return;
|
|
637
508
|
}
|
|
638
|
-
// Handle the command setmbloglevel from Settings
|
|
639
509
|
if (command === 'setmbloglevel') {
|
|
640
510
|
this.log.debug('Matterbridge log level:', param);
|
|
641
511
|
if (param === 'Debug') {
|
|
642
|
-
this.log.logLevel = "debug"
|
|
512
|
+
this.log.logLevel = "debug";
|
|
643
513
|
}
|
|
644
514
|
else if (param === 'Info') {
|
|
645
|
-
this.log.logLevel = "info"
|
|
515
|
+
this.log.logLevel = "info";
|
|
646
516
|
}
|
|
647
517
|
else if (param === 'Notice') {
|
|
648
|
-
this.log.logLevel = "notice"
|
|
518
|
+
this.log.logLevel = "notice";
|
|
649
519
|
}
|
|
650
520
|
else if (param === 'Warn') {
|
|
651
|
-
this.log.logLevel = "warn"
|
|
521
|
+
this.log.logLevel = "warn";
|
|
652
522
|
}
|
|
653
523
|
else if (param === 'Error') {
|
|
654
|
-
this.log.logLevel = "error"
|
|
524
|
+
this.log.logLevel = "error";
|
|
655
525
|
}
|
|
656
526
|
else if (param === 'Fatal') {
|
|
657
|
-
this.log.logLevel = "fatal"
|
|
527
|
+
this.log.logLevel = "fatal";
|
|
658
528
|
}
|
|
659
529
|
await this.matterbridge.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
|
|
660
530
|
await this.matterbridge.setLogLevel(this.log.logLevel);
|
|
661
531
|
res.json({ message: 'Command received' });
|
|
662
532
|
return;
|
|
663
533
|
}
|
|
664
|
-
// Handle the command setmbloglevel from Settings
|
|
665
534
|
if (command === 'setmjloglevel') {
|
|
666
535
|
this.log.debug('Matter.js log level:', param);
|
|
667
536
|
if (param === 'Debug') {
|
|
@@ -686,7 +555,6 @@ export class Frontend {
|
|
|
686
555
|
res.json({ message: 'Command received' });
|
|
687
556
|
return;
|
|
688
557
|
}
|
|
689
|
-
// Handle the command setmdnsinterface from Settings
|
|
690
558
|
if (command === 'setmdnsinterface') {
|
|
691
559
|
if (param === 'json' && isValidString(req.body.value)) {
|
|
692
560
|
this.matterbridge.matterbridgeInformation.mattermdnsinterface = req.body.value;
|
|
@@ -696,7 +564,6 @@ export class Frontend {
|
|
|
696
564
|
res.json({ message: 'Command received' });
|
|
697
565
|
return;
|
|
698
566
|
}
|
|
699
|
-
// Handle the command setipv4address from Settings
|
|
700
567
|
if (command === 'setipv4address') {
|
|
701
568
|
if (param === 'json' && isValidString(req.body.value)) {
|
|
702
569
|
this.log.debug(`Matter.js ipv4 address: ${req.body.value === '' ? 'all ipv4 addresses' : req.body.value}`);
|
|
@@ -706,7 +573,6 @@ export class Frontend {
|
|
|
706
573
|
res.json({ message: 'Command received' });
|
|
707
574
|
return;
|
|
708
575
|
}
|
|
709
|
-
// Handle the command setipv6address from Settings
|
|
710
576
|
if (command === 'setipv6address') {
|
|
711
577
|
if (param === 'json' && isValidString(req.body.value)) {
|
|
712
578
|
this.log.debug(`Matter.js ipv6 address: ${req.body.value === '' ? 'all ipv6 addresses' : req.body.value}`);
|
|
@@ -716,7 +582,6 @@ export class Frontend {
|
|
|
716
582
|
res.json({ message: 'Command received' });
|
|
717
583
|
return;
|
|
718
584
|
}
|
|
719
|
-
// Handle the command setmatterport from Settings
|
|
720
585
|
if (command === 'setmatterport') {
|
|
721
586
|
const port = Math.min(Math.max(parseInt(req.body.value), 5540), 5560);
|
|
722
587
|
this.matterbridge.matterbridgeInformation.matterPort = port;
|
|
@@ -725,7 +590,6 @@ export class Frontend {
|
|
|
725
590
|
res.json({ message: 'Command received' });
|
|
726
591
|
return;
|
|
727
592
|
}
|
|
728
|
-
// Handle the command setmatterdiscriminator from Settings
|
|
729
593
|
if (command === 'setmatterdiscriminator') {
|
|
730
594
|
const discriminator = Math.min(Math.max(parseInt(req.body.value), 1000), 4095);
|
|
731
595
|
this.matterbridge.matterbridgeInformation.matterDiscriminator = discriminator;
|
|
@@ -734,7 +598,6 @@ export class Frontend {
|
|
|
734
598
|
res.json({ message: 'Command received' });
|
|
735
599
|
return;
|
|
736
600
|
}
|
|
737
|
-
// Handle the command setmatterpasscode from Settings
|
|
738
601
|
if (command === 'setmatterpasscode') {
|
|
739
602
|
const passcode = Math.min(Math.max(parseInt(req.body.value), 10000000), 90000000);
|
|
740
603
|
this.matterbridge.matterbridgeInformation.matterPasscode = passcode;
|
|
@@ -743,20 +606,17 @@ export class Frontend {
|
|
|
743
606
|
res.json({ message: 'Command received' });
|
|
744
607
|
return;
|
|
745
608
|
}
|
|
746
|
-
// Handle the command setmbloglevel from Settings
|
|
747
609
|
if (command === 'setmblogfile') {
|
|
748
610
|
this.log.debug('Matterbridge file log:', param);
|
|
749
611
|
this.matterbridge.matterbridgeInformation.fileLogger = param === 'true';
|
|
750
612
|
await this.matterbridge.nodeContext?.set('matterbridgeFileLog', param === 'true');
|
|
751
|
-
// Create the file logger for matterbridge
|
|
752
613
|
if (param === 'true')
|
|
753
|
-
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug"
|
|
614
|
+
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug", true);
|
|
754
615
|
else
|
|
755
616
|
AnsiLogger.setGlobalLogfile(undefined);
|
|
756
617
|
res.json({ message: 'Command received' });
|
|
757
618
|
return;
|
|
758
619
|
}
|
|
759
|
-
// Handle the command setmbloglevel from Settings
|
|
760
620
|
if (command === 'setmjlogfile') {
|
|
761
621
|
this.log.debug('Matter file log:', param);
|
|
762
622
|
this.matterbridge.matterbridgeInformation.matterFileLogger = param === 'true';
|
|
@@ -783,48 +643,40 @@ export class Frontend {
|
|
|
783
643
|
res.json({ message: 'Command received' });
|
|
784
644
|
return;
|
|
785
645
|
}
|
|
786
|
-
// Handle the command unregister from Settings
|
|
787
646
|
if (command === 'unregister') {
|
|
788
647
|
await this.matterbridge.unregisterAndShutdownProcess();
|
|
789
648
|
res.json({ message: 'Command received' });
|
|
790
649
|
return;
|
|
791
650
|
}
|
|
792
|
-
// Handle the command reset from Settings
|
|
793
651
|
if (command === 'reset') {
|
|
794
652
|
await this.matterbridge.shutdownProcessAndReset();
|
|
795
653
|
res.json({ message: 'Command received' });
|
|
796
654
|
return;
|
|
797
655
|
}
|
|
798
|
-
// Handle the command factoryreset from Settings
|
|
799
656
|
if (command === 'factoryreset') {
|
|
800
657
|
await this.matterbridge.shutdownProcessAndFactoryReset();
|
|
801
658
|
res.json({ message: 'Command received' });
|
|
802
659
|
return;
|
|
803
660
|
}
|
|
804
|
-
// Handle the command shutdown from Header
|
|
805
661
|
if (command === 'shutdown') {
|
|
806
662
|
await this.matterbridge.shutdownProcess();
|
|
807
663
|
res.json({ message: 'Command received' });
|
|
808
664
|
return;
|
|
809
665
|
}
|
|
810
|
-
// Handle the command restart from Header
|
|
811
666
|
if (command === 'restart') {
|
|
812
667
|
await this.matterbridge.restartProcess();
|
|
813
668
|
res.json({ message: 'Command received' });
|
|
814
669
|
return;
|
|
815
670
|
}
|
|
816
|
-
// Handle the command update from Header
|
|
817
671
|
if (command === 'update') {
|
|
818
672
|
await this.matterbridge.updateProcess();
|
|
819
673
|
this.wssSendRestartRequired();
|
|
820
674
|
res.json({ message: 'Command received' });
|
|
821
675
|
return;
|
|
822
676
|
}
|
|
823
|
-
// Handle the command saveconfig from Home
|
|
824
677
|
if (command === 'saveconfig') {
|
|
825
678
|
param = param.replace(/\*/g, '\\');
|
|
826
679
|
this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
|
|
827
|
-
// console.log('Req.body:', JSON.stringify(req.body, null, 2));
|
|
828
680
|
if (!this.matterbridge.plugins.has(param)) {
|
|
829
681
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
830
682
|
}
|
|
@@ -839,7 +691,6 @@ export class Frontend {
|
|
|
839
691
|
res.json({ message: 'Command received' });
|
|
840
692
|
return;
|
|
841
693
|
}
|
|
842
|
-
// Handle the command installplugin from Home
|
|
843
694
|
if (command === 'installplugin') {
|
|
844
695
|
param = param.replace(/\*/g, '\\');
|
|
845
696
|
this.log.info(`Installing plugin ${plg}${param}${nf}...`);
|
|
@@ -848,7 +699,6 @@ export class Frontend {
|
|
|
848
699
|
await this.matterbridge.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
|
|
849
700
|
this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
|
|
850
701
|
this.wssSendSnackbarMessage(`Installed package ${param}`, 10, 'success');
|
|
851
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
852
702
|
}
|
|
853
703
|
catch (error) {
|
|
854
704
|
this.log.error(`Error installing plugin ${plg}${param}${er}`);
|
|
@@ -856,22 +706,17 @@ export class Frontend {
|
|
|
856
706
|
}
|
|
857
707
|
this.wssSendRestartRequired();
|
|
858
708
|
param = param.split('@')[0];
|
|
859
|
-
// Also add the plugin to matterbridge so no return!
|
|
860
709
|
if (param === 'matterbridge') {
|
|
861
|
-
// 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
|
|
862
710
|
res.json({ message: 'Command received' });
|
|
863
711
|
return;
|
|
864
712
|
}
|
|
865
713
|
}
|
|
866
|
-
// Handle the command addplugin from Home
|
|
867
714
|
if (command === 'addplugin' || command === 'installplugin') {
|
|
868
715
|
param = param.replace(/\*/g, '\\');
|
|
869
716
|
const plugin = await this.matterbridge.plugins.add(param);
|
|
870
717
|
if (plugin) {
|
|
871
718
|
this.wssSendSnackbarMessage(`Added plugin ${param}`);
|
|
872
719
|
if (this.matterbridge.bridgeMode === 'childbridge') {
|
|
873
|
-
// 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
|
|
874
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
875
720
|
this.matterbridge.createDynamicPlugin(plugin, true);
|
|
876
721
|
}
|
|
877
722
|
this.matterbridge.plugins.load(plugin, true, 'The plugin has been added', true).then(() => {
|
|
@@ -881,14 +726,13 @@ export class Frontend {
|
|
|
881
726
|
res.json({ message: 'Command received' });
|
|
882
727
|
return;
|
|
883
728
|
}
|
|
884
|
-
// Handle the command removeplugin from Home
|
|
885
729
|
if (command === 'removeplugin') {
|
|
886
730
|
if (!this.matterbridge.plugins.has(param)) {
|
|
887
731
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
888
732
|
}
|
|
889
733
|
else {
|
|
890
734
|
const plugin = this.matterbridge.plugins.get(param);
|
|
891
|
-
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true);
|
|
735
|
+
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true);
|
|
892
736
|
await this.matterbridge.plugins.remove(param);
|
|
893
737
|
this.wssSendSnackbarMessage(`Removed plugin ${param}`);
|
|
894
738
|
this.wssSendRefreshRequired('plugins');
|
|
@@ -896,7 +740,6 @@ export class Frontend {
|
|
|
896
740
|
res.json({ message: 'Command received' });
|
|
897
741
|
return;
|
|
898
742
|
}
|
|
899
|
-
// Handle the command enableplugin from Home
|
|
900
743
|
if (command === 'enableplugin') {
|
|
901
744
|
if (!this.matterbridge.plugins.has(param)) {
|
|
902
745
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
@@ -915,7 +758,6 @@ export class Frontend {
|
|
|
915
758
|
await this.matterbridge.plugins.enable(param);
|
|
916
759
|
this.wssSendSnackbarMessage(`Enabled plugin ${param}`);
|
|
917
760
|
if (this.matterbridge.bridgeMode === 'childbridge' && plugin.type === 'DynamicPlatform') {
|
|
918
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
919
761
|
this.matterbridge.createDynamicPlugin(plugin, true);
|
|
920
762
|
}
|
|
921
763
|
this.matterbridge.plugins.load(plugin, true, 'The plugin has been enabled', true).then(() => {
|
|
@@ -926,7 +768,6 @@ export class Frontend {
|
|
|
926
768
|
res.json({ message: 'Command received' });
|
|
927
769
|
return;
|
|
928
770
|
}
|
|
929
|
-
// Handle the command disableplugin from Home
|
|
930
771
|
if (command === 'disableplugin') {
|
|
931
772
|
if (!this.matterbridge.plugins.has(param)) {
|
|
932
773
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
@@ -934,7 +775,7 @@ export class Frontend {
|
|
|
934
775
|
else {
|
|
935
776
|
const plugin = this.matterbridge.plugins.get(param);
|
|
936
777
|
if (plugin && plugin.enabled) {
|
|
937
|
-
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true);
|
|
778
|
+
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true);
|
|
938
779
|
await this.matterbridge.plugins.disable(param);
|
|
939
780
|
this.wssSendSnackbarMessage(`Disabled plugin ${param}`);
|
|
940
781
|
this.wssSendRefreshRequired('plugins');
|
|
@@ -953,13 +794,10 @@ export class Frontend {
|
|
|
953
794
|
return;
|
|
954
795
|
}
|
|
955
796
|
this.wssSendSnackbarMessage(`Installing package ${filename}. Please wait...`);
|
|
956
|
-
// Define the path where the plugin file will be saved
|
|
957
797
|
const filePath = path.join(this.matterbridge.matterbridgeDirectory, 'uploads', filename);
|
|
958
798
|
try {
|
|
959
|
-
// Move the uploaded file to the specified path
|
|
960
799
|
await fs.rename(file.path, filePath);
|
|
961
800
|
this.log.info(`File ${plg}${filename}${nf} uploaded successfully`);
|
|
962
|
-
// Install the plugin package
|
|
963
801
|
if (filename.endsWith('.tgz')) {
|
|
964
802
|
await this.matterbridge.spawnCommand('npm', ['install', '-g', filePath, '--omit=dev', '--verbose']);
|
|
965
803
|
this.log.info(`Plugin package ${plg}${filename}${nf} installed successfully. Full restart required.`);
|
|
@@ -976,7 +814,6 @@ export class Frontend {
|
|
|
976
814
|
res.status(500).send(`Error uploading or installing plugin package ${filename}`);
|
|
977
815
|
}
|
|
978
816
|
});
|
|
979
|
-
// Fallback for routing (must be the last route)
|
|
980
817
|
this.expressApp.get('*', (req, res) => {
|
|
981
818
|
this.log.debug('The frontend sent:', req.url);
|
|
982
819
|
this.log.debug('Response send file:', path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
|
|
@@ -985,31 +822,24 @@ export class Frontend {
|
|
|
985
822
|
this.log.debug(`Frontend initialized on port ${YELLOW}${this.port}${db} static ${UNDERLINE}${path.join(this.matterbridge.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
|
|
986
823
|
}
|
|
987
824
|
async stop() {
|
|
988
|
-
// Remove all listeners from the cliEmitter
|
|
989
|
-
// cliEmitter.removeAllListeners();
|
|
990
|
-
// Close the http server
|
|
991
825
|
if (this.httpServer) {
|
|
992
826
|
this.httpServer.close();
|
|
993
827
|
this.httpServer.removeAllListeners();
|
|
994
828
|
this.httpServer = undefined;
|
|
995
829
|
this.log.debug('Frontend http server closed successfully');
|
|
996
830
|
}
|
|
997
|
-
// Close the https server
|
|
998
831
|
if (this.httpsServer) {
|
|
999
832
|
this.httpsServer.close();
|
|
1000
833
|
this.httpsServer.removeAllListeners();
|
|
1001
834
|
this.httpsServer = undefined;
|
|
1002
835
|
this.log.debug('Frontend https server closed successfully');
|
|
1003
836
|
}
|
|
1004
|
-
// Remove listeners from the express app
|
|
1005
837
|
if (this.expressApp) {
|
|
1006
838
|
this.expressApp.removeAllListeners();
|
|
1007
839
|
this.expressApp = undefined;
|
|
1008
840
|
this.log.debug('Frontend app closed successfully');
|
|
1009
841
|
}
|
|
1010
|
-
// Close the WebSocket server
|
|
1011
842
|
if (this.webSocketServer) {
|
|
1012
|
-
// Close all active connections
|
|
1013
843
|
this.webSocketServer.clients.forEach((client) => {
|
|
1014
844
|
if (client.readyState === WebSocket.OPEN) {
|
|
1015
845
|
client.close();
|
|
@@ -1026,7 +856,6 @@ export class Frontend {
|
|
|
1026
856
|
this.webSocketServer = undefined;
|
|
1027
857
|
}
|
|
1028
858
|
}
|
|
1029
|
-
// Function to format bytes to KB, MB, or GB
|
|
1030
859
|
formatMemoryUsage = (bytes) => {
|
|
1031
860
|
if (bytes >= 1024 ** 3) {
|
|
1032
861
|
return `${(bytes / 1024 ** 3).toFixed(2)} GB`;
|
|
@@ -1038,7 +867,6 @@ export class Frontend {
|
|
|
1038
867
|
return `${(bytes / 1024).toFixed(2)} KB`;
|
|
1039
868
|
}
|
|
1040
869
|
};
|
|
1041
|
-
// Function to format system uptime with only the most significant unit
|
|
1042
870
|
formatOsUpTime = (seconds) => {
|
|
1043
871
|
if (seconds >= 86400) {
|
|
1044
872
|
const days = Math.floor(seconds / 86400);
|
|
@@ -1054,13 +882,8 @@ export class Frontend {
|
|
|
1054
882
|
}
|
|
1055
883
|
return `${seconds} second${seconds !== 1 ? 's' : ''}`;
|
|
1056
884
|
};
|
|
1057
|
-
/**
|
|
1058
|
-
* Retrieves the api settings data.
|
|
1059
|
-
* @returns {Promise<object>} A promise that resolve in the api settings object.
|
|
1060
|
-
*/
|
|
1061
885
|
async getApiSettings() {
|
|
1062
886
|
const { lastCpuUsage } = await import('./cli.js');
|
|
1063
|
-
// Update the system information
|
|
1064
887
|
this.matterbridge.systemInformation.totalMemory = this.formatMemoryUsage(os.totalmem());
|
|
1065
888
|
this.matterbridge.systemInformation.freeMemory = this.formatMemoryUsage(os.freemem());
|
|
1066
889
|
this.matterbridge.systemInformation.systemUptime = this.formatOsUpTime(os.uptime());
|
|
@@ -1069,7 +892,6 @@ export class Frontend {
|
|
|
1069
892
|
this.matterbridge.systemInformation.rss = this.formatMemoryUsage(process.memoryUsage().rss);
|
|
1070
893
|
this.matterbridge.systemInformation.heapTotal = this.formatMemoryUsage(process.memoryUsage().heapTotal);
|
|
1071
894
|
this.matterbridge.systemInformation.heapUsed = this.formatMemoryUsage(process.memoryUsage().heapUsed);
|
|
1072
|
-
// Update the matterbridge information
|
|
1073
895
|
this.matterbridge.matterbridgeInformation.bridgeMode = this.matterbridge.bridgeMode;
|
|
1074
896
|
this.matterbridge.matterbridgeInformation.restartMode = this.matterbridge.restartMode;
|
|
1075
897
|
this.matterbridge.matterbridgeInformation.loggerLevel = this.matterbridge.log.logLevel;
|
|
@@ -1088,11 +910,6 @@ export class Frontend {
|
|
|
1088
910
|
this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
|
|
1089
911
|
return { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: this.matterbridge.matterbridgeInformation };
|
|
1090
912
|
}
|
|
1091
|
-
/**
|
|
1092
|
-
* Retrieves the reachable attribute.
|
|
1093
|
-
* @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
|
|
1094
|
-
* @returns {boolean} The reachable attribute.
|
|
1095
|
-
*/
|
|
1096
913
|
getReachability(device) {
|
|
1097
914
|
if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
|
|
1098
915
|
return false;
|
|
@@ -1102,11 +919,6 @@ export class Frontend {
|
|
|
1102
919
|
return true;
|
|
1103
920
|
return false;
|
|
1104
921
|
}
|
|
1105
|
-
/**
|
|
1106
|
-
* Retrieves the cluster text description from a given device.
|
|
1107
|
-
* @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
|
|
1108
|
-
* @returns {string} The attributes description of the cluster servers in the device.
|
|
1109
|
-
*/
|
|
1110
922
|
getClusterTextFromDevice(device) {
|
|
1111
923
|
if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
|
|
1112
924
|
return '';
|
|
@@ -1147,7 +959,6 @@ export class Frontend {
|
|
|
1147
959
|
};
|
|
1148
960
|
let attributes = '';
|
|
1149
961
|
device.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
|
|
1150
|
-
// console.log(`${device.deviceName} => Cluster: ${clusterName}-${clusterId} Attribute: ${attributeName}-${attributeId} Value(${typeof attributeValue}): ${attributeValue}`);
|
|
1151
962
|
if (typeof attributeValue === 'undefined')
|
|
1152
963
|
return;
|
|
1153
964
|
if (clusterName === 'onOff' && attributeName === 'onOff')
|
|
@@ -1225,13 +1036,8 @@ export class Frontend {
|
|
|
1225
1036
|
if (clusterName === 'userLabel' && attributeName === 'labelList')
|
|
1226
1037
|
attributes += `${getUserLabel(device)} `;
|
|
1227
1038
|
});
|
|
1228
|
-
// console.log(`${device.deviceName}.forEachAttribute: ${attributes}`);
|
|
1229
1039
|
return attributes.trimStart().trimEnd();
|
|
1230
1040
|
}
|
|
1231
|
-
/**
|
|
1232
|
-
* Retrieves the base registered plugins sanitized for res.json().
|
|
1233
|
-
* @returns {BaseRegisteredPlugin[]} An array of BaseRegisteredPlugin.
|
|
1234
|
-
*/
|
|
1235
1041
|
getBaseRegisteredPlugins() {
|
|
1236
1042
|
const baseRegisteredPlugins = [];
|
|
1237
1043
|
for (const plugin of this.matterbridge.plugins) {
|
|
@@ -1268,13 +1074,6 @@ export class Frontend {
|
|
|
1268
1074
|
}
|
|
1269
1075
|
return baseRegisteredPlugins;
|
|
1270
1076
|
}
|
|
1271
|
-
/**
|
|
1272
|
-
* Handles incoming websocket messages for the Matterbridge frontend.
|
|
1273
|
-
*
|
|
1274
|
-
* @param {WebSocket} client - The websocket client that sent the message.
|
|
1275
|
-
* @param {WebSocket.RawData} message - The raw data of the message received from the client.
|
|
1276
|
-
* @returns {Promise<void>} A promise that resolves when the message has been handled.
|
|
1277
|
-
*/
|
|
1278
1077
|
async wsMessageHandler(client, message) {
|
|
1279
1078
|
let data;
|
|
1280
1079
|
try {
|
|
@@ -1430,10 +1229,8 @@ export class Frontend {
|
|
|
1430
1229
|
else if (data.method === '/api/devices') {
|
|
1431
1230
|
const devices = [];
|
|
1432
1231
|
this.matterbridge.devices.forEach(async (device) => {
|
|
1433
|
-
// Filter by pluginName if provided
|
|
1434
1232
|
if (data.params.pluginName && data.params.pluginName !== device.plugin)
|
|
1435
1233
|
return;
|
|
1436
|
-
// Check if the device has the required properties
|
|
1437
1234
|
if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
|
|
1438
1235
|
return;
|
|
1439
1236
|
const cluster = this.getClusterTextFromDevice(device);
|
|
@@ -1517,7 +1314,6 @@ export class Frontend {
|
|
|
1517
1314
|
});
|
|
1518
1315
|
endpointServer.getChildEndpoints().forEach((childEndpoint) => {
|
|
1519
1316
|
deviceTypes = [];
|
|
1520
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1521
1317
|
const name = childEndpoint.endpoint?.id;
|
|
1522
1318
|
const clusterServers = childEndpoint.getAllClusterServers();
|
|
1523
1319
|
clusterServers.forEach((clusterServer) => {
|
|
@@ -1571,7 +1367,6 @@ export class Frontend {
|
|
|
1571
1367
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Plugin not found in /api/select' }));
|
|
1572
1368
|
return;
|
|
1573
1369
|
}
|
|
1574
|
-
// const selectDeviceValues = plugin.platform?.selectDevice ? Array.from(plugin.platform.selectDevice.values()).sort((keyA, keyB) => keyA.name.localeCompare(keyB.name)) : [];
|
|
1575
1370
|
const selectDeviceValues = plugin.platform?.getSelectDevices().sort((keyA, keyB) => keyA.name.localeCompare(keyB.name));
|
|
1576
1371
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, plugin: data.params.plugin, response: selectDeviceValues }));
|
|
1577
1372
|
return;
|
|
@@ -1586,7 +1381,6 @@ export class Frontend {
|
|
|
1586
1381
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Plugin not found in /api/select/entities' }));
|
|
1587
1382
|
return;
|
|
1588
1383
|
}
|
|
1589
|
-
// const selectEntityValues = plugin.platform?.selectDevice ? Array.from(plugin.platform.selectEntity.values()).sort((keyA, keyB) => keyA.name.localeCompare(keyB.name)) : [];
|
|
1590
1384
|
const selectEntityValues = plugin.platform?.getSelectEntities().sort((keyA, keyB) => keyA.name.localeCompare(keyB.name));
|
|
1591
1385
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, plugin: data.params.plugin, response: selectEntityValues }));
|
|
1592
1386
|
return;
|
|
@@ -1618,7 +1412,6 @@ export class Frontend {
|
|
|
1618
1412
|
return;
|
|
1619
1413
|
}
|
|
1620
1414
|
const config = plugin.configJson;
|
|
1621
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1622
1415
|
const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
|
|
1623
1416
|
this.log.debug(`SelectDevice(selectMode ${select}) data ${debugStringify(data)}`);
|
|
1624
1417
|
if (select === 'serial')
|
|
@@ -1626,11 +1419,9 @@ export class Frontend {
|
|
|
1626
1419
|
if (select === 'name')
|
|
1627
1420
|
this.log.info(`Selected device name ${data.params.name}`);
|
|
1628
1421
|
if (config && select && (select === 'serial' || select === 'name')) {
|
|
1629
|
-
// Remove postfix from the serial if it exists
|
|
1630
1422
|
if (config.postfix) {
|
|
1631
1423
|
data.params.serial = data.params.serial.replace('-' + config.postfix, '');
|
|
1632
1424
|
}
|
|
1633
|
-
// Add the serial to the whiteList if the whiteList exists and the serial or name is not already in it
|
|
1634
1425
|
if (isValidArray(config.whiteList, 1)) {
|
|
1635
1426
|
if (select === 'serial' && !config.whiteList.includes(data.params.serial)) {
|
|
1636
1427
|
config.whiteList.push(data.params.serial);
|
|
@@ -1639,7 +1430,6 @@ export class Frontend {
|
|
|
1639
1430
|
config.whiteList.push(data.params.name);
|
|
1640
1431
|
}
|
|
1641
1432
|
}
|
|
1642
|
-
// Remove the serial from the blackList if the blackList exists and the serial or name is in it
|
|
1643
1433
|
if (isValidArray(config.blackList, 1)) {
|
|
1644
1434
|
if (select === 'serial' && config.blackList.includes(data.params.serial)) {
|
|
1645
1435
|
config.blackList = config.blackList.filter((serial) => serial !== data.params.serial);
|
|
@@ -1661,7 +1451,6 @@ export class Frontend {
|
|
|
1661
1451
|
return;
|
|
1662
1452
|
}
|
|
1663
1453
|
const config = plugin.configJson;
|
|
1664
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1665
1454
|
const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
|
|
1666
1455
|
this.log.debug(`UnselectDevice(selectMode ${select}) data ${debugStringify(data)}`);
|
|
1667
1456
|
if (select === 'serial')
|
|
@@ -1672,7 +1461,6 @@ export class Frontend {
|
|
|
1672
1461
|
if (config.postfix) {
|
|
1673
1462
|
data.params.serial = data.params.serial.replace('-' + config.postfix, '');
|
|
1674
1463
|
}
|
|
1675
|
-
// Remove the serial from the whiteList if the whiteList exists and the serial is in it
|
|
1676
1464
|
if (isValidArray(config.whiteList, 1)) {
|
|
1677
1465
|
if (select === 'serial' && config.whiteList.includes(data.params.serial)) {
|
|
1678
1466
|
config.whiteList = config.whiteList.filter((serial) => serial !== data.params.serial);
|
|
@@ -1681,7 +1469,6 @@ export class Frontend {
|
|
|
1681
1469
|
config.whiteList = config.whiteList.filter((name) => name !== data.params.name);
|
|
1682
1470
|
}
|
|
1683
1471
|
}
|
|
1684
|
-
// Add the serial to the blackList
|
|
1685
1472
|
if (isValidArray(config.blackList)) {
|
|
1686
1473
|
if (select === 'serial' && !config.blackList.includes(data.params.serial)) {
|
|
1687
1474
|
config.blackList.push(data.params.serial);
|
|
@@ -1708,194 +1495,102 @@ export class Frontend {
|
|
|
1708
1495
|
return;
|
|
1709
1496
|
}
|
|
1710
1497
|
}
|
|
1711
|
-
/**
|
|
1712
|
-
* Sends a WebSocket message to all connected clients. The function is called by AnsiLogger.setGlobalCallback.
|
|
1713
|
-
*
|
|
1714
|
-
* @param {string} level - The logger level of the message: debug info notice warn error fatal...
|
|
1715
|
-
* @param {string} time - The time string of the message
|
|
1716
|
-
* @param {string} name - The logger name of the message
|
|
1717
|
-
* @param {string} message - The content of the message.
|
|
1718
|
-
*/
|
|
1719
1498
|
wssSendMessage(level, time, name, message) {
|
|
1720
1499
|
if (!level || !time || !name || !message)
|
|
1721
1500
|
return;
|
|
1722
|
-
// Remove ANSI escape codes from the message
|
|
1723
|
-
// eslint-disable-next-line no-control-regex
|
|
1724
1501
|
message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
|
|
1725
|
-
// Remove leading asterisks from the message
|
|
1726
1502
|
message = message.replace(/^\*+/, '');
|
|
1727
|
-
// Replace all occurrences of \t and \n
|
|
1728
1503
|
message = message.replace(/[\t\n]/g, '');
|
|
1729
|
-
// Remove non-printable characters
|
|
1730
|
-
// eslint-disable-next-line no-control-regex
|
|
1731
1504
|
message = message.replace(/[\x00-\x1F\x7F]/g, '');
|
|
1732
|
-
// Replace all occurrences of \" with "
|
|
1733
1505
|
message = message.replace(/\\"/g, '"');
|
|
1734
|
-
// Define the maximum allowed length for continuous characters without a space
|
|
1735
1506
|
const maxContinuousLength = 100;
|
|
1736
1507
|
const keepStartLength = 20;
|
|
1737
1508
|
const keepEndLength = 20;
|
|
1738
|
-
// Split the message into words
|
|
1739
1509
|
message = message
|
|
1740
1510
|
.split(' ')
|
|
1741
1511
|
.map((word) => {
|
|
1742
|
-
// If the word length exceeds the max continuous length, insert spaces and truncate
|
|
1743
1512
|
if (word.length > maxContinuousLength) {
|
|
1744
1513
|
return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
|
|
1745
1514
|
}
|
|
1746
1515
|
return word;
|
|
1747
1516
|
})
|
|
1748
1517
|
.join(' ');
|
|
1749
|
-
// Send the message to all connected clients
|
|
1750
1518
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1751
1519
|
if (client.readyState === WebSocket.OPEN) {
|
|
1752
1520
|
client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
|
|
1753
1521
|
}
|
|
1754
1522
|
});
|
|
1755
1523
|
}
|
|
1756
|
-
/**
|
|
1757
|
-
* Sends a need to refresh WebSocket message to all connected clients.
|
|
1758
|
-
*
|
|
1759
|
-
* @param {string} changed - The changed value. If null, the whole page will be refreshed.
|
|
1760
|
-
* possible values:
|
|
1761
|
-
* - 'matterbridgeLatestVersion'
|
|
1762
|
-
* - 'matterbridgeAdvertise'
|
|
1763
|
-
* - 'online'
|
|
1764
|
-
* - 'offline'
|
|
1765
|
-
* - 'reachability'
|
|
1766
|
-
* - 'settings'
|
|
1767
|
-
* - 'plugins'
|
|
1768
|
-
* - 'devices'
|
|
1769
|
-
* - 'fabrics'
|
|
1770
|
-
* - 'sessions'
|
|
1771
|
-
*/
|
|
1772
1524
|
wssSendRefreshRequired(changed = null) {
|
|
1773
1525
|
this.log.debug('Sending a refresh required message to all connected clients');
|
|
1774
|
-
// Send the message to all connected clients
|
|
1775
1526
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1776
1527
|
if (client.readyState === WebSocket.OPEN) {
|
|
1777
1528
|
client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', params: { changed: changed } }));
|
|
1778
1529
|
}
|
|
1779
1530
|
});
|
|
1780
1531
|
}
|
|
1781
|
-
/**
|
|
1782
|
-
* Sends a need to restart WebSocket message to all connected clients.
|
|
1783
|
-
*
|
|
1784
|
-
*/
|
|
1785
1532
|
wssSendRestartRequired(snackbar = true) {
|
|
1786
1533
|
this.log.debug('Sending a restart required message to all connected clients');
|
|
1787
1534
|
this.matterbridge.matterbridgeInformation.restartRequired = true;
|
|
1788
1535
|
if (snackbar === true)
|
|
1789
1536
|
this.wssSendSnackbarMessage(`Restart required`, 0);
|
|
1790
|
-
// Send the message to all connected clients
|
|
1791
1537
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1792
1538
|
if (client.readyState === WebSocket.OPEN) {
|
|
1793
1539
|
client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', params: {} }));
|
|
1794
1540
|
}
|
|
1795
1541
|
});
|
|
1796
1542
|
}
|
|
1797
|
-
/**
|
|
1798
|
-
* Sends a need to update WebSocket message to all connected clients.
|
|
1799
|
-
*
|
|
1800
|
-
*/
|
|
1801
1543
|
wssSendUpdateRequired() {
|
|
1802
1544
|
this.log.debug('Sending an update required message to all connected clients');
|
|
1803
1545
|
this.matterbridge.matterbridgeInformation.updateRequired = true;
|
|
1804
|
-
// Send the message to all connected clients
|
|
1805
1546
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1806
1547
|
if (client.readyState === WebSocket.OPEN) {
|
|
1807
1548
|
client.send(JSON.stringify({ id: WS_ID_UPDATE_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'update_required', params: {} }));
|
|
1808
1549
|
}
|
|
1809
1550
|
});
|
|
1810
1551
|
}
|
|
1811
|
-
/**
|
|
1812
|
-
* Sends a memory update message to all connected clients.
|
|
1813
|
-
*
|
|
1814
|
-
*/
|
|
1815
1552
|
wssSendCpuUpdate(cpuUsage) {
|
|
1816
1553
|
this.log.debug('Sending a cpu update message to all connected clients');
|
|
1817
|
-
// Send the message to all connected clients
|
|
1818
1554
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1819
1555
|
if (client.readyState === WebSocket.OPEN) {
|
|
1820
1556
|
client.send(JSON.stringify({ id: WS_ID_CPU_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'cpu_update', params: { cpuUsage } }));
|
|
1821
1557
|
}
|
|
1822
1558
|
});
|
|
1823
1559
|
}
|
|
1824
|
-
/**
|
|
1825
|
-
* Sends a cpu update message to all connected clients.
|
|
1826
|
-
*
|
|
1827
|
-
*/
|
|
1828
1560
|
wssSendMemoryUpdate(totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers) {
|
|
1829
1561
|
this.log.debug('Sending a memory update message to all connected clients');
|
|
1830
|
-
// Send the message to all connected clients
|
|
1831
1562
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1832
1563
|
if (client.readyState === WebSocket.OPEN) {
|
|
1833
1564
|
client.send(JSON.stringify({ id: WS_ID_MEMORY_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', params: { totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers } }));
|
|
1834
1565
|
}
|
|
1835
1566
|
});
|
|
1836
1567
|
}
|
|
1837
|
-
/**
|
|
1838
|
-
* Sends a memory update message to all connected clients.
|
|
1839
|
-
*
|
|
1840
|
-
*/
|
|
1841
1568
|
wssSendUptimeUpdate(systemUptime, processUptime) {
|
|
1842
1569
|
this.log.debug('Sending a uptime update message to all connected clients');
|
|
1843
|
-
// Send the message to all connected clients
|
|
1844
1570
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1845
1571
|
if (client.readyState === WebSocket.OPEN) {
|
|
1846
1572
|
client.send(JSON.stringify({ id: WS_ID_UPTIME_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'uptime_update', params: { systemUptime, processUptime } }));
|
|
1847
1573
|
}
|
|
1848
1574
|
});
|
|
1849
1575
|
}
|
|
1850
|
-
/**
|
|
1851
|
-
* Sends a cpu update message to all connected clients.
|
|
1852
|
-
* @param {string} message - The message to send.
|
|
1853
|
-
* @param {number} timeout - The timeout in seconds for the snackbar message.
|
|
1854
|
-
* @param {'info' | 'warning' | 'error' | 'success'} severity - The severity of the snackbar message (default info).
|
|
1855
|
-
*
|
|
1856
|
-
*/
|
|
1857
1576
|
wssSendSnackbarMessage(message, timeout = 5, severity = 'info') {
|
|
1858
1577
|
this.log.debug('Sending a snackbar message to all connected clients');
|
|
1859
|
-
// Send the message to all connected clients
|
|
1860
1578
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1861
1579
|
if (client.readyState === WebSocket.OPEN) {
|
|
1862
1580
|
client.send(JSON.stringify({ id: WS_ID_SNACKBAR, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', params: { message, timeout, severity } }));
|
|
1863
1581
|
}
|
|
1864
1582
|
});
|
|
1865
1583
|
}
|
|
1866
|
-
/**
|
|
1867
|
-
* Sends an attribute update message to all connected WebSocket clients.
|
|
1868
|
-
*
|
|
1869
|
-
* @param {string | undefined} plugin - The name of the plugin.
|
|
1870
|
-
* @param {string | undefined} serialNumber - The serial number of the device.
|
|
1871
|
-
* @param {string | undefined} uniqueId - The unique identifier of the device.
|
|
1872
|
-
* @param {string} cluster - The cluster name where the attribute belongs.
|
|
1873
|
-
* @param {string} attribute - The name of the attribute that changed.
|
|
1874
|
-
* @param {number | string | boolean} value - The new value of the attribute.
|
|
1875
|
-
*
|
|
1876
|
-
* @remarks
|
|
1877
|
-
* This method logs a debug message and sends a JSON-formatted message to all connected WebSocket clients
|
|
1878
|
-
* with the updated attribute information.
|
|
1879
|
-
*/
|
|
1880
1584
|
wssSendAttributeChangedMessage(plugin, serialNumber, uniqueId, cluster, attribute, value) {
|
|
1881
1585
|
this.log.debug('Sending an attribute update message to all connected clients');
|
|
1882
|
-
// Send the message to all connected clients
|
|
1883
1586
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1884
1587
|
if (client.readyState === WebSocket.OPEN) {
|
|
1885
1588
|
client.send(JSON.stringify({ id: WS_ID_STATEUPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'state_update', params: { plugin, serialNumber, uniqueId, cluster, attribute, value } }));
|
|
1886
1589
|
}
|
|
1887
1590
|
});
|
|
1888
1591
|
}
|
|
1889
|
-
/**
|
|
1890
|
-
* Sends a message to all connected clients.
|
|
1891
|
-
* @param {number} id - The message id.
|
|
1892
|
-
* @param {string} method - The message method.
|
|
1893
|
-
* @param {Record<string, string | number | boolean>} params - The message parameters.
|
|
1894
|
-
*
|
|
1895
|
-
*/
|
|
1896
1592
|
wssBroadcastMessage(id, method, params) {
|
|
1897
1593
|
this.log.debug(`Sending a broadcast message id ${id} method ${method} params ${debugStringify(params ?? {})} to all connected clients`);
|
|
1898
|
-
// Send the message to all connected clients
|
|
1899
1594
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1900
1595
|
if (client.readyState === WebSocket.OPEN) {
|
|
1901
1596
|
client.send(JSON.stringify({ id, src: 'Matterbridge', dst: 'Frontend', method, params }));
|
|
@@ -1903,4 +1598,3 @@ export class Frontend {
|
|
|
1903
1598
|
});
|
|
1904
1599
|
}
|
|
1905
1600
|
}
|
|
1906
|
-
//# sourceMappingURL=frontend.js.map
|