matterbridge 3.0.0 → 3.0.1-dev-20250501-4f463f9
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 +2 -0
- package/README.md +22 -4
- 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 -352
- 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 +46 -747
- package/dist/matterbridgeAccessoryPlatform.js +0 -34
- package/dist/matterbridgeBehaviors.js +1 -33
- package/dist/matterbridgeDeviceTypes.js +12 -431
- package/dist/matterbridgeDynamicPlatform.js +0 -34
- package/dist/matterbridgeEndpoint.js +11 -794
- package/dist/matterbridgeEndpointHelpers.js +9 -142
- package/dist/matterbridgePlatform.js +7 -225
- 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 -52
- 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 -53
- 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.1d983660.js → main.356788d7.js} +3 -3
- package/frontend/build/static/js/{main.1d983660.js.map → main.356788d7.js.map} +1 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -2
- package/dist/cli.d.ts +0 -29
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/cluster/export.d.ts +0 -2
- package/dist/cluster/export.d.ts.map +0 -1
- package/dist/cluster/export.js.map +0 -1
- package/dist/defaultConfigSchema.d.ts +0 -27
- package/dist/defaultConfigSchema.d.ts.map +0 -1
- package/dist/defaultConfigSchema.js.map +0 -1
- package/dist/deviceManager.d.ts +0 -114
- package/dist/deviceManager.d.ts.map +0 -1
- package/dist/deviceManager.js.map +0 -1
- package/dist/frontend.d.ts +0 -222
- 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 -431
- package/dist/matterbridge.d.ts.map +0 -1
- package/dist/matterbridge.js.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.d.ts +0 -40
- package/dist/matterbridgeAccessoryPlatform.d.ts.map +0 -1
- package/dist/matterbridgeAccessoryPlatform.js.map +0 -1
- package/dist/matterbridgeBehaviors.d.ts +0 -1514
- package/dist/matterbridgeBehaviors.d.ts.map +0 -1
- package/dist/matterbridgeBehaviors.js.map +0 -1
- package/dist/matterbridgeDeviceTypes.d.ts +0 -494
- package/dist/matterbridgeDeviceTypes.d.ts.map +0 -1
- package/dist/matterbridgeDeviceTypes.js.map +0 -1
- package/dist/matterbridgeDynamicPlatform.d.ts +0 -40
- package/dist/matterbridgeDynamicPlatform.d.ts.map +0 -1
- package/dist/matterbridgeDynamicPlatform.js.map +0 -1
- package/dist/matterbridgeEndpoint.d.ts +0 -943
- package/dist/matterbridgeEndpoint.d.ts.map +0 -1
- package/dist/matterbridgeEndpoint.js.map +0 -1
- package/dist/matterbridgeEndpointHelpers.d.ts +0 -2706
- package/dist/matterbridgeEndpointHelpers.d.ts.map +0 -1
- package/dist/matterbridgeEndpointHelpers.js.map +0 -1
- package/dist/matterbridgePlatform.d.ts +0 -294
- package/dist/matterbridgePlatform.d.ts.map +0 -1
- package/dist/matterbridgePlatform.js.map +0 -1
- package/dist/matterbridgeTypes.d.ts +0 -187
- 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 -58
- 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.1d983660.js.LICENSE.txt → main.356788d7.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, PowerSource } 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,43 +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
|
-
// Inject logging/debug wrapper for route/middleware registration
|
|
136
|
-
/*
|
|
137
|
-
const methods = ['get', 'post', 'put', 'delete', 'use'];
|
|
138
|
-
for (const method of methods) {
|
|
139
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
140
|
-
const original = (this.expressApp as any)[method].bind(this.expressApp);
|
|
141
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
142
|
-
(this.expressApp as any)[method] = (path: any, ...rest: any) => {
|
|
143
|
-
try {
|
|
144
|
-
console.log(`[DEBUG] Registering ${method.toUpperCase()} route:`, path);
|
|
145
|
-
return original(path, ...rest);
|
|
146
|
-
} catch (err) {
|
|
147
|
-
console.error(`[ERROR] Failed to register route: ${path}`);
|
|
148
|
-
throw err;
|
|
149
|
-
}
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
|
-
*/
|
|
153
|
-
// Log all requests to the server for debugging
|
|
154
|
-
/*
|
|
155
|
-
this.expressApp.use((req, res, next) => {
|
|
156
|
-
this.log.debug(`***Received request on expressApp: ${req.method} ${req.url}`);
|
|
157
|
-
next();
|
|
158
|
-
});
|
|
159
|
-
*/
|
|
160
|
-
// Serve static files from '/static' endpoint
|
|
161
54
|
this.expressApp.use(express.static(path.join(this.matterbridge.rootDirectory, 'frontend/build')));
|
|
162
55
|
if (!hasParameter('ssl')) {
|
|
163
|
-
// Create an HTTP server and attach the express app
|
|
164
56
|
this.httpServer = createServer(this.expressApp);
|
|
165
|
-
// Listen on the specified port
|
|
166
57
|
if (hasParameter('ingress')) {
|
|
167
58
|
this.httpServer.listen(this.port, '0.0.0.0', () => {
|
|
168
59
|
this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
|
|
@@ -176,7 +67,6 @@ export class Frontend {
|
|
|
176
67
|
this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
|
|
177
68
|
});
|
|
178
69
|
}
|
|
179
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
180
70
|
this.httpServer.on('error', (error) => {
|
|
181
71
|
this.log.error(`Frontend http server error listening on ${this.port}`);
|
|
182
72
|
switch (error.code) {
|
|
@@ -192,7 +82,6 @@ export class Frontend {
|
|
|
192
82
|
});
|
|
193
83
|
}
|
|
194
84
|
else {
|
|
195
|
-
// Load the SSL certificate, the private key and optionally the CA certificate
|
|
196
85
|
let cert;
|
|
197
86
|
try {
|
|
198
87
|
cert = await fs.readFile(path.join(this.matterbridge.matterbridgeDirectory, 'certs/cert.pem'), 'utf8');
|
|
@@ -220,9 +109,7 @@ export class Frontend {
|
|
|
220
109
|
this.log.info(`CA certificate file ${path.join(this.matterbridge.matterbridgeDirectory, 'certs/ca.pem')} not loaded: ${error}`);
|
|
221
110
|
}
|
|
222
111
|
const serverOptions = { cert, key, ca };
|
|
223
|
-
// Create an HTTPS server with the SSL certificate and private key (ca is optional) and attach the express app
|
|
224
112
|
this.httpsServer = https.createServer(serverOptions, this.expressApp);
|
|
225
|
-
// Listen on the specified port
|
|
226
113
|
if (hasParameter('ingress')) {
|
|
227
114
|
this.httpsServer.listen(this.port, '0.0.0.0', () => {
|
|
228
115
|
this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
|
|
@@ -236,7 +123,6 @@ export class Frontend {
|
|
|
236
123
|
this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
|
|
237
124
|
});
|
|
238
125
|
}
|
|
239
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
240
126
|
this.httpsServer.on('error', (error) => {
|
|
241
127
|
this.log.error(`Frontend https server error listening on ${this.port}`);
|
|
242
128
|
switch (error.code) {
|
|
@@ -253,18 +139,16 @@ export class Frontend {
|
|
|
253
139
|
}
|
|
254
140
|
if (this.initializeError)
|
|
255
141
|
return;
|
|
256
|
-
// Create a WebSocket server and attach it to the http or https server
|
|
257
142
|
const wssPort = this.port;
|
|
258
143
|
const wssHost = hasParameter('ssl') ? `wss://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}` : `ws://${this.matterbridge.systemInformation.ipv4Address}:${wssPort}`;
|
|
259
144
|
this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
|
|
260
145
|
this.webSocketServer.on('connection', (ws, request) => {
|
|
261
146
|
const clientIp = request.socket.remoteAddress;
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
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";
|
|
268
152
|
AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), callbackLogLevel);
|
|
269
153
|
this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
|
|
270
154
|
this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
|
|
@@ -298,7 +182,6 @@ export class Frontend {
|
|
|
298
182
|
this.webSocketServer.on('error', (ws, error) => {
|
|
299
183
|
this.log.error(`WebSocketServer error: ${error}`);
|
|
300
184
|
});
|
|
301
|
-
// Subscribe to cli events
|
|
302
185
|
const { cliEmitter } = await import('./cli.js');
|
|
303
186
|
cliEmitter.removeAllListeners();
|
|
304
187
|
cliEmitter.on('uptime', (systemUptime, processUptime) => {
|
|
@@ -310,7 +193,6 @@ export class Frontend {
|
|
|
310
193
|
cliEmitter.on('cpu', (cpuUsage) => {
|
|
311
194
|
this.wssSendCpuUpdate(cpuUsage);
|
|
312
195
|
});
|
|
313
|
-
// Endpoint to validate login code
|
|
314
196
|
this.expressApp.post('/api/login', express.json(), async (req, res) => {
|
|
315
197
|
const { password } = req.body;
|
|
316
198
|
this.log.debug('The frontend sent /api/login', password);
|
|
@@ -329,27 +211,23 @@ export class Frontend {
|
|
|
329
211
|
this.log.warn('/api/login error wrong password');
|
|
330
212
|
res.json({ valid: false });
|
|
331
213
|
}
|
|
332
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
333
214
|
}
|
|
334
215
|
catch (error) {
|
|
335
216
|
this.log.error('/api/login error getting password');
|
|
336
217
|
res.json({ valid: false });
|
|
337
218
|
}
|
|
338
219
|
});
|
|
339
|
-
// Endpoint to provide health check
|
|
340
220
|
this.expressApp.get('/health', (req, res) => {
|
|
341
221
|
this.log.debug('Express received /health');
|
|
342
222
|
const healthStatus = {
|
|
343
|
-
status: 'ok',
|
|
344
|
-
uptime: process.uptime(),
|
|
345
|
-
timestamp: new Date().toISOString(),
|
|
223
|
+
status: 'ok',
|
|
224
|
+
uptime: process.uptime(),
|
|
225
|
+
timestamp: new Date().toISOString(),
|
|
346
226
|
};
|
|
347
227
|
res.status(200).json(healthStatus);
|
|
348
228
|
});
|
|
349
|
-
// Endpoint to provide memory usage details
|
|
350
229
|
this.expressApp.get('/memory', async (req, res) => {
|
|
351
230
|
this.log.debug('Express received /memory');
|
|
352
|
-
// Memory usage from process
|
|
353
231
|
const memoryUsageRaw = process.memoryUsage();
|
|
354
232
|
const memoryUsage = {
|
|
355
233
|
rss: this.formatMemoryUsage(memoryUsageRaw.rss),
|
|
@@ -358,13 +236,10 @@ export class Frontend {
|
|
|
358
236
|
external: this.formatMemoryUsage(memoryUsageRaw.external),
|
|
359
237
|
arrayBuffers: this.formatMemoryUsage(memoryUsageRaw.arrayBuffers),
|
|
360
238
|
};
|
|
361
|
-
// V8 heap statistics
|
|
362
239
|
const { default: v8 } = await import('node:v8');
|
|
363
240
|
const heapStatsRaw = v8.getHeapStatistics();
|
|
364
241
|
const heapSpacesRaw = v8.getHeapSpaceStatistics();
|
|
365
|
-
// Format heapStats
|
|
366
242
|
const heapStats = Object.fromEntries(Object.entries(heapStatsRaw).map(([key, value]) => [key, this.formatMemoryUsage(value)]));
|
|
367
|
-
// Format heapSpaces
|
|
368
243
|
const heapSpaces = heapSpacesRaw.map((space) => ({
|
|
369
244
|
...space,
|
|
370
245
|
space_size: this.formatMemoryUsage(space.space_size),
|
|
@@ -382,7 +257,6 @@ export class Frontend {
|
|
|
382
257
|
};
|
|
383
258
|
res.status(200).json(memoryReport);
|
|
384
259
|
});
|
|
385
|
-
// Endpoint to start advertising the server node
|
|
386
260
|
this.expressApp.get('/api/advertise', express.json(), async (req, res) => {
|
|
387
261
|
const pairingCodes = await this.matterbridge.advertiseServerNode(this.matterbridge.serverNode);
|
|
388
262
|
if (pairingCodes) {
|
|
@@ -393,22 +267,18 @@ export class Frontend {
|
|
|
393
267
|
res.status(500).json({ error: 'Failed to generate pairing codes' });
|
|
394
268
|
}
|
|
395
269
|
});
|
|
396
|
-
// Endpoint to provide settings
|
|
397
270
|
this.expressApp.get('/api/settings', express.json(), async (req, res) => {
|
|
398
271
|
this.log.debug('The frontend sent /api/settings');
|
|
399
272
|
res.json(await this.getApiSettings());
|
|
400
273
|
});
|
|
401
|
-
// Endpoint to provide plugins
|
|
402
274
|
this.expressApp.get('/api/plugins', async (req, res) => {
|
|
403
275
|
this.log.debug('The frontend sent /api/plugins');
|
|
404
276
|
res.json(this.getBaseRegisteredPlugins());
|
|
405
277
|
});
|
|
406
|
-
// Endpoint to provide devices
|
|
407
278
|
this.expressApp.get('/api/devices', (req, res) => {
|
|
408
279
|
this.log.debug('The frontend sent /api/devices');
|
|
409
280
|
const devices = [];
|
|
410
281
|
this.matterbridge.devices.forEach(async (device) => {
|
|
411
|
-
// Check if the device has the required properties
|
|
412
282
|
if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
|
|
413
283
|
return;
|
|
414
284
|
const cluster = this.getClusterTextFromDevice(device);
|
|
@@ -427,7 +297,6 @@ export class Frontend {
|
|
|
427
297
|
});
|
|
428
298
|
res.json(devices);
|
|
429
299
|
});
|
|
430
|
-
// Endpoint to provide the cluster servers of the devices
|
|
431
300
|
this.expressApp.get('/api/devices_clusters/:selectedPluginName/:selectedDeviceEndpoint', (req, res) => {
|
|
432
301
|
const selectedPluginName = req.params.selectedPluginName;
|
|
433
302
|
const selectedDeviceEndpoint = parseInt(req.params.selectedDeviceEndpoint, 10);
|
|
@@ -500,7 +369,6 @@ export class Frontend {
|
|
|
500
369
|
});
|
|
501
370
|
res.json(data);
|
|
502
371
|
});
|
|
503
|
-
// Endpoint to view the matterbridge log
|
|
504
372
|
this.expressApp.get('/api/view-mblog', async (req, res) => {
|
|
505
373
|
this.log.debug('The frontend sent /api/view-mblog');
|
|
506
374
|
try {
|
|
@@ -513,7 +381,6 @@ export class Frontend {
|
|
|
513
381
|
res.status(500).send('Error reading matterbridge log file. Please enable the matterbridge log on file in the settings.');
|
|
514
382
|
}
|
|
515
383
|
});
|
|
516
|
-
// Endpoint to view the matter.js log
|
|
517
384
|
this.expressApp.get('/api/view-mjlog', async (req, res) => {
|
|
518
385
|
this.log.debug('The frontend sent /api/view-mjlog');
|
|
519
386
|
try {
|
|
@@ -526,7 +393,6 @@ export class Frontend {
|
|
|
526
393
|
res.status(500).send('Error reading matter log file. Please enable the matter log on file in the settings.');
|
|
527
394
|
}
|
|
528
395
|
});
|
|
529
|
-
// Endpoint to view the shelly log
|
|
530
396
|
this.expressApp.get('/api/shellyviewsystemlog', async (req, res) => {
|
|
531
397
|
this.log.debug('The frontend sent /api/shellyviewsystemlog');
|
|
532
398
|
try {
|
|
@@ -539,7 +405,6 @@ export class Frontend {
|
|
|
539
405
|
res.status(500).send('Error reading shelly log file. Please create the shelly system log before loading it.');
|
|
540
406
|
}
|
|
541
407
|
});
|
|
542
|
-
// Endpoint to download the matterbridge log
|
|
543
408
|
this.expressApp.get('/api/download-mblog', async (req, res) => {
|
|
544
409
|
this.log.debug(`The frontend sent /api/download-mblog ${path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile)}`);
|
|
545
410
|
try {
|
|
@@ -552,7 +417,6 @@ export class Frontend {
|
|
|
552
417
|
this.log.debug(`Error in /api/download-mblog: ${error instanceof Error ? error.message : error}`);
|
|
553
418
|
}
|
|
554
419
|
res.type('text/plain');
|
|
555
|
-
// res.download(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), 'matterbridge.log', (error) => {
|
|
556
420
|
res.download(path.join(os.tmpdir(), this.matterbridge.matterbrideLoggerFile), 'matterbridge.log', (error) => {
|
|
557
421
|
if (error) {
|
|
558
422
|
this.log.error(`Error downloading log file ${this.matterbridge.matterbrideLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
@@ -560,7 +424,6 @@ export class Frontend {
|
|
|
560
424
|
}
|
|
561
425
|
});
|
|
562
426
|
});
|
|
563
|
-
// Endpoint to download the matter log
|
|
564
427
|
this.expressApp.get('/api/download-mjlog', async (req, res) => {
|
|
565
428
|
this.log.debug(`The frontend sent /api/download-mjlog ${path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile)}`);
|
|
566
429
|
try {
|
|
@@ -580,7 +443,6 @@ export class Frontend {
|
|
|
580
443
|
}
|
|
581
444
|
});
|
|
582
445
|
});
|
|
583
|
-
// Endpoint to download the shelly log
|
|
584
446
|
this.expressApp.get('/api/shellydownloadsystemlog', async (req, res) => {
|
|
585
447
|
this.log.debug('The frontend sent /api/shellydownloadsystemlog');
|
|
586
448
|
try {
|
|
@@ -600,7 +462,6 @@ export class Frontend {
|
|
|
600
462
|
}
|
|
601
463
|
});
|
|
602
464
|
});
|
|
603
|
-
// Endpoint to download the matter storage file
|
|
604
465
|
this.expressApp.get('/api/download-mjstorage', async (req, res) => {
|
|
605
466
|
this.log.debug('The frontend sent /api/download-mjstorage');
|
|
606
467
|
await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.matterStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterStorageName));
|
|
@@ -611,7 +472,6 @@ export class Frontend {
|
|
|
611
472
|
}
|
|
612
473
|
});
|
|
613
474
|
});
|
|
614
|
-
// Endpoint to download the matterbridge storage directory
|
|
615
475
|
this.expressApp.get('/api/download-mbstorage', async (req, res) => {
|
|
616
476
|
this.log.debug('The frontend sent /api/download-mbstorage');
|
|
617
477
|
await createZip(path.join(os.tmpdir(), `matterbridge.${this.matterbridge.nodeStorageName}.zip`), path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.nodeStorageName));
|
|
@@ -622,7 +482,6 @@ export class Frontend {
|
|
|
622
482
|
}
|
|
623
483
|
});
|
|
624
484
|
});
|
|
625
|
-
// Endpoint to download the matterbridge plugin directory
|
|
626
485
|
this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
|
|
627
486
|
this.log.debug('The frontend sent /api/download-pluginstorage');
|
|
628
487
|
await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridge.matterbridgePluginDirectory);
|
|
@@ -633,11 +492,9 @@ export class Frontend {
|
|
|
633
492
|
}
|
|
634
493
|
});
|
|
635
494
|
});
|
|
636
|
-
// Endpoint to download the matterbridge plugin config files
|
|
637
495
|
this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
|
|
638
496
|
this.log.debug('The frontend sent /api/download-pluginconfig');
|
|
639
497
|
await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridge.matterbridgeDirectory, '*.config.json')));
|
|
640
|
-
// 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')));
|
|
641
498
|
res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
|
|
642
499
|
if (error) {
|
|
643
500
|
this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
|
|
@@ -645,7 +502,6 @@ export class Frontend {
|
|
|
645
502
|
}
|
|
646
503
|
});
|
|
647
504
|
});
|
|
648
|
-
// Endpoint to download the matterbridge plugin config files
|
|
649
505
|
this.expressApp.get('/api/download-backup', async (req, res) => {
|
|
650
506
|
this.log.debug('The frontend sent /api/download-backup');
|
|
651
507
|
res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
|
|
@@ -655,7 +511,6 @@ export class Frontend {
|
|
|
655
511
|
}
|
|
656
512
|
});
|
|
657
513
|
});
|
|
658
|
-
// Endpoint to receive commands
|
|
659
514
|
this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
|
|
660
515
|
const command = req.params.command;
|
|
661
516
|
let param = req.params.param;
|
|
@@ -665,15 +520,13 @@ export class Frontend {
|
|
|
665
520
|
return;
|
|
666
521
|
}
|
|
667
522
|
this.log.debug(`Received frontend command: ${command}:${param}`);
|
|
668
|
-
// Handle the command setpassword from Settings
|
|
669
523
|
if (command === 'setpassword') {
|
|
670
|
-
const password = param.slice(1, -1);
|
|
524
|
+
const password = param.slice(1, -1);
|
|
671
525
|
this.log.debug('setpassword', param, password);
|
|
672
526
|
await this.matterbridge.nodeContext?.set('password', password);
|
|
673
527
|
res.json({ message: 'Command received' });
|
|
674
528
|
return;
|
|
675
529
|
}
|
|
676
|
-
// Handle the command setbridgemode from Settings
|
|
677
530
|
if (command === 'setbridgemode') {
|
|
678
531
|
this.log.debug(`setbridgemode: ${param}`);
|
|
679
532
|
this.wssSendRestartRequired();
|
|
@@ -681,7 +534,6 @@ export class Frontend {
|
|
|
681
534
|
res.json({ message: 'Command received' });
|
|
682
535
|
return;
|
|
683
536
|
}
|
|
684
|
-
// Handle the command backup from Settings
|
|
685
537
|
if (command === 'backup') {
|
|
686
538
|
this.log.notice(`Prepairing the backup...`);
|
|
687
539
|
await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridge.matterbridgeDirectory), path.join(this.matterbridge.matterbridgePluginDirectory));
|
|
@@ -690,33 +542,31 @@ export class Frontend {
|
|
|
690
542
|
res.json({ message: 'Command received' });
|
|
691
543
|
return;
|
|
692
544
|
}
|
|
693
|
-
// Handle the command setmbloglevel from Settings
|
|
694
545
|
if (command === 'setmbloglevel') {
|
|
695
546
|
this.log.debug('Matterbridge log level:', param);
|
|
696
547
|
if (param === 'Debug') {
|
|
697
|
-
this.log.logLevel = "debug"
|
|
548
|
+
this.log.logLevel = "debug";
|
|
698
549
|
}
|
|
699
550
|
else if (param === 'Info') {
|
|
700
|
-
this.log.logLevel = "info"
|
|
551
|
+
this.log.logLevel = "info";
|
|
701
552
|
}
|
|
702
553
|
else if (param === 'Notice') {
|
|
703
|
-
this.log.logLevel = "notice"
|
|
554
|
+
this.log.logLevel = "notice";
|
|
704
555
|
}
|
|
705
556
|
else if (param === 'Warn') {
|
|
706
|
-
this.log.logLevel = "warn"
|
|
557
|
+
this.log.logLevel = "warn";
|
|
707
558
|
}
|
|
708
559
|
else if (param === 'Error') {
|
|
709
|
-
this.log.logLevel = "error"
|
|
560
|
+
this.log.logLevel = "error";
|
|
710
561
|
}
|
|
711
562
|
else if (param === 'Fatal') {
|
|
712
|
-
this.log.logLevel = "fatal"
|
|
563
|
+
this.log.logLevel = "fatal";
|
|
713
564
|
}
|
|
714
565
|
await this.matterbridge.nodeContext?.set('matterbridgeLogLevel', this.log.logLevel);
|
|
715
566
|
await this.matterbridge.setLogLevel(this.log.logLevel);
|
|
716
567
|
res.json({ message: 'Command received' });
|
|
717
568
|
return;
|
|
718
569
|
}
|
|
719
|
-
// Handle the command setmbloglevel from Settings
|
|
720
570
|
if (command === 'setmjloglevel') {
|
|
721
571
|
this.log.debug('Matter.js log level:', param);
|
|
722
572
|
if (param === 'Debug') {
|
|
@@ -741,7 +591,6 @@ export class Frontend {
|
|
|
741
591
|
res.json({ message: 'Command received' });
|
|
742
592
|
return;
|
|
743
593
|
}
|
|
744
|
-
// Handle the command setmdnsinterface from Settings
|
|
745
594
|
if (command === 'setmdnsinterface') {
|
|
746
595
|
if (param === 'json' && isValidString(req.body.value)) {
|
|
747
596
|
this.matterbridge.matterbridgeInformation.mattermdnsinterface = req.body.value;
|
|
@@ -751,7 +600,6 @@ export class Frontend {
|
|
|
751
600
|
res.json({ message: 'Command received' });
|
|
752
601
|
return;
|
|
753
602
|
}
|
|
754
|
-
// Handle the command setipv4address from Settings
|
|
755
603
|
if (command === 'setipv4address') {
|
|
756
604
|
if (param === 'json' && isValidString(req.body.value)) {
|
|
757
605
|
this.log.debug(`Matter.js ipv4 address: ${req.body.value === '' ? 'all ipv4 addresses' : req.body.value}`);
|
|
@@ -761,7 +609,6 @@ export class Frontend {
|
|
|
761
609
|
res.json({ message: 'Command received' });
|
|
762
610
|
return;
|
|
763
611
|
}
|
|
764
|
-
// Handle the command setipv6address from Settings
|
|
765
612
|
if (command === 'setipv6address') {
|
|
766
613
|
if (param === 'json' && isValidString(req.body.value)) {
|
|
767
614
|
this.log.debug(`Matter.js ipv6 address: ${req.body.value === '' ? 'all ipv6 addresses' : req.body.value}`);
|
|
@@ -771,7 +618,6 @@ export class Frontend {
|
|
|
771
618
|
res.json({ message: 'Command received' });
|
|
772
619
|
return;
|
|
773
620
|
}
|
|
774
|
-
// Handle the command setmatterport from Settings
|
|
775
621
|
if (command === 'setmatterport') {
|
|
776
622
|
const port = Math.min(Math.max(parseInt(req.body.value), 5540), 5560);
|
|
777
623
|
this.matterbridge.matterbridgeInformation.matterPort = port;
|
|
@@ -780,7 +626,6 @@ export class Frontend {
|
|
|
780
626
|
res.json({ message: 'Command received' });
|
|
781
627
|
return;
|
|
782
628
|
}
|
|
783
|
-
// Handle the command setmatterdiscriminator from Settings
|
|
784
629
|
if (command === 'setmatterdiscriminator') {
|
|
785
630
|
const discriminator = Math.min(Math.max(parseInt(req.body.value), 1000), 4095);
|
|
786
631
|
this.matterbridge.matterbridgeInformation.matterDiscriminator = discriminator;
|
|
@@ -789,7 +634,6 @@ export class Frontend {
|
|
|
789
634
|
res.json({ message: 'Command received' });
|
|
790
635
|
return;
|
|
791
636
|
}
|
|
792
|
-
// Handle the command setmatterpasscode from Settings
|
|
793
637
|
if (command === 'setmatterpasscode') {
|
|
794
638
|
const passcode = Math.min(Math.max(parseInt(req.body.value), 10000000), 90000000);
|
|
795
639
|
this.matterbridge.matterbridgeInformation.matterPasscode = passcode;
|
|
@@ -798,20 +642,17 @@ export class Frontend {
|
|
|
798
642
|
res.json({ message: 'Command received' });
|
|
799
643
|
return;
|
|
800
644
|
}
|
|
801
|
-
// Handle the command setmbloglevel from Settings
|
|
802
645
|
if (command === 'setmblogfile') {
|
|
803
646
|
this.log.debug('Matterbridge file log:', param);
|
|
804
647
|
this.matterbridge.matterbridgeInformation.fileLogger = param === 'true';
|
|
805
648
|
await this.matterbridge.nodeContext?.set('matterbridgeFileLog', param === 'true');
|
|
806
|
-
// Create the file logger for matterbridge
|
|
807
649
|
if (param === 'true')
|
|
808
|
-
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug"
|
|
650
|
+
AnsiLogger.setGlobalLogfile(path.join(this.matterbridge.matterbridgeDirectory, this.matterbridge.matterbrideLoggerFile), "debug", true);
|
|
809
651
|
else
|
|
810
652
|
AnsiLogger.setGlobalLogfile(undefined);
|
|
811
653
|
res.json({ message: 'Command received' });
|
|
812
654
|
return;
|
|
813
655
|
}
|
|
814
|
-
// Handle the command setmbloglevel from Settings
|
|
815
656
|
if (command === 'setmjlogfile') {
|
|
816
657
|
this.log.debug('Matter file log:', param);
|
|
817
658
|
this.matterbridge.matterbridgeInformation.matterFileLogger = param === 'true';
|
|
@@ -838,48 +679,40 @@ export class Frontend {
|
|
|
838
679
|
res.json({ message: 'Command received' });
|
|
839
680
|
return;
|
|
840
681
|
}
|
|
841
|
-
// Handle the command unregister from Settings
|
|
842
682
|
if (command === 'unregister') {
|
|
843
683
|
await this.matterbridge.unregisterAndShutdownProcess();
|
|
844
684
|
res.json({ message: 'Command received' });
|
|
845
685
|
return;
|
|
846
686
|
}
|
|
847
|
-
// Handle the command reset from Settings
|
|
848
687
|
if (command === 'reset') {
|
|
849
688
|
await this.matterbridge.shutdownProcessAndReset();
|
|
850
689
|
res.json({ message: 'Command received' });
|
|
851
690
|
return;
|
|
852
691
|
}
|
|
853
|
-
// Handle the command factoryreset from Settings
|
|
854
692
|
if (command === 'factoryreset') {
|
|
855
693
|
await this.matterbridge.shutdownProcessAndFactoryReset();
|
|
856
694
|
res.json({ message: 'Command received' });
|
|
857
695
|
return;
|
|
858
696
|
}
|
|
859
|
-
// Handle the command shutdown from Header
|
|
860
697
|
if (command === 'shutdown') {
|
|
861
698
|
await this.matterbridge.shutdownProcess();
|
|
862
699
|
res.json({ message: 'Command received' });
|
|
863
700
|
return;
|
|
864
701
|
}
|
|
865
|
-
// Handle the command restart from Header
|
|
866
702
|
if (command === 'restart') {
|
|
867
703
|
await this.matterbridge.restartProcess();
|
|
868
704
|
res.json({ message: 'Command received' });
|
|
869
705
|
return;
|
|
870
706
|
}
|
|
871
|
-
// Handle the command update from Header
|
|
872
707
|
if (command === 'update') {
|
|
873
708
|
await this.matterbridge.updateProcess();
|
|
874
709
|
this.wssSendRestartRequired();
|
|
875
710
|
res.json({ message: 'Command received' });
|
|
876
711
|
return;
|
|
877
712
|
}
|
|
878
|
-
// Handle the command saveconfig from Home
|
|
879
713
|
if (command === 'saveconfig') {
|
|
880
714
|
param = param.replace(/\*/g, '\\');
|
|
881
715
|
this.log.info(`Saving config for plugin ${plg}${param}${nf}...`);
|
|
882
|
-
// console.log('Req.body:', JSON.stringify(req.body, null, 2));
|
|
883
716
|
if (!this.matterbridge.plugins.has(param)) {
|
|
884
717
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
885
718
|
}
|
|
@@ -894,7 +727,6 @@ export class Frontend {
|
|
|
894
727
|
res.json({ message: 'Command received' });
|
|
895
728
|
return;
|
|
896
729
|
}
|
|
897
|
-
// Handle the command installplugin from Home
|
|
898
730
|
if (command === 'installplugin') {
|
|
899
731
|
param = param.replace(/\*/g, '\\');
|
|
900
732
|
this.log.info(`Installing plugin ${plg}${param}${nf}...`);
|
|
@@ -903,7 +735,6 @@ export class Frontend {
|
|
|
903
735
|
await this.matterbridge.spawnCommand('npm', ['install', '-g', param, '--omit=dev', '--verbose']);
|
|
904
736
|
this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
|
|
905
737
|
this.wssSendSnackbarMessage(`Installed package ${param}`, 10, 'success');
|
|
906
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
907
738
|
}
|
|
908
739
|
catch (error) {
|
|
909
740
|
this.log.error(`Error installing plugin ${plg}${param}${er}`);
|
|
@@ -911,22 +742,17 @@ export class Frontend {
|
|
|
911
742
|
}
|
|
912
743
|
this.wssSendRestartRequired();
|
|
913
744
|
param = param.split('@')[0];
|
|
914
|
-
// Also add the plugin to matterbridge so no return!
|
|
915
745
|
if (param === 'matterbridge') {
|
|
916
|
-
// 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
|
|
917
746
|
res.json({ message: 'Command received' });
|
|
918
747
|
return;
|
|
919
748
|
}
|
|
920
749
|
}
|
|
921
|
-
// Handle the command addplugin from Home
|
|
922
750
|
if (command === 'addplugin' || command === 'installplugin') {
|
|
923
751
|
param = param.replace(/\*/g, '\\');
|
|
924
752
|
const plugin = await this.matterbridge.plugins.add(param);
|
|
925
753
|
if (plugin) {
|
|
926
754
|
this.wssSendSnackbarMessage(`Added plugin ${param}`);
|
|
927
755
|
if (this.matterbridge.bridgeMode === 'childbridge') {
|
|
928
|
-
// 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
|
|
929
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
930
756
|
this.matterbridge.createDynamicPlugin(plugin, true);
|
|
931
757
|
}
|
|
932
758
|
this.matterbridge.plugins.load(plugin, true, 'The plugin has been added', true).then(() => {
|
|
@@ -936,14 +762,13 @@ export class Frontend {
|
|
|
936
762
|
res.json({ message: 'Command received' });
|
|
937
763
|
return;
|
|
938
764
|
}
|
|
939
|
-
// Handle the command removeplugin from Home
|
|
940
765
|
if (command === 'removeplugin') {
|
|
941
766
|
if (!this.matterbridge.plugins.has(param)) {
|
|
942
767
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
943
768
|
}
|
|
944
769
|
else {
|
|
945
770
|
const plugin = this.matterbridge.plugins.get(param);
|
|
946
|
-
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true);
|
|
771
|
+
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been removed.', true);
|
|
947
772
|
await this.matterbridge.plugins.remove(param);
|
|
948
773
|
this.wssSendSnackbarMessage(`Removed plugin ${param}`);
|
|
949
774
|
this.wssSendRefreshRequired('plugins');
|
|
@@ -951,7 +776,6 @@ export class Frontend {
|
|
|
951
776
|
res.json({ message: 'Command received' });
|
|
952
777
|
return;
|
|
953
778
|
}
|
|
954
|
-
// Handle the command enableplugin from Home
|
|
955
779
|
if (command === 'enableplugin') {
|
|
956
780
|
if (!this.matterbridge.plugins.has(param)) {
|
|
957
781
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
@@ -970,7 +794,6 @@ export class Frontend {
|
|
|
970
794
|
await this.matterbridge.plugins.enable(param);
|
|
971
795
|
this.wssSendSnackbarMessage(`Enabled plugin ${param}`);
|
|
972
796
|
if (this.matterbridge.bridgeMode === 'childbridge' && plugin.type === 'DynamicPlatform') {
|
|
973
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
974
797
|
this.matterbridge.createDynamicPlugin(plugin, true);
|
|
975
798
|
}
|
|
976
799
|
this.matterbridge.plugins.load(plugin, true, 'The plugin has been enabled', true).then(() => {
|
|
@@ -981,7 +804,6 @@ export class Frontend {
|
|
|
981
804
|
res.json({ message: 'Command received' });
|
|
982
805
|
return;
|
|
983
806
|
}
|
|
984
|
-
// Handle the command disableplugin from Home
|
|
985
807
|
if (command === 'disableplugin') {
|
|
986
808
|
if (!this.matterbridge.plugins.has(param)) {
|
|
987
809
|
this.log.warn(`Plugin ${plg}${param}${wr} not found in matterbridge`);
|
|
@@ -989,7 +811,7 @@ export class Frontend {
|
|
|
989
811
|
else {
|
|
990
812
|
const plugin = this.matterbridge.plugins.get(param);
|
|
991
813
|
if (plugin && plugin.enabled) {
|
|
992
|
-
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true);
|
|
814
|
+
await this.matterbridge.plugins.shutdown(plugin, 'The plugin has been disabled.', true);
|
|
993
815
|
await this.matterbridge.plugins.disable(param);
|
|
994
816
|
this.wssSendSnackbarMessage(`Disabled plugin ${param}`);
|
|
995
817
|
this.wssSendRefreshRequired('plugins');
|
|
@@ -1008,13 +830,10 @@ export class Frontend {
|
|
|
1008
830
|
return;
|
|
1009
831
|
}
|
|
1010
832
|
this.wssSendSnackbarMessage(`Installing package ${filename}. Please wait...`);
|
|
1011
|
-
// Define the path where the plugin file will be saved
|
|
1012
833
|
const filePath = path.join(this.matterbridge.matterbridgeDirectory, 'uploads', filename);
|
|
1013
834
|
try {
|
|
1014
|
-
// Move the uploaded file to the specified path
|
|
1015
835
|
await fs.rename(file.path, filePath);
|
|
1016
836
|
this.log.info(`File ${plg}${filename}${nf} uploaded successfully`);
|
|
1017
|
-
// Install the plugin package
|
|
1018
837
|
if (filename.endsWith('.tgz')) {
|
|
1019
838
|
await this.matterbridge.spawnCommand('npm', ['install', '-g', filePath, '--omit=dev', '--verbose']);
|
|
1020
839
|
this.log.info(`Plugin package ${plg}${filename}${nf} installed successfully. Full restart required.`);
|
|
@@ -1031,46 +850,31 @@ export class Frontend {
|
|
|
1031
850
|
res.status(500).send(`Error uploading or installing plugin package ${filename}`);
|
|
1032
851
|
}
|
|
1033
852
|
});
|
|
1034
|
-
// Fallback for routing (must be the last route)
|
|
1035
853
|
this.expressApp.use((req, res) => {
|
|
1036
854
|
this.log.debug('The frontend sent:', req.url);
|
|
1037
855
|
res.sendFile(path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
|
|
1038
856
|
});
|
|
1039
|
-
/* Not working in express v5!
|
|
1040
|
-
this.expressApp.get('*', (req, res) => {
|
|
1041
|
-
this.log.debug('The frontend sent:', req.url);
|
|
1042
|
-
this.log.debug('Response send file:', path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
|
|
1043
|
-
res.sendFile(path.join(this.matterbridge.rootDirectory, 'frontend/build/index.html'));
|
|
1044
|
-
});
|
|
1045
|
-
*/
|
|
1046
857
|
this.log.debug(`Frontend initialized on port ${YELLOW}${this.port}${db} static ${UNDERLINE}${path.join(this.matterbridge.rootDirectory, 'frontend/build')}${UNDERLINEOFF}${rs}`);
|
|
1047
858
|
}
|
|
1048
859
|
async stop() {
|
|
1049
|
-
// Remove all listeners from the cliEmitter
|
|
1050
|
-
// cliEmitter.removeAllListeners();
|
|
1051
|
-
// Close the http server
|
|
1052
860
|
if (this.httpServer) {
|
|
1053
861
|
this.httpServer.close();
|
|
1054
862
|
this.httpServer.removeAllListeners();
|
|
1055
863
|
this.httpServer = undefined;
|
|
1056
864
|
this.log.debug('Frontend http server closed successfully');
|
|
1057
865
|
}
|
|
1058
|
-
// Close the https server
|
|
1059
866
|
if (this.httpsServer) {
|
|
1060
867
|
this.httpsServer.close();
|
|
1061
868
|
this.httpsServer.removeAllListeners();
|
|
1062
869
|
this.httpsServer = undefined;
|
|
1063
870
|
this.log.debug('Frontend https server closed successfully');
|
|
1064
871
|
}
|
|
1065
|
-
// Remove listeners from the express app
|
|
1066
872
|
if (this.expressApp) {
|
|
1067
873
|
this.expressApp.removeAllListeners();
|
|
1068
874
|
this.expressApp = undefined;
|
|
1069
875
|
this.log.debug('Frontend app closed successfully');
|
|
1070
876
|
}
|
|
1071
|
-
// Close the WebSocket server
|
|
1072
877
|
if (this.webSocketServer) {
|
|
1073
|
-
// Close all active connections
|
|
1074
878
|
this.webSocketServer.clients.forEach((client) => {
|
|
1075
879
|
if (client.readyState === WebSocket.OPEN) {
|
|
1076
880
|
client.close();
|
|
@@ -1087,7 +891,6 @@ export class Frontend {
|
|
|
1087
891
|
this.webSocketServer = undefined;
|
|
1088
892
|
}
|
|
1089
893
|
}
|
|
1090
|
-
// Function to format bytes to KB, MB, or GB
|
|
1091
894
|
formatMemoryUsage = (bytes) => {
|
|
1092
895
|
if (bytes >= 1024 ** 3) {
|
|
1093
896
|
return `${(bytes / 1024 ** 3).toFixed(2)} GB`;
|
|
@@ -1099,7 +902,6 @@ export class Frontend {
|
|
|
1099
902
|
return `${(bytes / 1024).toFixed(2)} KB`;
|
|
1100
903
|
}
|
|
1101
904
|
};
|
|
1102
|
-
// Function to format system uptime with only the most significant unit
|
|
1103
905
|
formatOsUpTime = (seconds) => {
|
|
1104
906
|
if (seconds >= 86400) {
|
|
1105
907
|
const days = Math.floor(seconds / 86400);
|
|
@@ -1115,13 +917,8 @@ export class Frontend {
|
|
|
1115
917
|
}
|
|
1116
918
|
return `${seconds} second${seconds !== 1 ? 's' : ''}`;
|
|
1117
919
|
};
|
|
1118
|
-
/**
|
|
1119
|
-
* Retrieves the api settings data.
|
|
1120
|
-
* @returns {Promise<object>} A promise that resolve in the api settings object.
|
|
1121
|
-
*/
|
|
1122
920
|
async getApiSettings() {
|
|
1123
921
|
const { lastCpuUsage } = await import('./cli.js');
|
|
1124
|
-
// Update the system information
|
|
1125
922
|
this.matterbridge.systemInformation.totalMemory = this.formatMemoryUsage(os.totalmem());
|
|
1126
923
|
this.matterbridge.systemInformation.freeMemory = this.formatMemoryUsage(os.freemem());
|
|
1127
924
|
this.matterbridge.systemInformation.systemUptime = this.formatOsUpTime(os.uptime());
|
|
@@ -1130,7 +927,6 @@ export class Frontend {
|
|
|
1130
927
|
this.matterbridge.systemInformation.rss = this.formatMemoryUsage(process.memoryUsage().rss);
|
|
1131
928
|
this.matterbridge.systemInformation.heapTotal = this.formatMemoryUsage(process.memoryUsage().heapTotal);
|
|
1132
929
|
this.matterbridge.systemInformation.heapUsed = this.formatMemoryUsage(process.memoryUsage().heapUsed);
|
|
1133
|
-
// Update the matterbridge information
|
|
1134
930
|
this.matterbridge.matterbridgeInformation.bridgeMode = this.matterbridge.bridgeMode;
|
|
1135
931
|
this.matterbridge.matterbridgeInformation.restartMode = this.matterbridge.restartMode;
|
|
1136
932
|
this.matterbridge.matterbridgeInformation.loggerLevel = this.matterbridge.log.logLevel;
|
|
@@ -1149,11 +945,6 @@ export class Frontend {
|
|
|
1149
945
|
this.matterbridge.matterbridgeInformation.profile = this.matterbridge.profile;
|
|
1150
946
|
return { systemInformation: this.matterbridge.systemInformation, matterbridgeInformation: this.matterbridge.matterbridgeInformation };
|
|
1151
947
|
}
|
|
1152
|
-
/**
|
|
1153
|
-
* Retrieves the reachable attribute.
|
|
1154
|
-
* @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
|
|
1155
|
-
* @returns {boolean} The reachable attribute.
|
|
1156
|
-
*/
|
|
1157
948
|
getReachability(device) {
|
|
1158
949
|
if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
|
|
1159
950
|
return false;
|
|
@@ -1178,20 +969,13 @@ export class Frontend {
|
|
|
1178
969
|
}
|
|
1179
970
|
return;
|
|
1180
971
|
};
|
|
1181
|
-
// Root endpoint
|
|
1182
972
|
if (device.hasClusterServer(PowerSource.Cluster.id))
|
|
1183
973
|
return powerSource(device);
|
|
1184
|
-
// Child endpoints
|
|
1185
974
|
for (const child of device.getChildEndpoints()) {
|
|
1186
975
|
if (child.hasClusterServer(PowerSource.Cluster.id))
|
|
1187
976
|
return powerSource(child);
|
|
1188
977
|
}
|
|
1189
978
|
}
|
|
1190
|
-
/**
|
|
1191
|
-
* Retrieves the cluster text description from a given device.
|
|
1192
|
-
* @param {MatterbridgeDevice} device - The MatterbridgeDevice object.
|
|
1193
|
-
* @returns {string} The attributes description of the cluster servers in the device.
|
|
1194
|
-
*/
|
|
1195
979
|
getClusterTextFromDevice(device) {
|
|
1196
980
|
if (!device.lifecycle.isReady || device.construction.status !== Lifecycle.Status.Active)
|
|
1197
981
|
return '';
|
|
@@ -1233,7 +1017,6 @@ export class Frontend {
|
|
|
1233
1017
|
let attributes = '';
|
|
1234
1018
|
let supportedModes = [];
|
|
1235
1019
|
device.forEachAttribute((clusterName, clusterId, attributeName, attributeId, attributeValue) => {
|
|
1236
|
-
// console.log(`${device.deviceName} => Cluster: ${clusterName}-${clusterId} Attribute: ${attributeName}-${attributeId} Value(${typeof attributeValue}): ${attributeValue}`);
|
|
1237
1020
|
if (typeof attributeValue === 'undefined')
|
|
1238
1021
|
return;
|
|
1239
1022
|
if (clusterName === 'onOff' && attributeName === 'onOff')
|
|
@@ -1325,13 +1108,8 @@ export class Frontend {
|
|
|
1325
1108
|
if (clusterName === 'userLabel' && attributeName === 'labelList')
|
|
1326
1109
|
attributes += `${getUserLabel(device)} `;
|
|
1327
1110
|
});
|
|
1328
|
-
// console.log(`${device.deviceName}.forEachAttribute: ${attributes}`);
|
|
1329
1111
|
return attributes.trimStart().trimEnd();
|
|
1330
1112
|
}
|
|
1331
|
-
/**
|
|
1332
|
-
* Retrieves the base registered plugins sanitized for res.json().
|
|
1333
|
-
* @returns {BaseRegisteredPlugin[]} An array of BaseRegisteredPlugin.
|
|
1334
|
-
*/
|
|
1335
1113
|
getBaseRegisteredPlugins() {
|
|
1336
1114
|
const baseRegisteredPlugins = [];
|
|
1337
1115
|
for (const plugin of this.matterbridge.plugins) {
|
|
@@ -1369,13 +1147,6 @@ export class Frontend {
|
|
|
1369
1147
|
}
|
|
1370
1148
|
return baseRegisteredPlugins;
|
|
1371
1149
|
}
|
|
1372
|
-
/**
|
|
1373
|
-
* Handles incoming websocket messages for the Matterbridge frontend.
|
|
1374
|
-
*
|
|
1375
|
-
* @param {WebSocket} client - The websocket client that sent the message.
|
|
1376
|
-
* @param {WebSocket.RawData} message - The raw data of the message received from the client.
|
|
1377
|
-
* @returns {Promise<void>} A promise that resolves when the message has been handled.
|
|
1378
|
-
*/
|
|
1379
1150
|
async wsMessageHandler(client, message) {
|
|
1380
1151
|
let data;
|
|
1381
1152
|
try {
|
|
@@ -1531,10 +1302,8 @@ export class Frontend {
|
|
|
1531
1302
|
else if (data.method === '/api/devices') {
|
|
1532
1303
|
const devices = [];
|
|
1533
1304
|
this.matterbridge.devices.forEach(async (device) => {
|
|
1534
|
-
// Filter by pluginName if provided
|
|
1535
1305
|
if (data.params.pluginName && data.params.pluginName !== device.plugin)
|
|
1536
1306
|
return;
|
|
1537
|
-
// Check if the device has the required properties
|
|
1538
1307
|
if (!device.plugin || !device.name || !device.deviceName || !device.serialNumber || !device.uniqueId || !device.lifecycle.isReady)
|
|
1539
1308
|
return;
|
|
1540
1309
|
const cluster = this.getClusterTextFromDevice(device);
|
|
@@ -1619,7 +1388,6 @@ export class Frontend {
|
|
|
1619
1388
|
});
|
|
1620
1389
|
endpointServer.getChildEndpoints().forEach((childEndpoint) => {
|
|
1621
1390
|
deviceTypes = [];
|
|
1622
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1623
1391
|
const name = childEndpoint.endpoint?.id;
|
|
1624
1392
|
const clusterServers = childEndpoint.getAllClusterServers();
|
|
1625
1393
|
clusterServers.forEach((clusterServer) => {
|
|
@@ -1718,7 +1486,6 @@ export class Frontend {
|
|
|
1718
1486
|
return;
|
|
1719
1487
|
}
|
|
1720
1488
|
const config = plugin.configJson;
|
|
1721
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1722
1489
|
const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
|
|
1723
1490
|
this.log.debug(`SelectDevice(selectMode ${select}) data ${debugStringify(data)}`);
|
|
1724
1491
|
if (select === 'serial')
|
|
@@ -1726,11 +1493,9 @@ export class Frontend {
|
|
|
1726
1493
|
if (select === 'name')
|
|
1727
1494
|
this.log.info(`Selected device name ${data.params.name}`);
|
|
1728
1495
|
if (config && select && (select === 'serial' || select === 'name')) {
|
|
1729
|
-
// Remove postfix from the serial if it exists
|
|
1730
1496
|
if (config.postfix) {
|
|
1731
1497
|
data.params.serial = data.params.serial.replace('-' + config.postfix, '');
|
|
1732
1498
|
}
|
|
1733
|
-
// Add the serial to the whiteList if the whiteList exists and the serial or name is not already in it
|
|
1734
1499
|
if (isValidArray(config.whiteList, 1)) {
|
|
1735
1500
|
if (select === 'serial' && !config.whiteList.includes(data.params.serial)) {
|
|
1736
1501
|
config.whiteList.push(data.params.serial);
|
|
@@ -1739,7 +1504,6 @@ export class Frontend {
|
|
|
1739
1504
|
config.whiteList.push(data.params.name);
|
|
1740
1505
|
}
|
|
1741
1506
|
}
|
|
1742
|
-
// Remove the serial from the blackList if the blackList exists and the serial or name is in it
|
|
1743
1507
|
if (isValidArray(config.blackList, 1)) {
|
|
1744
1508
|
if (select === 'serial' && config.blackList.includes(data.params.serial)) {
|
|
1745
1509
|
config.blackList = config.blackList.filter((serial) => serial !== data.params.serial);
|
|
@@ -1761,7 +1525,6 @@ export class Frontend {
|
|
|
1761
1525
|
return;
|
|
1762
1526
|
}
|
|
1763
1527
|
const config = plugin.configJson;
|
|
1764
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1765
1528
|
const select = plugin.schemaJson?.properties?.blackList?.selectFrom;
|
|
1766
1529
|
this.log.debug(`UnselectDevice(selectMode ${select}) data ${debugStringify(data)}`);
|
|
1767
1530
|
if (select === 'serial')
|
|
@@ -1772,7 +1535,6 @@ export class Frontend {
|
|
|
1772
1535
|
if (config.postfix) {
|
|
1773
1536
|
data.params.serial = data.params.serial.replace('-' + config.postfix, '');
|
|
1774
1537
|
}
|
|
1775
|
-
// Remove the serial from the whiteList if the whiteList exists and the serial is in it
|
|
1776
1538
|
if (isValidArray(config.whiteList, 1)) {
|
|
1777
1539
|
if (select === 'serial' && config.whiteList.includes(data.params.serial)) {
|
|
1778
1540
|
config.whiteList = config.whiteList.filter((serial) => serial !== data.params.serial);
|
|
@@ -1781,7 +1543,6 @@ export class Frontend {
|
|
|
1781
1543
|
config.whiteList = config.whiteList.filter((name) => name !== data.params.name);
|
|
1782
1544
|
}
|
|
1783
1545
|
}
|
|
1784
|
-
// Add the serial to the blackList
|
|
1785
1546
|
if (isValidArray(config.blackList)) {
|
|
1786
1547
|
if (select === 'serial' && !config.blackList.includes(data.params.serial)) {
|
|
1787
1548
|
config.blackList.push(data.params.serial);
|
|
@@ -1808,196 +1569,103 @@ export class Frontend {
|
|
|
1808
1569
|
return;
|
|
1809
1570
|
}
|
|
1810
1571
|
}
|
|
1811
|
-
/**
|
|
1812
|
-
* Sends a WebSocket message to all connected clients. The function is called by AnsiLogger.setGlobalCallback.
|
|
1813
|
-
*
|
|
1814
|
-
* @param {string} level - The logger level of the message: debug info notice warn error fatal...
|
|
1815
|
-
* @param {string} time - The time string of the message
|
|
1816
|
-
* @param {string} name - The logger name of the message
|
|
1817
|
-
* @param {string} message - The content of the message.
|
|
1818
|
-
*/
|
|
1819
1572
|
wssSendMessage(level, time, name, message) {
|
|
1820
1573
|
if (!level || !time || !name || !message)
|
|
1821
1574
|
return;
|
|
1822
|
-
// Remove ANSI escape codes from the message
|
|
1823
|
-
// eslint-disable-next-line no-control-regex
|
|
1824
1575
|
message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
|
|
1825
|
-
// Remove leading asterisks from the message
|
|
1826
1576
|
message = message.replace(/^\*+/, '');
|
|
1827
|
-
// Replace all occurrences of \t and \n
|
|
1828
1577
|
message = message.replace(/[\t\n]/g, '');
|
|
1829
|
-
// Remove non-printable characters
|
|
1830
|
-
// eslint-disable-next-line no-control-regex
|
|
1831
1578
|
message = message.replace(/[\x00-\x1F\x7F]/g, '');
|
|
1832
|
-
// Replace all occurrences of \" with "
|
|
1833
1579
|
message = message.replace(/\\"/g, '"');
|
|
1834
|
-
// Replace all occurrences of angle-brackets with < and >"
|
|
1835
1580
|
message = message.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>');
|
|
1836
|
-
// Define the maximum allowed length for continuous characters without a space
|
|
1837
1581
|
const maxContinuousLength = 100;
|
|
1838
1582
|
const keepStartLength = 20;
|
|
1839
1583
|
const keepEndLength = 20;
|
|
1840
|
-
// Split the message into words
|
|
1841
1584
|
message = message
|
|
1842
1585
|
.split(' ')
|
|
1843
1586
|
.map((word) => {
|
|
1844
|
-
// If the word length exceeds the max continuous length, insert spaces and truncate
|
|
1845
1587
|
if (word.length > maxContinuousLength) {
|
|
1846
1588
|
return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
|
|
1847
1589
|
}
|
|
1848
1590
|
return word;
|
|
1849
1591
|
})
|
|
1850
1592
|
.join(' ');
|
|
1851
|
-
// Send the message to all connected clients
|
|
1852
1593
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1853
1594
|
if (client.readyState === WebSocket.OPEN) {
|
|
1854
1595
|
client.send(JSON.stringify({ id: WS_ID_LOG, src: 'Matterbridge', level, time, name, message }));
|
|
1855
1596
|
}
|
|
1856
1597
|
});
|
|
1857
1598
|
}
|
|
1858
|
-
/**
|
|
1859
|
-
* Sends a need to refresh WebSocket message to all connected clients.
|
|
1860
|
-
*
|
|
1861
|
-
* @param {string} changed - The changed value. If null, the whole page will be refreshed.
|
|
1862
|
-
* possible values:
|
|
1863
|
-
* - 'matterbridgeLatestVersion'
|
|
1864
|
-
* - 'matterbridgeAdvertise'
|
|
1865
|
-
* - 'online'
|
|
1866
|
-
* - 'offline'
|
|
1867
|
-
* - 'reachability'
|
|
1868
|
-
* - 'settings'
|
|
1869
|
-
* - 'plugins'
|
|
1870
|
-
* - 'devices'
|
|
1871
|
-
* - 'fabrics'
|
|
1872
|
-
* - 'sessions'
|
|
1873
|
-
*/
|
|
1874
1599
|
wssSendRefreshRequired(changed = null) {
|
|
1875
1600
|
this.log.debug('Sending a refresh required message to all connected clients');
|
|
1876
|
-
// Send the message to all connected clients
|
|
1877
1601
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1878
1602
|
if (client.readyState === WebSocket.OPEN) {
|
|
1879
1603
|
client.send(JSON.stringify({ id: WS_ID_REFRESH_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', params: { changed: changed } }));
|
|
1880
1604
|
}
|
|
1881
1605
|
});
|
|
1882
1606
|
}
|
|
1883
|
-
/**
|
|
1884
|
-
* Sends a need to restart WebSocket message to all connected clients.
|
|
1885
|
-
*
|
|
1886
|
-
*/
|
|
1887
1607
|
wssSendRestartRequired(snackbar = true) {
|
|
1888
1608
|
this.log.debug('Sending a restart required message to all connected clients');
|
|
1889
1609
|
this.matterbridge.matterbridgeInformation.restartRequired = true;
|
|
1890
1610
|
if (snackbar === true)
|
|
1891
1611
|
this.wssSendSnackbarMessage(`Restart required`, 0);
|
|
1892
|
-
// Send the message to all connected clients
|
|
1893
1612
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1894
1613
|
if (client.readyState === WebSocket.OPEN) {
|
|
1895
1614
|
client.send(JSON.stringify({ id: WS_ID_RESTART_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', params: {} }));
|
|
1896
1615
|
}
|
|
1897
1616
|
});
|
|
1898
1617
|
}
|
|
1899
|
-
/**
|
|
1900
|
-
* Sends a need to update WebSocket message to all connected clients.
|
|
1901
|
-
*
|
|
1902
|
-
*/
|
|
1903
1618
|
wssSendUpdateRequired() {
|
|
1904
1619
|
this.log.debug('Sending an update required message to all connected clients');
|
|
1905
1620
|
this.matterbridge.matterbridgeInformation.updateRequired = true;
|
|
1906
|
-
// Send the message to all connected clients
|
|
1907
1621
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1908
1622
|
if (client.readyState === WebSocket.OPEN) {
|
|
1909
1623
|
client.send(JSON.stringify({ id: WS_ID_UPDATE_NEEDED, src: 'Matterbridge', dst: 'Frontend', method: 'update_required', params: {} }));
|
|
1910
1624
|
}
|
|
1911
1625
|
});
|
|
1912
1626
|
}
|
|
1913
|
-
/**
|
|
1914
|
-
* Sends a memory update message to all connected clients.
|
|
1915
|
-
*
|
|
1916
|
-
*/
|
|
1917
1627
|
wssSendCpuUpdate(cpuUsage) {
|
|
1918
1628
|
this.log.debug('Sending a cpu update message to all connected clients');
|
|
1919
|
-
// Send the message to all connected clients
|
|
1920
1629
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1921
1630
|
if (client.readyState === WebSocket.OPEN) {
|
|
1922
1631
|
client.send(JSON.stringify({ id: WS_ID_CPU_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'cpu_update', params: { cpuUsage } }));
|
|
1923
1632
|
}
|
|
1924
1633
|
});
|
|
1925
1634
|
}
|
|
1926
|
-
/**
|
|
1927
|
-
* Sends a cpu update message to all connected clients.
|
|
1928
|
-
*
|
|
1929
|
-
*/
|
|
1930
1635
|
wssSendMemoryUpdate(totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers) {
|
|
1931
1636
|
this.log.debug('Sending a memory update message to all connected clients');
|
|
1932
|
-
// Send the message to all connected clients
|
|
1933
1637
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1934
1638
|
if (client.readyState === WebSocket.OPEN) {
|
|
1935
1639
|
client.send(JSON.stringify({ id: WS_ID_MEMORY_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', params: { totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers } }));
|
|
1936
1640
|
}
|
|
1937
1641
|
});
|
|
1938
1642
|
}
|
|
1939
|
-
/**
|
|
1940
|
-
* Sends a memory update message to all connected clients.
|
|
1941
|
-
*
|
|
1942
|
-
*/
|
|
1943
1643
|
wssSendUptimeUpdate(systemUptime, processUptime) {
|
|
1944
1644
|
this.log.debug('Sending a uptime update message to all connected clients');
|
|
1945
|
-
// Send the message to all connected clients
|
|
1946
1645
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1947
1646
|
if (client.readyState === WebSocket.OPEN) {
|
|
1948
1647
|
client.send(JSON.stringify({ id: WS_ID_UPTIME_UPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'uptime_update', params: { systemUptime, processUptime } }));
|
|
1949
1648
|
}
|
|
1950
1649
|
});
|
|
1951
1650
|
}
|
|
1952
|
-
/**
|
|
1953
|
-
* Sends a cpu update message to all connected clients.
|
|
1954
|
-
* @param {string} message - The message to send.
|
|
1955
|
-
* @param {number} timeout - The timeout in seconds for the snackbar message.
|
|
1956
|
-
* @param {'info' | 'warning' | 'error' | 'success'} severity - The severity of the snackbar message (default info).
|
|
1957
|
-
*
|
|
1958
|
-
*/
|
|
1959
1651
|
wssSendSnackbarMessage(message, timeout = 5, severity = 'info') {
|
|
1960
1652
|
this.log.debug('Sending a snackbar message to all connected clients');
|
|
1961
|
-
// Send the message to all connected clients
|
|
1962
1653
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1963
1654
|
if (client.readyState === WebSocket.OPEN) {
|
|
1964
1655
|
client.send(JSON.stringify({ id: WS_ID_SNACKBAR, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', params: { message, timeout, severity } }));
|
|
1965
1656
|
}
|
|
1966
1657
|
});
|
|
1967
1658
|
}
|
|
1968
|
-
/**
|
|
1969
|
-
* Sends an attribute update message to all connected WebSocket clients.
|
|
1970
|
-
*
|
|
1971
|
-
* @param {string | undefined} plugin - The name of the plugin.
|
|
1972
|
-
* @param {string | undefined} serialNumber - The serial number of the device.
|
|
1973
|
-
* @param {string | undefined} uniqueId - The unique identifier of the device.
|
|
1974
|
-
* @param {string} cluster - The cluster name where the attribute belongs.
|
|
1975
|
-
* @param {string} attribute - The name of the attribute that changed.
|
|
1976
|
-
* @param {number | string | boolean} value - The new value of the attribute.
|
|
1977
|
-
*
|
|
1978
|
-
* @remarks
|
|
1979
|
-
* This method logs a debug message and sends a JSON-formatted message to all connected WebSocket clients
|
|
1980
|
-
* with the updated attribute information.
|
|
1981
|
-
*/
|
|
1982
1659
|
wssSendAttributeChangedMessage(plugin, serialNumber, uniqueId, cluster, attribute, value) {
|
|
1983
1660
|
this.log.debug('Sending an attribute update message to all connected clients');
|
|
1984
|
-
// Send the message to all connected clients
|
|
1985
1661
|
this.webSocketServer?.clients.forEach((client) => {
|
|
1986
1662
|
if (client.readyState === WebSocket.OPEN) {
|
|
1987
1663
|
client.send(JSON.stringify({ id: WS_ID_STATEUPDATE, src: 'Matterbridge', dst: 'Frontend', method: 'state_update', params: { plugin, serialNumber, uniqueId, cluster, attribute, value } }));
|
|
1988
1664
|
}
|
|
1989
1665
|
});
|
|
1990
1666
|
}
|
|
1991
|
-
/**
|
|
1992
|
-
* Sends a message to all connected clients.
|
|
1993
|
-
* @param {number} id - The message id.
|
|
1994
|
-
* @param {string} method - The message method.
|
|
1995
|
-
* @param {Record<string, string | number | boolean>} params - The message parameters.
|
|
1996
|
-
*
|
|
1997
|
-
*/
|
|
1998
1667
|
wssBroadcastMessage(id, method, params) {
|
|
1999
1668
|
this.log.debug(`Sending a broadcast message id ${id} method ${method} params ${debugStringify(params ?? {})} to all connected clients`);
|
|
2000
|
-
// Send the message to all connected clients
|
|
2001
1669
|
this.webSocketServer?.clients.forEach((client) => {
|
|
2002
1670
|
if (client.readyState === WebSocket.OPEN) {
|
|
2003
1671
|
client.send(JSON.stringify({ id, src: 'Matterbridge', dst: 'Frontend', method, params }));
|
|
@@ -2005,4 +1673,3 @@ export class Frontend {
|
|
|
2005
1673
|
});
|
|
2006
1674
|
}
|
|
2007
1675
|
}
|
|
2008
|
-
//# sourceMappingURL=frontend.js.map
|