matterbridge 2.2.8 → 2.2.9-dev.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 +20 -1
- package/dist/cli.js +2 -37
- package/dist/cluster/export.js +0 -2
- package/dist/defaultConfigSchema.js +0 -23
- package/dist/deviceManager.js +1 -94
- package/dist/frontend.js +19 -326
- 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 +51 -747
- package/dist/matterbridgeAccessoryPlatform.js +0 -33
- package/dist/matterbridgeBehaviors.js +1 -32
- package/dist/matterbridgeDeviceTypes.js +11 -112
- package/dist/matterbridgeDynamicPlatform.js +0 -33
- package/dist/matterbridgeEndpoint.js +6 -720
- package/dist/matterbridgeEndpointHelpers.js +9 -118
- package/dist/matterbridgePlatform.js +7 -216
- 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/frontend/build/asset-manifest.json +3 -3
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/js/{main.e11d6bb4.js → main.ff47208e.js} +3 -3
- package/frontend/build/static/js/{main.e11d6bb4.js.map → main.ff47208e.js.map} +1 -1
- package/npm-shrinkwrap.json +9 -9
- package/package.json +1 -2
- package/dist/cli.d.ts +0 -29
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cluster/export.d.ts +0 -2
- package/dist/cluster/export.d.ts.map +0 -1
- package/dist/cluster/export.js.map +0 -1
- package/dist/defaultConfigSchema.d.ts +0 -27
- package/dist/defaultConfigSchema.d.ts.map +0 -1
- package/dist/defaultConfigSchema.js.map +0 -1
- package/dist/deviceManager.d.ts +0 -114
- package/dist/deviceManager.d.ts.map +0 -1
- package/dist/deviceManager.js.map +0 -1
- package/dist/frontend.d.ts +0 -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 -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/frontend/build/static/js/{main.e11d6bb4.js.LICENSE.txt → main.ff47208e.js.LICENSE.txt} +0 -0
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,7 +814,6 @@ export class Frontend {
|
|
|
977
814
|
res.status(500).send(`Error uploading or installing plugin package ${filename}`);
|
|
978
815
|
}
|
|
979
816
|
});
|
|
980
|
-
// Fallback for routing (must be the last route)
|
|
981
817
|
this.expressApp.get('*', (req, res) => {
|
|
982
818
|
this.log.debug('The frontend sent:', req.url);
|
|
983
819
|
this.log.debug('Response send file:', path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
|
|
@@ -986,31 +822,24 @@ export class Frontend {
|
|
|
986
822
|
this.log.debug(`Frontend initialized on port ${YELLOW}${this.port}${db} static ${UNDERLINE}${path.join(this.matterbridge.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
|
|
987
823
|
}
|
|
988
824
|
async stop() {
|
|
989
|
-
// Remove all listeners from the cliEmitter
|
|
990
|
-
// cliEmitter.removeAllListeners();
|
|
991
|
-
// Close the http server
|
|
992
825
|
if (this.httpServer) {
|
|
993
826
|
this.httpServer.close();
|
|
994
827
|
this.httpServer.removeAllListeners();
|
|
995
828
|
this.httpServer = undefined;
|
|
996
829
|
this.log.debug('Frontend http server closed successfully');
|
|
997
830
|
}
|
|
998
|
-
// Close the https server
|
|
999
831
|
if (this.httpsServer) {
|
|
1000
832
|
this.httpsServer.close();
|
|
1001
833
|
this.httpsServer.removeAllListeners();
|
|
1002
834
|
this.httpsServer = undefined;
|
|
1003
835
|
this.log.debug('Frontend https server closed successfully');
|
|
1004
836
|
}
|
|
1005
|
-
// Remove listeners from the express app
|
|
1006
837
|
if (this.expressApp) {
|
|
1007
838
|
this.expressApp.removeAllListeners();
|
|
1008
839
|
this.expressApp = undefined;
|
|
1009
840
|
this.log.debug('Frontend app closed successfully');
|
|
1010
841
|
}
|
|
1011
|
-
// Close the WebSocket server
|
|
1012
842
|
if (this.webSocketServer) {
|
|
1013
|
-
// Close all active connections
|
|
1014
843
|
this.webSocketServer.clients.forEach((client) => {
|
|
1015
844
|
if (client.readyState === WebSocket.OPEN) {
|
|
1016
845
|
client.close();
|
|
@@ -1027,7 +856,6 @@ export class Frontend {
|
|
|
1027
856
|
this.webSocketServer = undefined;
|
|
1028
857
|
}
|
|
1029
858
|
}
|
|
1030
|
-
// Function to format bytes to KB, MB, or GB
|
|
1031
859
|
formatMemoryUsage = (bytes) => {
|
|
1032
860
|
if (bytes >= 1024 ** 3) {
|
|
1033
861
|
return `${(bytes / 1024 ** 3).toFixed(2)} GB`;
|
|
@@ -1039,7 +867,6 @@ export class Frontend {
|
|
|
1039
867
|
return `${(bytes / 1024).toFixed(2)} KB`;
|
|
1040
868
|
}
|
|
1041
869
|
};
|
|
1042
|
-
// Function to format system uptime with only the most significant unit
|
|
1043
870
|
formatOsUpTime = (seconds) => {
|
|
1044
871
|
if (seconds >= 86400) {
|
|
1045
872
|
const days = Math.floor(seconds / 86400);
|
|
@@ -1055,13 +882,8 @@ export class Frontend {
|
|
|
1055
882
|
}
|
|
1056
883
|
return `${seconds} second${seconds !== 1 ? 's' : ''}`;
|
|
1057
884
|
};
|
|
1058
|
-
/**
|
|
1059
|
-
* Retrieves the api settings data.
|
|
1060
|
-
* @returns {Promise<object>} A promise that resolve in the api settings object.
|
|
1061
|
-
*/
|
|
1062
885
|
async getApiSettings() {
|
|
1063
886
|
const { lastCpuUsage } = await import('./cli.js');
|
|
1064
|
-
// Update the system information
|
|
1065
887
|
this.matterbridge.systemInformation.totalMemory = this.formatMemoryUsage(os.totalmem());
|
|
1066
888
|
this.matterbridge.systemInformation.freeMemory = this.formatMemoryUsage(os.freemem());
|
|
1067
889
|
this.matterbridge.systemInformation.systemUptime = this.formatOsUpTime(os.uptime());
|
|
@@ -1070,7 +892,6 @@ export class Frontend {
|
|
|
1070
892
|
this.matterbridge.systemInformation.rss = this.formatMemoryUsage(process.memoryUsage().rss);
|
|
1071
893
|
this.matterbridge.systemInformation.heapTotal = this.formatMemoryUsage(process.memoryUsage().heapTotal);
|
|
1072
894
|
this.matterbridge.systemInformation.heapUsed = this.formatMemoryUsage(process.memoryUsage().heapUsed);
|
|
1073
|
-
// Update the matterbridge information
|
|
1074
895
|
this.matterbridge.matterbridgeInformation.bridgeMode = this.matterbridge.bridgeMode;
|
|
1075
896
|
this.matterbridge.matterbridgeInformation.restartMode = this.matterbridge.restartMode;
|
|
1076
897
|
this.matterbridge.matterbridgeInformation.loggerLevel = this.matterbridge.log.logLevel;
|
|
@@ -1089,11 +910,6 @@ export class Frontend {
|
|
|
1089
910
|
this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
|
|
1090
911
|
return { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: this.matterbridge.matterbridgeInformation };
|
|
1091
912
|
}
|
|
1092
|
-
/**
|
|
1093
|
-
* Retrieves the reachable attribute.
|
|
1094
|
-
* @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
|
|
1095
|
-
* @returns {boolean} The reachable attribute.
|
|
1096
|
-
*/
|
|
1097
913
|
getReachability(device) {
|
|
1098
914
|
if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
|
|
1099
915
|
return false;
|
|
@@ -1103,11 +919,6 @@ export class Frontend {
|
|
|
1103
919
|
return true;
|
|
1104
920
|
return false;
|
|
1105
921
|
}
|
|
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
922
|
getClusterTextFromDevice(device) {
|
|
1112
923
|
if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
|
|
1113
924
|
return '';
|
|
@@ -1148,7 +959,6 @@ export class Frontend {
|
|
|
1148
959
|
};
|
|
1149
960
|
let attributes = '';
|
|
1150
961
|
device.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
|
|
1151
|
-
// console.log(`${device.deviceName} => Cluster: ${clusterName}-${clusterId} Attribute: ${attributeName}-${attributeId} Value(${typeof attributeValue}): ${attributeValue}`);
|
|
1152
962
|
if (typeof attributeValue === 'undefined')
|
|
1153
963
|
return;
|
|
1154
964
|
if (clusterName === 'onOff' && attributeName === 'onOff')
|
|
@@ -1226,13 +1036,8 @@ export class Frontend {
|
|
|
1226
1036
|
if (clusterName === 'userLabel' && attributeName === 'labelList')
|
|
1227
1037
|
attributes += `${getUserLabel(device)} `;
|
|
1228
1038
|
});
|
|
1229
|
-
// console.log(`${device.deviceName}.forEachAttribute: ${attributes}`);
|
|
1230
1039
|
return attributes.trimStart().trimEnd();
|
|
1231
1040
|
}
|
|
1232
|
-
/**
|
|
1233
|
-
* Retrieves the base registered plugins sanitized for res.json().
|
|
1234
|
-
* @returns {BaseRegisteredPlugin[]} An array of BaseRegisteredPlugin.
|
|
1235
|
-
*/
|
|
1236
1041
|
getBaseRegisteredPlugins() {
|
|
1237
1042
|
const baseRegisteredPlugins = [];
|
|
1238
1043
|
for (const plugin of this.matterbridge.plugins) {
|
|
@@ -1269,13 +1074,6 @@ export class Frontend {
|
|
|
1269
1074
|
}
|
|
1270
1075
|
return baseRegisteredPlugins;
|
|
1271
1076
|
}
|
|
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
1077
|
async wsMessageHandler(client, message) {
|
|
1280
1078
|
let data;
|
|
1281
1079
|
try {
|
|
@@ -1431,10 +1229,8 @@ export class Frontend {
|
|
|
1431
1229
|
else if (data.method === '/api/devices') {
|
|
1432
1230
|
const devices = [];
|
|
1433
1231
|
this.matterbridge.devices.forEach(async (device) => {
|
|
1434
|
-
// Filter by pluginName if provided
|
|
1435
1232
|
if (data.params.pluginName && data.params.pluginName !== device.plugin)
|
|
1436
1233
|
return;
|
|
1437
|
-
// Check if the device has the required properties
|
|
1438
1234
|
if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
|
|
1439
1235
|
return;
|
|
1440
1236
|
const cluster = this.getClusterTextFromDevice(device);
|
|
@@ -1518,7 +1314,6 @@ export class Frontend {
|
|
|
1518
1314
|
});
|
|
1519
1315
|
endpointServer.getChildEndpoints().forEach((childEndpoint) => {
|
|
1520
1316
|
deviceTypes = [];
|
|
1521
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1522
1317
|
const name = childEndpoint.endpoint?.id;
|
|
1523
1318
|
const clusterServers = childEndpoint.getAllClusterServers();
|
|
1524
1319
|
clusterServers.forEach((clusterServer) => {
|
|
@@ -1572,7 +1367,6 @@ export class Frontend {
|
|
|
1572
1367
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Plugin not found in /api/select' }));
|
|
1573
1368
|
return;
|
|
1574
1369
|
}
|
|
1575
|
-
// const selectDeviceValues = plugin.platform?.selectDevice ? Array.from(plugin.platform.selectDevice.values()).sort((keyA, keyB) => keyA.name.localeCompare(keyB.name)) : [];
|
|
1576
1370
|
const selectDeviceValues = plugin.platform?.getSelectDevices().sort((keyA, keyB) => keyA.name.localeCompare(keyB.name));
|
|
1577
1371
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, plugin: data.params.plugin, response: selectDeviceValues }));
|
|
1578
1372
|
return;
|
|
@@ -1587,7 +1381,6 @@ export class Frontend {
|
|
|
1587
1381
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, error: 'Plugin not found in /api/select/entities' }));
|
|
1588
1382
|
return;
|
|
1589
1383
|
}
|
|
1590
|
-
// const selectEntityValues = plugin.platform?.selectDevice ? Array.from(plugin.platform.selectEntity.values()).sort((keyA, keyB) => keyA.name.localeCompare(keyB.name)) : [];
|
|
1591
1384
|
const selectEntityValues = plugin.platform?.getSelectEntities().sort((keyA, keyB) => keyA.name.localeCompare(keyB.name));
|
|
1592
1385
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, plugin: data.params.plugin, response: selectEntityValues }));
|
|
1593
1386
|
return;
|
|
@@ -1619,7 +1412,6 @@ export class Frontend {
|
|
|
1619
1412
|
return;
|
|
1620
1413
|
}
|
|
1621
1414
|
const config = plugin.configJson;
|
|
1622
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1623
1415
|
const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
|
|
1624
1416
|
this.log.debug(`SelectDevice(selectMode ${select}) data ${debugStringify(data)}`);
|
|
1625
1417
|
if (select === 'serial')
|
|
@@ -1627,11 +1419,9 @@ export class Frontend {
|
|
|
1627
1419
|
if (select === 'name')
|
|
1628
1420
|
this.log.info(`Selected device name ${data.params.name}`);
|
|
1629
1421
|
if (config && select && (select === 'serial' || select === 'name')) {
|
|
1630
|
-
// Remove postfix from the serial if it exists
|
|
1631
1422
|
if (config.postfix) {
|
|
1632
1423
|
data.params.serial = data.params.serial.replace('-' + config.postfix, '');
|
|
1633
1424
|
}
|
|
1634
|
-
// Add the serial to the whiteList if the whiteList exists and the serial or name is not already in it
|
|
1635
1425
|
if (isValidArray(config.whiteList, 1)) {
|
|
1636
1426
|
if (select === 'serial' && !config.whiteList.includes(data.params.serial)) {
|
|
1637
1427
|
config.whiteList.push(data.params.serial);
|
|
@@ -1640,7 +1430,6 @@ export class Frontend {
|
|
|
1640
1430
|
config.whiteList.push(data.params.name);
|
|
1641
1431
|
}
|
|
1642
1432
|
}
|
|
1643
|
-
// Remove the serial from the blackList if the blackList exists and the serial or name is in it
|
|
1644
1433
|
if (isValidArray(config.blackList, 1)) {
|
|
1645
1434
|
if (select === 'serial' && config.blackList.includes(data.params.serial)) {
|
|
1646
1435
|
config.blackList = config.blackList.filter((serial) => serial !== data.params.serial);
|
|
@@ -1662,7 +1451,6 @@ export class Frontend {
|
|
|
1662
1451
|
return;
|
|
1663
1452
|
}
|
|
1664
1453
|
const config = plugin.configJson;
|
|
1665
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1666
1454
|
const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
|
|
1667
1455
|
this.log.debug(`UnselectDevice(selectMode ${select}) data ${debugStringify(data)}`);
|
|
1668
1456
|
if (select === 'serial')
|
|
@@ -1673,7 +1461,6 @@ export class Frontend {
|
|
|
1673
1461
|
if (config.postfix) {
|
|
1674
1462
|
data.params.serial = data.params.serial.replace('-' + config.postfix, '');
|
|
1675
1463
|
}
|
|
1676
|
-
// Remove the serial from the whiteList if the whiteList exists and the serial is in it
|
|
1677
1464
|
if (isValidArray(config.whiteList, 1)) {
|
|
1678
1465
|
if (select === 'serial' && config.whiteList.includes(data.params.serial)) {
|
|
1679
1466
|
config.whiteList = config.whiteList.filter((serial) => serial !== data.params.serial);
|
|
@@ -1682,7 +1469,6 @@ export class Frontend {
|
|
|
1682
1469
|
config.whiteList = config.whiteList.filter((name) => name !== data.params.name);
|
|
1683
1470
|
}
|
|
1684
1471
|
}
|
|
1685
|
-
// Add the serial to the blackList
|
|
1686
1472
|
if (isValidArray(config.blackList)) {
|
|
1687
1473
|
if (select === 'serial' && !config.blackList.includes(data.params.serial)) {
|
|
1688
1474
|
config.blackList.push(data.params.serial);
|
|
@@ -1709,194 +1495,102 @@ export class Frontend {
|
|
|
1709
1495
|
return;
|
|
1710
1496
|
}
|
|
1711
1497
|
}
|
|
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
1498
|
wssSendMessage(level, time, name, message) {
|
|
1721
1499
|
if (!level || !time || !name || !message)
|
|
1722
1500
|
return;
|
|
1723
|
-
// Remove ANSI escape codes from the message
|
|
1724
|
-
// eslint-disable-next-line no-control-regex
|
|
1725
1501
|
message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
|
|
1726
|
-
// Remove leading asterisks from the message
|
|
1727
1502
|
message = message.replace(/^\*+/, '');
|
|
1728
|
-
// Replace all occurrences of \t and \n
|
|
1729
1503
|
message = message.replace(/[\t\n]/g, '');
|
|
1730
|
-
// Remove non-printable characters
|
|
1731
|
-
// eslint-disable-next-line no-control-regex
|
|
1732
1504
|
message = message.replace(/[\x00-\x1F\x7F]/g, '');
|
|
1733
|
-
// Replace all occurrences of \" with "
|
|
1734
1505
|
message = message.replace(/\\"/g, '"');
|
|
1735
|
-
// Define the maximum allowed length for continuous characters without a space
|
|
1736
1506
|
const maxContinuousLength = 100;
|
|
1737
1507
|
const keepStartLength = 20;
|
|
1738
1508
|
const keepEndLength = 20;
|
|
1739
|
-
// Split the message into words
|
|
1740
1509
|
message = message
|
|
1741
1510
|
.split(' ')
|
|
1742
1511
|
.map((word) => {
|
|
1743
|
-
// If the word length exceeds the max continuous length, insert spaces and truncate
|
|
1744
1512
|
if (word.length > maxContinuousLength) {
|
|
1745
1513
|
return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
|
|
1746
1514
|
}
|
|
1747
1515
|
return word;
|
|
1748
1516
|
})
|
|
1749
1517
|
.join(' ');
|
|
1750
|
-
// Send the message to all connected clients
|
|
1751
1518
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1752
1519
|
if (client.readyState === WebSocket.OPEN) {
|
|
1753
1520
|
client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
|
|
1754
1521
|
}
|
|
1755
1522
|
});
|
|
1756
1523
|
}
|
|
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
1524
|
wssSendRefreshRequired(changed = null) {
|
|
1774
1525
|
this.log.debug('Sending a refresh required message to all connected clients');
|
|
1775
|
-
// Send the message to all connected clients
|
|
1776
1526
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1777
1527
|
if (client.readyState === WebSocket.OPEN) {
|
|
1778
1528
|
client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', params: { changed: changed } }));
|
|
1779
1529
|
}
|
|
1780
1530
|
});
|
|
1781
1531
|
}
|
|
1782
|
-
/**
|
|
1783
|
-
* Sends a need to restart WebSocket message to all connected clients.
|
|
1784
|
-
*
|
|
1785
|
-
*/
|
|
1786
1532
|
wssSendRestartRequired(snackbar = true) {
|
|
1787
1533
|
this.log.debug('Sending a restart required message to all connected clients');
|
|
1788
1534
|
this.matterbridge.matterbridgeInformation.restartRequired = true;
|
|
1789
1535
|
if (snackbar === true)
|
|
1790
1536
|
this.wssSendSnackbarMessage(`Restart required`, 0);
|
|
1791
|
-
// Send the message to all connected clients
|
|
1792
1537
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1793
1538
|
if (client.readyState === WebSocket.OPEN) {
|
|
1794
1539
|
client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', params: {} }));
|
|
1795
1540
|
}
|
|
1796
1541
|
});
|
|
1797
1542
|
}
|
|
1798
|
-
/**
|
|
1799
|
-
* Sends a need to update WebSocket message to all connected clients.
|
|
1800
|
-
*
|
|
1801
|
-
*/
|
|
1802
1543
|
wssSendUpdateRequired() {
|
|
1803
1544
|
this.log.debug('Sending an update required message to all connected clients');
|
|
1804
1545
|
this.matterbridge.matterbridgeInformation.updateRequired = true;
|
|
1805
|
-
// Send the message to all connected clients
|
|
1806
1546
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1807
1547
|
if (client.readyState === WebSocket.OPEN) {
|
|
1808
1548
|
client.send(JSON.stringify({ id: WS_ID_UPDATE_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'update_required', params: {} }));
|
|
1809
1549
|
}
|
|
1810
1550
|
});
|
|
1811
1551
|
}
|
|
1812
|
-
/**
|
|
1813
|
-
* Sends a memory update message to all connected clients.
|
|
1814
|
-
*
|
|
1815
|
-
*/
|
|
1816
1552
|
wssSendCpuUpdate(cpuUsage) {
|
|
1817
1553
|
this.log.debug('Sending a cpu update message to all connected clients');
|
|
1818
|
-
// Send the message to all connected clients
|
|
1819
1554
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1820
1555
|
if (client.readyState === WebSocket.OPEN) {
|
|
1821
1556
|
client.send(JSON.stringify({ id: WS_ID_CPU_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'cpu_update', params: { cpuUsage } }));
|
|
1822
1557
|
}
|
|
1823
1558
|
});
|
|
1824
1559
|
}
|
|
1825
|
-
/**
|
|
1826
|
-
* Sends a cpu update message to all connected clients.
|
|
1827
|
-
*
|
|
1828
|
-
*/
|
|
1829
1560
|
wssSendMemoryUpdate(totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers) {
|
|
1830
1561
|
this.log.debug('Sending a memory update message to all connected clients');
|
|
1831
|
-
// Send the message to all connected clients
|
|
1832
1562
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1833
1563
|
if (client.readyState === WebSocket.OPEN) {
|
|
1834
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 } }));
|
|
1835
1565
|
}
|
|
1836
1566
|
});
|
|
1837
1567
|
}
|
|
1838
|
-
/**
|
|
1839
|
-
* Sends a memory update message to all connected clients.
|
|
1840
|
-
*
|
|
1841
|
-
*/
|
|
1842
1568
|
wssSendUptimeUpdate(systemUptime, processUptime) {
|
|
1843
1569
|
this.log.debug('Sending a uptime update message to all connected clients');
|
|
1844
|
-
// Send the message to all connected clients
|
|
1845
1570
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1846
1571
|
if (client.readyState === WebSocket.OPEN) {
|
|
1847
1572
|
client.send(JSON.stringify({ id: WS_ID_UPTIME_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'uptime_update', params: { systemUptime, processUptime } }));
|
|
1848
1573
|
}
|
|
1849
1574
|
});
|
|
1850
1575
|
}
|
|
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
1576
|
wssSendSnackbarMessage(message, timeout = 5, severity = 'info') {
|
|
1859
1577
|
this.log.debug('Sending a snackbar message to all connected clients');
|
|
1860
|
-
// Send the message to all connected clients
|
|
1861
1578
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1862
1579
|
if (client.readyState === WebSocket.OPEN) {
|
|
1863
1580
|
client.send(JSON.stringify({ id: WS_ID_SNACKBAR, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', params: { message, timeout, severity } }));
|
|
1864
1581
|
}
|
|
1865
1582
|
});
|
|
1866
1583
|
}
|
|
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
1584
|
wssSendAttributeChangedMessage(plugin, serialNumber, uniqueId, cluster, attribute, value) {
|
|
1882
1585
|
this.log.debug('Sending an attribute update message to all connected clients');
|
|
1883
|
-
// Send the message to all connected clients
|
|
1884
1586
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1885
1587
|
if (client.readyState === WebSocket.OPEN) {
|
|
1886
1588
|
client.send(JSON.stringify({ id: WS_ID_STATEUPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'state_update', params: { plugin, serialNumber, uniqueId, cluster, attribute, value } }));
|
|
1887
1589
|
}
|
|
1888
1590
|
});
|
|
1889
1591
|
}
|
|
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
1592
|
wssBroadcastMessage(id, method, params) {
|
|
1898
1593
|
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
1594
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1901
1595
|
if (client.readyState === WebSocket.OPEN) {
|
|
1902
1596
|
client.send(JSON.stringify({ id, src: 'Matterbridge', dst: 'Frontend', method, params }));
|
|
@@ -1904,4 +1598,3 @@ export class Frontend {
|
|
|
1904
1598
|
});
|
|
1905
1599
|
}
|
|
1906
1600
|
}
|
|
1907
|
-
//# sourceMappingURL=frontend.js.map
|