matterbridge 2.2.6 → 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 +64 -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 +23 -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 +116 -718
- package/dist/matterbridgeEndpointHelpers.js +30 -136
- package/dist/matterbridgePlatform.js +12 -221
- package/dist/matterbridgeTypes.js +0 -24
- package/dist/pluginManager.js +98 -251
- 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/frontend/build/asset-manifest.json +3 -3
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/js/{main.f00179ca.js → main.1fa50342.js} +3 -3
- package/frontend/build/static/js/{main.f00179ca.js.map → main.1fa50342.js.map} +1 -1
- 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 -835
- package/dist/matterbridgeEndpoint.d.ts.map +0 -1
- package/dist/matterbridgeEndpoint.js.map +0 -1
- package/dist/matterbridgeEndpointHelpers.d.ts +0 -2275
- package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
- package/dist/matterbridgeEndpointHelpers.js.map +0 -1
- package/dist/matterbridgePlatform.d.ts +0 -285
- package/dist/matterbridgePlatform.d.ts.map +0 -1
- package/dist/matterbridgePlatform.js.map +0 -1
- package/dist/matterbridgeTypes.d.ts +0 -179
- package/dist/matterbridgeTypes.d.ts.map +0 -1
- package/dist/matterbridgeTypes.js.map +0 -1
- package/dist/pluginManager.d.ts +0 -236
- package/dist/pluginManager.d.ts.map +0 -1
- package/dist/pluginManager.js.map +0 -1
- package/dist/shelly.d.ts +0 -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/frontend/build/static/js/{main.f00179ca.js.LICENSE.txt → main.1fa50342.js.LICENSE.txt} +0 -0
package/dist/frontend.js
CHANGED
|
@@ -1,28 +1,4 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* This file contains the class Frontend.
|
|
3
|
-
*
|
|
4
|
-
* @file frontend.ts
|
|
5
|
-
* @author Luca Liguori
|
|
6
|
-
* @date 2025-01-13
|
|
7
|
-
* @version 1.0.2
|
|
8
|
-
*
|
|
9
|
-
* Copyright 2025, 2026, 2027 Luca Liguori.
|
|
10
|
-
*
|
|
11
|
-
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
12
|
-
* you may not use this file except in compliance with the License.
|
|
13
|
-
* You may obtain a copy of the License at
|
|
14
|
-
*
|
|
15
|
-
* http://www.apache.org/licenses/LICENSE-2.0
|
|
16
|
-
*
|
|
17
|
-
* Unless required by applicable law or agreed to in writing, software
|
|
18
|
-
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
19
|
-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
20
|
-
* See the License for the specific language governing permissions and
|
|
21
|
-
* limitations under the License. *
|
|
22
|
-
*/
|
|
23
|
-
// @matter
|
|
24
1
|
import { EndpointServer, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, Lifecycle } from '@matter/main';
|
|
25
|
-
// Node modules
|
|
26
2
|
import { createServer } from 'node:http';
|
|
27
3
|
import os from 'node:os';
|
|
28
4
|
import path from 'node:path';
|
|
@@ -31,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) {
|
|
@@ -1242,6 +1048,10 @@ export class Frontend {
|
|
|
1242
1048
|
version: plugin.version,
|
|
1243
1049
|
description: plugin.description,
|
|
1244
1050
|
author: plugin.author,
|
|
1051
|
+
homepage: plugin.homepage,
|
|
1052
|
+
help: plugin.help,
|
|
1053
|
+
changelog: plugin.changelog,
|
|
1054
|
+
funding: plugin.funding,
|
|
1245
1055
|
latestVersion: plugin.latestVersion,
|
|
1246
1056
|
locked: plugin.locked,
|
|
1247
1057
|
error: plugin.error,
|
|
@@ -1264,13 +1074,6 @@ export class Frontend {
|
|
|
1264
1074
|
}
|
|
1265
1075
|
return baseRegisteredPlugins;
|
|
1266
1076
|
}
|
|
1267
|
-
/**
|
|
1268
|
-
* Handles incoming websocket messages for the Matterbridge frontend.
|
|
1269
|
-
*
|
|
1270
|
-
* @param {WebSocket} client - The websocket client that sent the message.
|
|
1271
|
-
* @param {WebSocket.RawData} message - The raw data of the message received from the client.
|
|
1272
|
-
* @returns {Promise<void>} A promise that resolves when the message has been handled.
|
|
1273
|
-
*/
|
|
1274
1077
|
async wsMessageHandler(client, message) {
|
|
1275
1078
|
let data;
|
|
1276
1079
|
try {
|
|
@@ -1426,10 +1229,8 @@ export class Frontend {
|
|
|
1426
1229
|
else if (data.method === '/api/devices') {
|
|
1427
1230
|
const devices = [];
|
|
1428
1231
|
this.matterbridge.devices.forEach(async (device) => {
|
|
1429
|
-
// Filter by pluginName if provided
|
|
1430
1232
|
if (data.params.pluginName && data.params.pluginName !== device.plugin)
|
|
1431
1233
|
return;
|
|
1432
|
-
// Check if the device has the required properties
|
|
1433
1234
|
if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
|
|
1434
1235
|
return;
|
|
1435
1236
|
const cluster = this.getClusterTextFromDevice(device);
|
|
@@ -1513,7 +1314,6 @@ export class Frontend {
|
|
|
1513
1314
|
});
|
|
1514
1315
|
endpointServer.getChildEndpoints().forEach((childEndpoint) => {
|
|
1515
1316
|
deviceTypes = [];
|
|
1516
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1517
1317
|
const name = childEndpoint.endpoint?.id;
|
|
1518
1318
|
const clusterServers = childEndpoint.getAllClusterServers();
|
|
1519
1319
|
clusterServers.forEach((clusterServer) => {
|
|
@@ -1567,7 +1367,6 @@ export class Frontend {
|
|
|
1567
1367
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Plugin not found in /api/select' }));
|
|
1568
1368
|
return;
|
|
1569
1369
|
}
|
|
1570
|
-
// const selectDeviceValues = plugin.platform?.selectDevice ? Array.from(plugin.platform.selectDevice.values()).sort((keyA, keyB) => keyA.name.localeCompare(keyB.name)) : [];
|
|
1571
1370
|
const selectDeviceValues = plugin.platform?.getSelectDevices().sort((keyA, keyB) => keyA.name.localeCompare(keyB.name));
|
|
1572
1371
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, plugin: data.params.plugin, response: selectDeviceValues }));
|
|
1573
1372
|
return;
|
|
@@ -1582,7 +1381,6 @@ export class Frontend {
|
|
|
1582
1381
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Plugin not found in /api/select/entities' }));
|
|
1583
1382
|
return;
|
|
1584
1383
|
}
|
|
1585
|
-
// const selectEntityValues = plugin.platform?.selectDevice ? Array.from(plugin.platform.selectEntity.values()).sort((keyA, keyB) => keyA.name.localeCompare(keyB.name)) : [];
|
|
1586
1384
|
const selectEntityValues = plugin.platform?.getSelectEntities().sort((keyA, keyB) => keyA.name.localeCompare(keyB.name));
|
|
1587
1385
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, plugin: data.params.plugin, response: selectEntityValues }));
|
|
1588
1386
|
return;
|
|
@@ -1614,7 +1412,6 @@ export class Frontend {
|
|
|
1614
1412
|
return;
|
|
1615
1413
|
}
|
|
1616
1414
|
const config = plugin.configJson;
|
|
1617
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1618
1415
|
const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
|
|
1619
1416
|
this.log.debug(`SelectDevice(selectMode ${select}) data ${debugStringify(data)}`);
|
|
1620
1417
|
if (select === 'serial')
|
|
@@ -1622,11 +1419,9 @@ export class Frontend {
|
|
|
1622
1419
|
if (select === 'name')
|
|
1623
1420
|
this.log.info(`Selected device name ${data.params.name}`);
|
|
1624
1421
|
if (config && select && (select === 'serial' || select === 'name')) {
|
|
1625
|
-
// Remove postfix from the serial if it exists
|
|
1626
1422
|
if (config.postfix) {
|
|
1627
1423
|
data.params.serial = data.params.serial.replace('-' + config.postfix, '');
|
|
1628
1424
|
}
|
|
1629
|
-
// Add the serial to the whiteList if the whiteList exists and the serial or name is not already in it
|
|
1630
1425
|
if (isValidArray(config.whiteList, 1)) {
|
|
1631
1426
|
if (select === 'serial' && !config.whiteList.includes(data.params.serial)) {
|
|
1632
1427
|
config.whiteList.push(data.params.serial);
|
|
@@ -1635,7 +1430,6 @@ export class Frontend {
|
|
|
1635
1430
|
config.whiteList.push(data.params.name);
|
|
1636
1431
|
}
|
|
1637
1432
|
}
|
|
1638
|
-
// Remove the serial from the blackList if the blackList exists and the serial or name is in it
|
|
1639
1433
|
if (isValidArray(config.blackList, 1)) {
|
|
1640
1434
|
if (select === 'serial' && config.blackList.includes(data.params.serial)) {
|
|
1641
1435
|
config.blackList = config.blackList.filter((serial) => serial !== data.params.serial);
|
|
@@ -1657,7 +1451,6 @@ export class Frontend {
|
|
|
1657
1451
|
return;
|
|
1658
1452
|
}
|
|
1659
1453
|
const config = plugin.configJson;
|
|
1660
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1661
1454
|
const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
|
|
1662
1455
|
this.log.debug(`UnselectDevice(selectMode ${select}) data ${debugStringify(data)}`);
|
|
1663
1456
|
if (select === 'serial')
|
|
@@ -1668,7 +1461,6 @@ export class Frontend {
|
|
|
1668
1461
|
if (config.postfix) {
|
|
1669
1462
|
data.params.serial = data.params.serial.replace('-' + config.postfix, '');
|
|
1670
1463
|
}
|
|
1671
|
-
// Remove the serial from the whiteList if the whiteList exists and the serial is in it
|
|
1672
1464
|
if (isValidArray(config.whiteList, 1)) {
|
|
1673
1465
|
if (select === 'serial' && config.whiteList.includes(data.params.serial)) {
|
|
1674
1466
|
config.whiteList = config.whiteList.filter((serial) => serial !== data.params.serial);
|
|
@@ -1677,7 +1469,6 @@ export class Frontend {
|
|
|
1677
1469
|
config.whiteList = config.whiteList.filter((name) => name !== data.params.name);
|
|
1678
1470
|
}
|
|
1679
1471
|
}
|
|
1680
|
-
// Add the serial to the blackList
|
|
1681
1472
|
if (isValidArray(config.blackList)) {
|
|
1682
1473
|
if (select === 'serial' && !config.blackList.includes(data.params.serial)) {
|
|
1683
1474
|
config.blackList.push(data.params.serial);
|
|
@@ -1704,194 +1495,102 @@ export class Frontend {
|
|
|
1704
1495
|
return;
|
|
1705
1496
|
}
|
|
1706
1497
|
}
|
|
1707
|
-
/**
|
|
1708
|
-
* Sends a WebSocket message to all connected clients. The function is called by AnsiLogger.setGlobalCallback.
|
|
1709
|
-
*
|
|
1710
|
-
* @param {string} level - The logger level of the message: debug info notice warn error fatal...
|
|
1711
|
-
* @param {string} time - The time string of the message
|
|
1712
|
-
* @param {string} name - The logger name of the message
|
|
1713
|
-
* @param {string} message - The content of the message.
|
|
1714
|
-
*/
|
|
1715
1498
|
wssSendMessage(level, time, name, message) {
|
|
1716
1499
|
if (!level || !time || !name || !message)
|
|
1717
1500
|
return;
|
|
1718
|
-
// Remove ANSI escape codes from the message
|
|
1719
|
-
// eslint-disable-next-line no-control-regex
|
|
1720
1501
|
message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
|
|
1721
|
-
// Remove leading asterisks from the message
|
|
1722
1502
|
message = message.replace(/^\*+/, '');
|
|
1723
|
-
// Replace all occurrences of \t and \n
|
|
1724
1503
|
message = message.replace(/[\t\n]/g, '');
|
|
1725
|
-
// Remove non-printable characters
|
|
1726
|
-
// eslint-disable-next-line no-control-regex
|
|
1727
1504
|
message = message.replace(/[\x00-\x1F\x7F]/g, '');
|
|
1728
|
-
// Replace all occurrences of \" with "
|
|
1729
1505
|
message = message.replace(/\\"/g, '"');
|
|
1730
|
-
// Define the maximum allowed length for continuous characters without a space
|
|
1731
1506
|
const maxContinuousLength = 100;
|
|
1732
1507
|
const keepStartLength = 20;
|
|
1733
1508
|
const keepEndLength = 20;
|
|
1734
|
-
// Split the message into words
|
|
1735
1509
|
message = message
|
|
1736
1510
|
.split(' ')
|
|
1737
1511
|
.map((word) => {
|
|
1738
|
-
// If the word length exceeds the max continuous length, insert spaces and truncate
|
|
1739
1512
|
if (word.length > maxContinuousLength) {
|
|
1740
1513
|
return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
|
|
1741
1514
|
}
|
|
1742
1515
|
return word;
|
|
1743
1516
|
})
|
|
1744
1517
|
.join(' ');
|
|
1745
|
-
// Send the message to all connected clients
|
|
1746
1518
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1747
1519
|
if (client.readyState === WebSocket.OPEN) {
|
|
1748
1520
|
client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
|
|
1749
1521
|
}
|
|
1750
1522
|
});
|
|
1751
1523
|
}
|
|
1752
|
-
/**
|
|
1753
|
-
* Sends a need to refresh WebSocket message to all connected clients.
|
|
1754
|
-
*
|
|
1755
|
-
* @param {string} changed - The changed value. If null, the whole page will be refreshed.
|
|
1756
|
-
* possible values:
|
|
1757
|
-
* - 'matterbridgeLatestVersion'
|
|
1758
|
-
* - 'matterbridgeAdvertise'
|
|
1759
|
-
* - 'online'
|
|
1760
|
-
* - 'offline'
|
|
1761
|
-
* - 'reachability'
|
|
1762
|
-
* - 'settings'
|
|
1763
|
-
* - 'plugins'
|
|
1764
|
-
* - 'devices'
|
|
1765
|
-
* - 'fabrics'
|
|
1766
|
-
* - 'sessions'
|
|
1767
|
-
*/
|
|
1768
1524
|
wssSendRefreshRequired(changed = null) {
|
|
1769
1525
|
this.log.debug('Sending a refresh required message to all connected clients');
|
|
1770
|
-
// Send the message to all connected clients
|
|
1771
1526
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1772
1527
|
if (client.readyState === WebSocket.OPEN) {
|
|
1773
1528
|
client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', params: { changed: changed } }));
|
|
1774
1529
|
}
|
|
1775
1530
|
});
|
|
1776
1531
|
}
|
|
1777
|
-
/**
|
|
1778
|
-
* Sends a need to restart WebSocket message to all connected clients.
|
|
1779
|
-
*
|
|
1780
|
-
*/
|
|
1781
1532
|
wssSendRestartRequired(snackbar = true) {
|
|
1782
1533
|
this.log.debug('Sending a restart required message to all connected clients');
|
|
1783
1534
|
this.matterbridge.matterbridgeInformation.restartRequired = true;
|
|
1784
1535
|
if (snackbar === true)
|
|
1785
1536
|
this.wssSendSnackbarMessage(`Restart required`, 0);
|
|
1786
|
-
// Send the message to all connected clients
|
|
1787
1537
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1788
1538
|
if (client.readyState === WebSocket.OPEN) {
|
|
1789
1539
|
client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', params: {} }));
|
|
1790
1540
|
}
|
|
1791
1541
|
});
|
|
1792
1542
|
}
|
|
1793
|
-
/**
|
|
1794
|
-
* Sends a need to update WebSocket message to all connected clients.
|
|
1795
|
-
*
|
|
1796
|
-
*/
|
|
1797
1543
|
wssSendUpdateRequired() {
|
|
1798
1544
|
this.log.debug('Sending an update required message to all connected clients');
|
|
1799
1545
|
this.matterbridge.matterbridgeInformation.updateRequired = true;
|
|
1800
|
-
// Send the message to all connected clients
|
|
1801
1546
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1802
1547
|
if (client.readyState === WebSocket.OPEN) {
|
|
1803
1548
|
client.send(JSON.stringify({ id: WS_ID_UPDATE_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'update_required', params: {} }));
|
|
1804
1549
|
}
|
|
1805
1550
|
});
|
|
1806
1551
|
}
|
|
1807
|
-
/**
|
|
1808
|
-
* Sends a memory update message to all connected clients.
|
|
1809
|
-
*
|
|
1810
|
-
*/
|
|
1811
1552
|
wssSendCpuUpdate(cpuUsage) {
|
|
1812
1553
|
this.log.debug('Sending a cpu update message to all connected clients');
|
|
1813
|
-
// Send the message to all connected clients
|
|
1814
1554
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1815
1555
|
if (client.readyState === WebSocket.OPEN) {
|
|
1816
1556
|
client.send(JSON.stringify({ id: WS_ID_CPU_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'cpu_update', params: { cpuUsage } }));
|
|
1817
1557
|
}
|
|
1818
1558
|
});
|
|
1819
1559
|
}
|
|
1820
|
-
/**
|
|
1821
|
-
* Sends a cpu update message to all connected clients.
|
|
1822
|
-
*
|
|
1823
|
-
*/
|
|
1824
1560
|
wssSendMemoryUpdate(totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers) {
|
|
1825
1561
|
this.log.debug('Sending a memory update message to all connected clients');
|
|
1826
|
-
// Send the message to all connected clients
|
|
1827
1562
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1828
1563
|
if (client.readyState === WebSocket.OPEN) {
|
|
1829
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 } }));
|
|
1830
1565
|
}
|
|
1831
1566
|
});
|
|
1832
1567
|
}
|
|
1833
|
-
/**
|
|
1834
|
-
* Sends a memory update message to all connected clients.
|
|
1835
|
-
*
|
|
1836
|
-
*/
|
|
1837
1568
|
wssSendUptimeUpdate(systemUptime, processUptime) {
|
|
1838
1569
|
this.log.debug('Sending a uptime update message to all connected clients');
|
|
1839
|
-
// Send the message to all connected clients
|
|
1840
1570
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1841
1571
|
if (client.readyState === WebSocket.OPEN) {
|
|
1842
1572
|
client.send(JSON.stringify({ id: WS_ID_UPTIME_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'uptime_update', params: { systemUptime, processUptime } }));
|
|
1843
1573
|
}
|
|
1844
1574
|
});
|
|
1845
1575
|
}
|
|
1846
|
-
/**
|
|
1847
|
-
* Sends a cpu update message to all connected clients.
|
|
1848
|
-
* @param {string} message - The message to send.
|
|
1849
|
-
* @param {number} timeout - The timeout in seconds for the snackbar message.
|
|
1850
|
-
* @param {'info' | 'warning' | 'error' | 'success'} severity - The severity of the snackbar message (default info).
|
|
1851
|
-
*
|
|
1852
|
-
*/
|
|
1853
1576
|
wssSendSnackbarMessage(message, timeout = 5, severity = 'info') {
|
|
1854
1577
|
this.log.debug('Sending a snackbar message to all connected clients');
|
|
1855
|
-
// Send the message to all connected clients
|
|
1856
1578
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1857
1579
|
if (client.readyState === WebSocket.OPEN) {
|
|
1858
1580
|
client.send(JSON.stringify({ id: WS_ID_SNACKBAR, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', params: { message, timeout, severity } }));
|
|
1859
1581
|
}
|
|
1860
1582
|
});
|
|
1861
1583
|
}
|
|
1862
|
-
/**
|
|
1863
|
-
* Sends an attribute update message to all connected WebSocket clients.
|
|
1864
|
-
*
|
|
1865
|
-
* @param {string | undefined} plugin - The name of the plugin.
|
|
1866
|
-
* @param {string | undefined} serialNumber - The serial number of the device.
|
|
1867
|
-
* @param {string | undefined} uniqueId - The unique identifier of the device.
|
|
1868
|
-
* @param {string} cluster - The cluster name where the attribute belongs.
|
|
1869
|
-
* @param {string} attribute - The name of the attribute that changed.
|
|
1870
|
-
* @param {number | string | boolean} value - The new value of the attribute.
|
|
1871
|
-
*
|
|
1872
|
-
* @remarks
|
|
1873
|
-
* This method logs a debug message and sends a JSON-formatted message to all connected WebSocket clients
|
|
1874
|
-
* with the updated attribute information.
|
|
1875
|
-
*/
|
|
1876
1584
|
wssSendAttributeChangedMessage(plugin, serialNumber, uniqueId, cluster, attribute, value) {
|
|
1877
1585
|
this.log.debug('Sending an attribute update message to all connected clients');
|
|
1878
|
-
// Send the message to all connected clients
|
|
1879
1586
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1880
1587
|
if (client.readyState === WebSocket.OPEN) {
|
|
1881
1588
|
client.send(JSON.stringify({ id: WS_ID_STATEUPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'state_update', params: { plugin, serialNumber, uniqueId, cluster, attribute, value } }));
|
|
1882
1589
|
}
|
|
1883
1590
|
});
|
|
1884
1591
|
}
|
|
1885
|
-
/**
|
|
1886
|
-
* Sends a message to all connected clients.
|
|
1887
|
-
* @param {number} id - The message id.
|
|
1888
|
-
* @param {string} method - The message method.
|
|
1889
|
-
* @param {Record<string, string | number | boolean>} params - The message parameters.
|
|
1890
|
-
*
|
|
1891
|
-
*/
|
|
1892
1592
|
wssBroadcastMessage(id, method, params) {
|
|
1893
1593
|
this.log.debug(`Sending a broadcast message id ${id} method ${method} params ${debugStringify(params ?? {})} to all connected clients`);
|
|
1894
|
-
// Send the message to all connected clients
|
|
1895
1594
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1896
1595
|
if (client.readyState === WebSocket.OPEN) {
|
|
1897
1596
|
client.send(JSON.stringify({ id, src: 'Matterbridge', dst: 'Frontend', method, params }));
|
|
@@ -1899,4 +1598,3 @@ export class Frontend {
|
|
|
1899
1598
|
});
|
|
1900
1599
|
}
|
|
1901
1600
|
}
|
|
1902
|
-
//# sourceMappingURL=frontend.js.map
|