matterbridge 1.4.1 → 1.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +43 -0
- package/README.md +1 -2
- package/dist/cluster/AirQualityCluster.d.ts.map +1 -1
- package/dist/cluster/AirQualityCluster.js +1 -0
- package/dist/cluster/AirQualityCluster.js.map +1 -1
- package/dist/cluster/BridgedDeviceBasicInformationCluster.d.ts.map +1 -1
- package/dist/cluster/BridgedDeviceBasicInformationCluster.js +1 -0
- package/dist/cluster/BridgedDeviceBasicInformationCluster.js.map +1 -1
- package/dist/cluster/PowerTopologyCluster.d.ts.map +1 -1
- package/dist/cluster/PowerTopologyCluster.js +1 -1
- package/dist/cluster/PowerTopologyCluster.js.map +1 -1
- package/dist/cluster/TvocCluster.d.ts.map +1 -1
- package/dist/cluster/TvocCluster.js +1 -0
- package/dist/cluster/TvocCluster.js.map +1 -1
- package/dist/matterbridge.d.ts +16 -0
- package/dist/matterbridge.d.ts.map +1 -1
- package/dist/matterbridge.js +299 -25
- package/dist/matterbridge.js.map +1 -1
- package/dist/matterbridgeDevice.d.ts +65 -157
- package/dist/matterbridgeDevice.d.ts.map +1 -1
- package/dist/matterbridgeDevice.js +224 -26
- package/dist/matterbridgeDevice.js.map +1 -1
- package/dist/matterbridgeTypes.d.ts +2 -0
- package/dist/matterbridgeTypes.d.ts.map +1 -1
- package/dist/pluginManager.d.ts.map +1 -1
- package/dist/pluginManager.js +1 -0
- package/dist/pluginManager.js.map +1 -1
- package/dist/utils/utils.d.ts +58 -0
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +133 -0
- package/dist/utils/utils.js.map +1 -1
- package/frontend/build/asset-manifest.json +6 -6
- package/frontend/build/index.html +1 -1
- package/frontend/build/static/css/main.ee3183e2.css +2 -0
- package/frontend/build/static/css/main.ee3183e2.css.map +1 -0
- package/frontend/build/static/js/{main.fd6f85a1.js → main.e76dd8f6.js} +3 -3
- package/frontend/build/static/js/main.e76dd8f6.js.map +1 -0
- package/package.json +26 -24
- package/frontend/build/static/css/main.5174e68c.css +0 -2
- package/frontend/build/static/css/main.5174e68c.css.map +0 -1
- package/frontend/build/static/js/main.fd6f85a1.js.map +0 -1
- /package/frontend/build/static/js/{main.fd6f85a1.js.LICENSE.txt → main.e76dd8f6.js.LICENSE.txt} +0 -0
package/dist/matterbridge.js
CHANGED
|
@@ -35,7 +35,7 @@ import WebSocket, { WebSocketServer } from 'ws';
|
|
|
35
35
|
// Matterbridge
|
|
36
36
|
import { MatterbridgeDevice } from './matterbridgeDevice.js';
|
|
37
37
|
import { BridgedDeviceBasicInformation, BridgedDeviceBasicInformationCluster } from './cluster/BridgedDeviceBasicInformationCluster.js';
|
|
38
|
-
import { logInterfaces, wait, waiter } from './utils/utils.js';
|
|
38
|
+
import { logInterfaces, wait, waiter, zipDirectory } from './utils/utils.js';
|
|
39
39
|
// @project-chip/matter-node.js
|
|
40
40
|
import { CommissioningController, CommissioningServer, MatterServer } from '@project-chip/matter-node.js';
|
|
41
41
|
import { BasicInformationCluster, ClusterServer, FixedLabelCluster, GeneralCommissioning, PowerSourceCluster, SwitchCluster, ThreadNetworkDiagnosticsCluster, getClusterNameById } from '@project-chip/matter-node.js/cluster';
|
|
@@ -87,7 +87,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
87
87
|
bridgeMode: '',
|
|
88
88
|
restartMode: '',
|
|
89
89
|
loggerLevel: "info" /* LogLevel.INFO */,
|
|
90
|
+
fileLogger: false,
|
|
90
91
|
matterLoggerLevel: Level.INFO,
|
|
92
|
+
matterFileLogger: false,
|
|
91
93
|
};
|
|
92
94
|
homeDirectory = '';
|
|
93
95
|
rootDirectory = '';
|
|
@@ -106,6 +108,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
106
108
|
// public loggerLevel: LogLevel = LogLevel.INFO;
|
|
107
109
|
profile = getParameter('profile');
|
|
108
110
|
log;
|
|
111
|
+
matterbrideLoggerFile = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
|
|
112
|
+
matterLoggerFile = 'matter' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
|
|
109
113
|
plugins;
|
|
110
114
|
devices;
|
|
111
115
|
registeredDevices = [];
|
|
@@ -203,9 +207,17 @@ export class Matterbridge extends EventEmitter {
|
|
|
203
207
|
this.restartMode = 'service';
|
|
204
208
|
if (hasParameter('docker'))
|
|
205
209
|
this.restartMode = 'docker';
|
|
206
|
-
// Set
|
|
210
|
+
// Set the matterbridge directory
|
|
211
|
+
this.homeDirectory = os.homedir();
|
|
212
|
+
this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
|
|
213
|
+
// Create the file logger for matterbridge
|
|
214
|
+
if (hasParameter('filelogger')) {
|
|
215
|
+
AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
|
|
216
|
+
this.matterbridgeInformation.fileLogger = true;
|
|
217
|
+
}
|
|
218
|
+
// Create matterbridge logger
|
|
207
219
|
this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "info" /* LogLevel.INFO */ });
|
|
208
|
-
// Set
|
|
220
|
+
// Set matterbridge logger level
|
|
209
221
|
if (hasParameter('logger')) {
|
|
210
222
|
const level = getParameter('logger');
|
|
211
223
|
if (level === 'debug') {
|
|
@@ -236,7 +248,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
236
248
|
}
|
|
237
249
|
MatterbridgeDevice.logLevel = this.log.logLevel;
|
|
238
250
|
this.log.debug('Matterbridge is starting...');
|
|
239
|
-
// Set matter.js logger level and
|
|
251
|
+
// Set matter.js logger level, format and logger
|
|
240
252
|
if (hasParameter('matterlogger')) {
|
|
241
253
|
const level = getParameter('matterlogger');
|
|
242
254
|
if (level === 'debug') {
|
|
@@ -266,9 +278,23 @@ export class Matterbridge extends EventEmitter {
|
|
|
266
278
|
Logger.defaultLogLevel = Level.INFO;
|
|
267
279
|
}
|
|
268
280
|
Logger.format = Format.ANSI;
|
|
281
|
+
Logger.setLogger('default', this.createMatterLogger());
|
|
282
|
+
// Create the file logger for matter.js
|
|
283
|
+
if (hasParameter('matterfilelogger')) {
|
|
284
|
+
this.matterbridgeInformation.matterFileLogger = true;
|
|
285
|
+
/*
|
|
286
|
+
try {
|
|
287
|
+
await fs.unlink(path.join(this.matterbridgeDirectory, this.matterLoggerFile));
|
|
288
|
+
} catch (error) {
|
|
289
|
+
this.log.debug(`Error unlinking the log file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
|
|
290
|
+
}
|
|
291
|
+
*/
|
|
292
|
+
Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
|
|
293
|
+
defaultLogLevel: Level.DEBUG,
|
|
294
|
+
logFormat: Format.PLAIN,
|
|
295
|
+
});
|
|
296
|
+
}
|
|
269
297
|
// Initialize nodeStorage and nodeContext
|
|
270
|
-
this.homeDirectory = os.homedir();
|
|
271
|
-
this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
|
|
272
298
|
this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
|
|
273
299
|
this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
|
|
274
300
|
this.log.debug('Creating node storage context for matterbridge');
|
|
@@ -288,6 +314,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
288
314
|
await this.spawnCommand('npm', ['install', '-g', plugin.name]);
|
|
289
315
|
this.log.info(`Plugin ${plg}${plugin.name}${nf} reinstalled.`);
|
|
290
316
|
plugin.error = false;
|
|
317
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
291
318
|
}
|
|
292
319
|
catch (error) {
|
|
293
320
|
plugin.error = true;
|
|
@@ -605,9 +632,11 @@ export class Matterbridge extends EventEmitter {
|
|
|
605
632
|
*/
|
|
606
633
|
deregisterSignalHandlers() {
|
|
607
634
|
this.log.debug(`Deregistering SIGINT and SIGTERM signal handlers...`);
|
|
608
|
-
|
|
635
|
+
if (this.sigintHandler)
|
|
636
|
+
process.off('SIGINT', this.sigintHandler);
|
|
609
637
|
this.sigintHandler = undefined;
|
|
610
|
-
|
|
638
|
+
if (this.sigtermHandler)
|
|
639
|
+
process.off('SIGTERM', this.sigtermHandler);
|
|
611
640
|
this.sigtermHandler = undefined;
|
|
612
641
|
}
|
|
613
642
|
/**
|
|
@@ -856,6 +885,96 @@ export class Matterbridge extends EventEmitter {
|
|
|
856
885
|
// error.stack && this.log.debug(error.stack);
|
|
857
886
|
});
|
|
858
887
|
}
|
|
888
|
+
/**
|
|
889
|
+
* Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
|
|
890
|
+
*
|
|
891
|
+
* @returns {Function} The MatterLogger function.
|
|
892
|
+
*/
|
|
893
|
+
createMatterLogger() {
|
|
894
|
+
const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
|
|
895
|
+
return (_level, formattedLog) => {
|
|
896
|
+
const logger = formattedLog.slice(44, 44 + 20).trim();
|
|
897
|
+
const message = formattedLog.slice(65);
|
|
898
|
+
matterLogger.logName = logger;
|
|
899
|
+
switch (_level) {
|
|
900
|
+
case Level.DEBUG:
|
|
901
|
+
matterLogger.log("debug" /* LogLevel.DEBUG */, message);
|
|
902
|
+
break;
|
|
903
|
+
case Level.INFO:
|
|
904
|
+
matterLogger.log("info" /* LogLevel.INFO */, message);
|
|
905
|
+
break;
|
|
906
|
+
case Level.NOTICE:
|
|
907
|
+
matterLogger.log("notice" /* LogLevel.NOTICE */, message);
|
|
908
|
+
break;
|
|
909
|
+
case Level.WARN:
|
|
910
|
+
matterLogger.log("warn" /* LogLevel.WARN */, message);
|
|
911
|
+
break;
|
|
912
|
+
case Level.ERROR:
|
|
913
|
+
matterLogger.log("error" /* LogLevel.ERROR */, message);
|
|
914
|
+
break;
|
|
915
|
+
case Level.FATAL:
|
|
916
|
+
matterLogger.log("fatal" /* LogLevel.FATAL */, message);
|
|
917
|
+
break;
|
|
918
|
+
default:
|
|
919
|
+
matterLogger.log("debug" /* LogLevel.DEBUG */, message);
|
|
920
|
+
break;
|
|
921
|
+
}
|
|
922
|
+
};
|
|
923
|
+
}
|
|
924
|
+
/**
|
|
925
|
+
* Creates a Matter File Logger.
|
|
926
|
+
*
|
|
927
|
+
* @param {string} filePath - The path to the log file.
|
|
928
|
+
* @param {boolean} [unlink=false] - Whether to unlink the log file before creating a new one.
|
|
929
|
+
* @returns {Function} - A function that logs formatted messages to the log file.
|
|
930
|
+
*/
|
|
931
|
+
async createMatterFileLogger(filePath, unlink = false) {
|
|
932
|
+
// 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
|
|
933
|
+
let fileSize = 0;
|
|
934
|
+
if (unlink) {
|
|
935
|
+
try {
|
|
936
|
+
await fs.unlink(filePath);
|
|
937
|
+
}
|
|
938
|
+
catch (error) {
|
|
939
|
+
this.log.debug(`Error unlinking the log file ${CYAN}${filePath}${er}: ${error instanceof Error ? error.message : error}`);
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
return async (_level, formattedLog) => {
|
|
943
|
+
fileSize += formattedLog.length;
|
|
944
|
+
if (fileSize > 100000000) {
|
|
945
|
+
return;
|
|
946
|
+
}
|
|
947
|
+
const now = new Date();
|
|
948
|
+
const timestamp = `${now.getHours().toString().padStart(2, '0')}:${now.getMinutes().toString().padStart(2, '0')}:${now.getSeconds().toString().padStart(2, '0')}.${now.getMilliseconds().toString().padStart(3, '0')}`;
|
|
949
|
+
const message = formattedLog.slice(24);
|
|
950
|
+
const parts = message.split(' ');
|
|
951
|
+
const logger = parts[1];
|
|
952
|
+
const finalMessage = parts.slice(2).join(' ') + os.EOL;
|
|
953
|
+
switch (_level) {
|
|
954
|
+
case Level.DEBUG:
|
|
955
|
+
await fs.appendFile(filePath, `[${timestamp}] [${logger}] [debug] ${finalMessage}`);
|
|
956
|
+
break;
|
|
957
|
+
case Level.INFO:
|
|
958
|
+
await fs.appendFile(filePath, `[${timestamp}] [${logger}] [info] ${finalMessage}`);
|
|
959
|
+
break;
|
|
960
|
+
case Level.NOTICE:
|
|
961
|
+
await fs.appendFile(filePath, `[${timestamp}] [${logger}] [notice] ${finalMessage}`);
|
|
962
|
+
break;
|
|
963
|
+
case Level.WARN:
|
|
964
|
+
await fs.appendFile(filePath, `[${timestamp}] [${logger}] [warn] ${finalMessage}`);
|
|
965
|
+
break;
|
|
966
|
+
case Level.ERROR:
|
|
967
|
+
await fs.appendFile(filePath, `[${timestamp}] [${logger}] [error] ${finalMessage}`);
|
|
968
|
+
break;
|
|
969
|
+
case Level.FATAL:
|
|
970
|
+
await fs.appendFile(filePath, `[${timestamp}] [${logger}] [fatal] ${finalMessage}`);
|
|
971
|
+
break;
|
|
972
|
+
default:
|
|
973
|
+
await fs.appendFile(filePath, `[${timestamp}] [${logger}] ${finalMessage}`);
|
|
974
|
+
break;
|
|
975
|
+
}
|
|
976
|
+
};
|
|
977
|
+
}
|
|
859
978
|
/**
|
|
860
979
|
* Update matterbridge and cleanup.
|
|
861
980
|
*/
|
|
@@ -979,6 +1098,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
979
1098
|
await this.stopMatterServer();
|
|
980
1099
|
// Closing matter storage
|
|
981
1100
|
await this.stopMatterStorage();
|
|
1101
|
+
// Remove the matterfilelogger
|
|
1102
|
+
try {
|
|
1103
|
+
Logger.removeLogger('matterfilelogger');
|
|
1104
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1105
|
+
}
|
|
1106
|
+
catch (error) {
|
|
1107
|
+
// this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
|
|
1108
|
+
}
|
|
982
1109
|
// Serialize registeredDevices
|
|
983
1110
|
if (this.nodeStorage && this.nodeContext) {
|
|
984
1111
|
this.log.info('Saving registered devices...');
|
|
@@ -1580,6 +1707,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
1580
1707
|
if (storageType === 'json') {
|
|
1581
1708
|
await this.backupJsonMatterStorage(storageName, storageName.replace('.json', '') + '.backup.json');
|
|
1582
1709
|
}
|
|
1710
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1583
1711
|
}
|
|
1584
1712
|
catch (error) {
|
|
1585
1713
|
this.log.error(`Storage initialize() error! The file .matterbridge/${storageName} may be corrupted.`);
|
|
@@ -2203,7 +2331,13 @@ export class Matterbridge extends EventEmitter {
|
|
|
2203
2331
|
process.on('unhandledRejection', (reason, promise) => {
|
|
2204
2332
|
this.log.error('Unhandled Rejection at:', promise, 'reason:', reason);
|
|
2205
2333
|
});
|
|
2334
|
+
|
|
2335
|
+
spawn - [14:27:21.125] [Matterbridge:spawn]: changed 38 packages in 4s
|
|
2336
|
+
spawn - [14:27:21.125] [Matterbridge:spawn]: 10 packages are looking for funding run `npm fund` for details
|
|
2337
|
+
debug - [14:27:21.131] [Matterbridge]: Child process exited with code 0 and signal null
|
|
2338
|
+
debug - [14:27:21.131] [Matterbridge]: Child process stdio streams have closed with code 0
|
|
2206
2339
|
*/
|
|
2340
|
+
const cmdLine = command + ' ' + args.join(' ');
|
|
2207
2341
|
if (process.platform === 'win32' && command === 'npm') {
|
|
2208
2342
|
// Must be spawn('cmd.exe', ['/c', 'npm -g install <package>']);
|
|
2209
2343
|
const argstring = 'npm ' + args.join(' ');
|
|
@@ -2223,9 +2357,11 @@ export class Matterbridge extends EventEmitter {
|
|
|
2223
2357
|
this.log.error(`Failed to start child process: ${err.message}`);
|
|
2224
2358
|
reject(err); // Reject the promise on error
|
|
2225
2359
|
});
|
|
2226
|
-
childProcess.on('close', (code) => {
|
|
2360
|
+
childProcess.on('close', (code, signal) => {
|
|
2361
|
+
this.wssSendMessage('spawn', this.log.now(), 'Matterbridge:spawn', `child process closed with code ${code} and signal ${signal}`);
|
|
2227
2362
|
if (code === 0) {
|
|
2228
|
-
|
|
2363
|
+
if (cmdLine.startsWith('npm install -g'))
|
|
2364
|
+
this.log.notice(`${cmdLine.replace('npm install -g ', '')} installed correctly`);
|
|
2229
2365
|
resolve();
|
|
2230
2366
|
}
|
|
2231
2367
|
else {
|
|
@@ -2234,8 +2370,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
2234
2370
|
}
|
|
2235
2371
|
});
|
|
2236
2372
|
childProcess.on('exit', (code, signal) => {
|
|
2373
|
+
this.wssSendMessage('spawn', this.log.now(), 'Matterbridge:spawn', `child process exited with code ${code} and signal ${signal}`);
|
|
2237
2374
|
if (code === 0) {
|
|
2238
|
-
this.log.debug(`Child process exited with code ${code} and signal ${signal}`);
|
|
2239
2375
|
resolve();
|
|
2240
2376
|
}
|
|
2241
2377
|
else {
|
|
@@ -2250,14 +2386,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
2250
2386
|
if (childProcess.stdout) {
|
|
2251
2387
|
childProcess.stdout.on('data', (data) => {
|
|
2252
2388
|
const message = data.toString().trim();
|
|
2253
|
-
// this.log.info('\n' + message);
|
|
2254
2389
|
this.wssSendMessage('spawn', this.log.now(), 'Matterbridge:spawn', message);
|
|
2255
2390
|
});
|
|
2256
2391
|
}
|
|
2257
2392
|
if (childProcess.stderr) {
|
|
2258
2393
|
childProcess.stderr.on('data', (data) => {
|
|
2259
2394
|
const message = data.toString().trim();
|
|
2260
|
-
// this.log.debug('\n' + message);
|
|
2261
2395
|
this.wssSendMessage('spawn', this.log.now(), 'Matterbridge:spawn', message);
|
|
2262
2396
|
});
|
|
2263
2397
|
}
|
|
@@ -2286,11 +2420,21 @@ export class Matterbridge extends EventEmitter {
|
|
|
2286
2420
|
message = message.replace(/[\x00-\x1F\x7F]/g, '');
|
|
2287
2421
|
// Replace all occurrences of \" with "
|
|
2288
2422
|
message = message.replace(/\\"/g, '"');
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2423
|
+
// Define the maximum allowed length for continuous characters without a space
|
|
2424
|
+
const maxContinuousLength = 100;
|
|
2425
|
+
const keepStartLength = 20;
|
|
2426
|
+
const keepEndLength = 20;
|
|
2427
|
+
// Split the message into words
|
|
2428
|
+
message = message
|
|
2429
|
+
.split(' ')
|
|
2430
|
+
.map((word) => {
|
|
2431
|
+
// If the word length exceeds the max continuous length, insert spaces and truncate
|
|
2432
|
+
if (word.length > maxContinuousLength) {
|
|
2433
|
+
return word.slice(0, keepStartLength) + ' ... ' + word.slice(-keepEndLength);
|
|
2434
|
+
}
|
|
2435
|
+
return word;
|
|
2436
|
+
})
|
|
2437
|
+
.join(' ');
|
|
2294
2438
|
// Send the message to all connected clients
|
|
2295
2439
|
this.webSocketServer?.clients.forEach((client) => {
|
|
2296
2440
|
if (client.readyState === WebSocket.OPEN) {
|
|
@@ -2395,7 +2539,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2395
2539
|
this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
|
|
2396
2540
|
this.webSocketServer.on('connection', (ws, request) => {
|
|
2397
2541
|
const clientIp = request.socket.remoteAddress;
|
|
2398
|
-
|
|
2542
|
+
AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), "debug" /* LogLevel.DEBUG */);
|
|
2399
2543
|
this.log.debug('WebSocketServer logger global callback added');
|
|
2400
2544
|
this.log.info(`WebSocketServer client "${clientIp}" connected to Matterbridge`);
|
|
2401
2545
|
// this.wssSendMessage('info', this.log.now(), 'Matterbridge', `WebSocketServer client "${clientIp}" connected to Matterbridge`);
|
|
@@ -2405,7 +2549,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2405
2549
|
ws.on('close', () => {
|
|
2406
2550
|
this.log.info('WebSocket client disconnected');
|
|
2407
2551
|
if (this.webSocketServer?.clients.size === 0) {
|
|
2408
|
-
|
|
2552
|
+
AnsiLogger.setGlobalCallback(undefined);
|
|
2409
2553
|
this.log.debug('All WebSocket clients disconnected. WebSocketServer logger global callback removed');
|
|
2410
2554
|
}
|
|
2411
2555
|
});
|
|
@@ -2441,6 +2585,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2441
2585
|
this.log.warn('/api/login error wrong password');
|
|
2442
2586
|
res.json({ valid: false });
|
|
2443
2587
|
}
|
|
2588
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2444
2589
|
}
|
|
2445
2590
|
catch (error) {
|
|
2446
2591
|
this.log.error('/api/login error getting password');
|
|
@@ -2460,6 +2605,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2460
2605
|
try {
|
|
2461
2606
|
qrPairingCode = await this.matterbridgeContext.get('qrPairingCode');
|
|
2462
2607
|
manualPairingCode = await this.matterbridgeContext.get('manualPairingCode');
|
|
2608
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2463
2609
|
}
|
|
2464
2610
|
catch (error) {
|
|
2465
2611
|
if (this.bridgeMode === 'bridge')
|
|
@@ -2477,12 +2623,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
2477
2623
|
this.matterbridgeInformation.profile = this.profile;
|
|
2478
2624
|
const response = { wssHost, ssl: hasParameter('ssl'), qrPairingCode, manualPairingCode, systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
|
|
2479
2625
|
// this.log.debug('Response:', debugStringify(response));
|
|
2480
|
-
|
|
2481
|
-
this.
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
this.log.debug('WebSocketServer logger global callback added');
|
|
2626
|
+
/*
|
|
2627
|
+
if (this.webSocketServer && this.webSocketServer.clients.size > 0 && !AnsiLogger.getGlobalCallback()) {
|
|
2628
|
+
AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), LogLevel.DEBUG);
|
|
2629
|
+
this.log.debug('WebSocketServer logger global callback added');
|
|
2485
2630
|
}
|
|
2631
|
+
*/
|
|
2486
2632
|
res.json(response);
|
|
2487
2633
|
});
|
|
2488
2634
|
// Endpoint to provide plugins
|
|
@@ -2595,6 +2741,85 @@ export class Matterbridge extends EventEmitter {
|
|
|
2595
2741
|
});
|
|
2596
2742
|
res.json(data);
|
|
2597
2743
|
});
|
|
2744
|
+
// Endpoint to send the log
|
|
2745
|
+
this.expressApp.get('/api/view-log', async (req, res) => {
|
|
2746
|
+
this.log.debug('The frontend sent /api/log');
|
|
2747
|
+
try {
|
|
2748
|
+
const data = await fs.readFile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), 'utf8');
|
|
2749
|
+
res.type('text/plain');
|
|
2750
|
+
res.send(data);
|
|
2751
|
+
}
|
|
2752
|
+
catch (error) {
|
|
2753
|
+
this.log.error(`Error reading log file ${this.matterbrideLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
2754
|
+
res.status(500).send('Error reading log file');
|
|
2755
|
+
}
|
|
2756
|
+
});
|
|
2757
|
+
// Endpoint to download the matterbridge log
|
|
2758
|
+
this.expressApp.get('/api/download-mblog', async (req, res) => {
|
|
2759
|
+
this.log.debug('The frontend sent /api/download-mblog');
|
|
2760
|
+
try {
|
|
2761
|
+
await fs.access(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), fs.constants.F_OK);
|
|
2762
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2763
|
+
}
|
|
2764
|
+
catch (error) {
|
|
2765
|
+
fs.appendFile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
|
|
2766
|
+
}
|
|
2767
|
+
res.download(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), 'matterbridge.log', (error) => {
|
|
2768
|
+
if (error) {
|
|
2769
|
+
this.log.error(`Error downloading log file ${this.matterbrideLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
2770
|
+
res.status(500).send('Error downloading the matterbridge log file');
|
|
2771
|
+
}
|
|
2772
|
+
});
|
|
2773
|
+
});
|
|
2774
|
+
// Endpoint to download the matter log
|
|
2775
|
+
this.expressApp.get('/api/download-mjlog', async (req, res) => {
|
|
2776
|
+
this.log.debug('The frontend sent /api/download-mjlog');
|
|
2777
|
+
try {
|
|
2778
|
+
await fs.access(path.join(this.matterbridgeDirectory, this.matterLoggerFile), fs.constants.F_OK);
|
|
2779
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2780
|
+
}
|
|
2781
|
+
catch (error) {
|
|
2782
|
+
fs.appendFile(path.join(this.matterbridgeDirectory, this.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
|
|
2783
|
+
}
|
|
2784
|
+
res.download(path.join(this.matterbridgeDirectory, this.matterLoggerFile), 'matter.log', (error) => {
|
|
2785
|
+
if (error) {
|
|
2786
|
+
this.log.error(`Error downloading log file ${this.matterLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
2787
|
+
res.status(500).send('Error downloading the matter log file');
|
|
2788
|
+
}
|
|
2789
|
+
});
|
|
2790
|
+
});
|
|
2791
|
+
// Endpoint to download the matter storage file
|
|
2792
|
+
this.expressApp.get('/api/download-mjstorage', (req, res) => {
|
|
2793
|
+
this.log.debug('The frontend sent /api/download-mjstorage');
|
|
2794
|
+
res.download(path.join(this.matterbridgeDirectory, this.matterStorageName), 'matterbridge.json', (error) => {
|
|
2795
|
+
if (error) {
|
|
2796
|
+
this.log.error(`Error downloading log file ${this.matterStorageName}: ${error instanceof Error ? error.message : error}`);
|
|
2797
|
+
res.status(500).send('Error downloading the matter storage file');
|
|
2798
|
+
}
|
|
2799
|
+
});
|
|
2800
|
+
});
|
|
2801
|
+
// Endpoint to download the matterbridge storage directory
|
|
2802
|
+
this.expressApp.get('/api/download-mbstorage', async (req, res) => {
|
|
2803
|
+
this.log.debug('The frontend sent /api/download-mbstorage');
|
|
2804
|
+
await zipDirectory(path.join(this.matterbridgeDirectory, `matterbridge.${this.nodeStorageName}.zip`), path.join(this.matterbridgeDirectory, this.nodeStorageName));
|
|
2805
|
+
res.download(path.join(this.matterbridgeDirectory, `matterbridge.${this.nodeStorageName}.zip`), `matterbridge.${this.nodeStorageName}.zip`, (error) => {
|
|
2806
|
+
if (error) {
|
|
2807
|
+
this.log.error(`Error downloading file ${`matterbridge.${this.nodeStorageName}.zip`}: ${error instanceof Error ? error.message : error}`);
|
|
2808
|
+
res.status(500).send('Error downloading the matterbridge storage file');
|
|
2809
|
+
}
|
|
2810
|
+
});
|
|
2811
|
+
});
|
|
2812
|
+
// Endpoint to download the matterbridge plugin directory
|
|
2813
|
+
this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
|
|
2814
|
+
this.log.debug('The frontend sent /api/download-pluginstorage');
|
|
2815
|
+
await zipDirectory(path.join(this.matterbridgeDirectory, `matterbridge.pluginstorage.zip`), this.matterbridgePluginDirectory);
|
|
2816
|
+
res.download(path.join(this.matterbridgeDirectory, `matterbridge.pluginstorage.zip`), `matterbridge.pluginstorage.zip`, (error) => {
|
|
2817
|
+
if (error) {
|
|
2818
|
+
this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
|
|
2819
|
+
res.status(500).send('Error downloading the matterbridge plugin storage file');
|
|
2820
|
+
}
|
|
2821
|
+
});
|
|
2822
|
+
});
|
|
2598
2823
|
// Endpoint to receive commands
|
|
2599
2824
|
this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
|
|
2600
2825
|
const command = req.params.command;
|
|
@@ -2671,6 +2896,53 @@ export class Matterbridge extends EventEmitter {
|
|
|
2671
2896
|
res.json({ message: 'Command received' });
|
|
2672
2897
|
return;
|
|
2673
2898
|
}
|
|
2899
|
+
// Handle the command setmbloglevel from Settings
|
|
2900
|
+
if (command === 'setmblogfile') {
|
|
2901
|
+
this.log.debug('Matterbridge file log:', param);
|
|
2902
|
+
this.matterbridgeInformation.fileLogger = param === 'true';
|
|
2903
|
+
await this.nodeContext?.set('matterbridgeFileLog', param === 'true');
|
|
2904
|
+
// Create the file logger for matterbridge
|
|
2905
|
+
if (param === 'true')
|
|
2906
|
+
AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
|
|
2907
|
+
else
|
|
2908
|
+
AnsiLogger.setGlobalLogfile(undefined);
|
|
2909
|
+
res.json({ message: 'Command received' });
|
|
2910
|
+
return;
|
|
2911
|
+
}
|
|
2912
|
+
// Handle the command setmbloglevel from Settings
|
|
2913
|
+
if (command === 'setmjlogfile') {
|
|
2914
|
+
this.log.debug('Matter file log:', param);
|
|
2915
|
+
this.matterbridgeInformation.matterFileLogger = param === 'true';
|
|
2916
|
+
await this.nodeContext?.set('matterFileLog', param === 'true');
|
|
2917
|
+
if (param === 'true') {
|
|
2918
|
+
/*
|
|
2919
|
+
try {
|
|
2920
|
+
await fs.unlink(path.join(this.matterbridgeDirectory, this.matterLoggerFile));
|
|
2921
|
+
} catch (error) {
|
|
2922
|
+
this.log.debug(`Error unlinking the log file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
|
|
2923
|
+
}
|
|
2924
|
+
*/
|
|
2925
|
+
try {
|
|
2926
|
+
Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
|
|
2927
|
+
defaultLogLevel: Level.DEBUG,
|
|
2928
|
+
logFormat: Format.PLAIN,
|
|
2929
|
+
});
|
|
2930
|
+
}
|
|
2931
|
+
catch (error) {
|
|
2932
|
+
this.log.debug(`Error adding the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
|
|
2933
|
+
}
|
|
2934
|
+
}
|
|
2935
|
+
else {
|
|
2936
|
+
try {
|
|
2937
|
+
Logger.removeLogger('matterfilelogger');
|
|
2938
|
+
}
|
|
2939
|
+
catch (error) {
|
|
2940
|
+
this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
|
|
2941
|
+
}
|
|
2942
|
+
}
|
|
2943
|
+
res.json({ message: 'Command received' });
|
|
2944
|
+
return;
|
|
2945
|
+
}
|
|
2674
2946
|
// Handle the command unregister from Settings
|
|
2675
2947
|
if (command === 'unregister') {
|
|
2676
2948
|
await this.unregisterAndShutdownProcess();
|
|
@@ -2707,6 +2979,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2707
2979
|
try {
|
|
2708
2980
|
await this.spawnCommand('npm', ['install', '-g', 'matterbridge']);
|
|
2709
2981
|
this.log.info('Matterbridge has been updated. Full restart required.');
|
|
2982
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2710
2983
|
}
|
|
2711
2984
|
catch (error) {
|
|
2712
2985
|
this.log.error('Error updating matterbridge');
|
|
@@ -2739,6 +3012,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
2739
3012
|
try {
|
|
2740
3013
|
await this.spawnCommand('npm', ['install', '-g', param]);
|
|
2741
3014
|
this.log.info(`Plugin ${plg}${param}${nf} installed. Full restart required.`);
|
|
3015
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2742
3016
|
}
|
|
2743
3017
|
catch (error) {
|
|
2744
3018
|
this.log.error(`Error installing plugin ${plg}${param}${er}`);
|