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