matterbridge 1.4.2 → 1.5.0
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 +55 -0
- package/README-ADVANCED.md +197 -0
- package/README-DEV.md +167 -0
- package/README.md +26 -318
- package/dist/matterbridge.d.ts +17 -1
- package/dist/matterbridge.d.ts.map +1 -1
- package/dist/matterbridge.js +307 -92
- package/dist/matterbridge.js.map +1 -1
- package/dist/matterbridgeTypes.d.ts +4 -0
- package/dist/matterbridgeTypes.d.ts.map +1 -1
- package/dist/pluginManager.d.ts.map +1 -1
- package/dist/pluginManager.js +14 -3
- package/dist/pluginManager.js.map +1 -1
- package/dist/utils/utils.d.ts +21 -1
- package/dist/utils/utils.d.ts.map +1 -1
- package/dist/utils/utils.js +95 -1
- package/dist/utils/utils.js.map +1 -1
- package/frontend/build/asset-manifest.json +8 -8
- 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/453.abd36b29.chunk.js +2 -0
- package/frontend/build/static/js/{453.d855a71b.chunk.js.map → 453.abd36b29.chunk.js.map} +1 -1
- package/frontend/build/static/js/main.4c5271fd.js +3 -0
- package/frontend/build/static/js/main.4c5271fd.js.map +1 -0
- package/package.json +12 -9
- 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/453.d855a71b.chunk.js +0 -2
- package/frontend/build/static/js/main.dec34964.js +0 -3
- package/frontend/build/static/js/main.dec34964.js.map +0 -1
- /package/frontend/build/static/js/{main.dec34964.js.LICENSE.txt → main.4c5271fd.js.LICENSE.txt} +0 -0
package/dist/matterbridge.js
CHANGED
|
@@ -20,8 +20,7 @@
|
|
|
20
20
|
* See the License for the specific language governing permissions and
|
|
21
21
|
* limitations under the License. *
|
|
22
22
|
*/
|
|
23
|
-
|
|
24
|
-
import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, stringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, hk, or, idn, BLUE, CYAN, nt } from 'node-ansi-logger';
|
|
23
|
+
// Node.js modules
|
|
25
24
|
import { fileURLToPath } from 'url';
|
|
26
25
|
import { promises as fs } from 'fs';
|
|
27
26
|
import { exec, spawn } from 'child_process';
|
|
@@ -32,19 +31,22 @@ import express from 'express';
|
|
|
32
31
|
import os from 'os';
|
|
33
32
|
import path from 'path';
|
|
34
33
|
import WebSocket, { WebSocketServer } from 'ws';
|
|
34
|
+
// NodeStorage and AnsiLogger modules
|
|
35
|
+
import { NodeStorageManager } from 'node-persist-manager';
|
|
36
|
+
import { AnsiLogger, UNDERLINE, UNDERLINEOFF, YELLOW, db, debugStringify, stringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, hk, or, idn, BLUE, CYAN, nt } from 'node-ansi-logger';
|
|
35
37
|
// Matterbridge
|
|
36
38
|
import { MatterbridgeDevice } from './matterbridgeDevice.js';
|
|
37
39
|
import { BridgedDeviceBasicInformation, BridgedDeviceBasicInformationCluster } from './cluster/BridgedDeviceBasicInformationCluster.js';
|
|
38
|
-
import { logInterfaces, wait, waiter } from './utils/utils.js';
|
|
40
|
+
import { logInterfaces, wait, waiter, createZip } from './utils/utils.js';
|
|
39
41
|
// @project-chip/matter-node.js
|
|
40
42
|
import { CommissioningController, CommissioningServer, MatterServer } from '@project-chip/matter-node.js';
|
|
41
43
|
import { BasicInformationCluster, ClusterServer, FixedLabelCluster, GeneralCommissioning, PowerSourceCluster, SwitchCluster, ThreadNetworkDiagnosticsCluster, getClusterNameById } from '@project-chip/matter-node.js/cluster';
|
|
42
44
|
import { DeviceTypeId, VendorId } from '@project-chip/matter-node.js/datatype';
|
|
43
45
|
import { Aggregator, DeviceTypes, NodeStateInformation } from '@project-chip/matter-node.js/device';
|
|
44
|
-
import {
|
|
46
|
+
import { Format, Level, Logger } from '@project-chip/matter-node.js/log';
|
|
45
47
|
import { ManualPairingCodeCodec, QrCodeSchema } from '@project-chip/matter-node.js/schema';
|
|
46
48
|
import { StorageBackendDisk, StorageBackendJsonFile, StorageManager } from '@project-chip/matter-node.js/storage';
|
|
47
|
-
import {
|
|
49
|
+
import { getParameter, getIntParameter, hasParameter } from '@project-chip/matter-node.js/util';
|
|
48
50
|
import { CryptoNode } from '@project-chip/matter-node.js/crypto';
|
|
49
51
|
import { PluginManager } from './pluginManager.js';
|
|
50
52
|
import { DeviceManager } from './deviceManager.js';
|
|
@@ -80,6 +82,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
80
82
|
globalModulesDirectory: '',
|
|
81
83
|
matterbridgeVersion: '',
|
|
82
84
|
matterbridgeLatestVersion: '',
|
|
85
|
+
matterbridgeQrPairingCode: undefined,
|
|
86
|
+
matterbridgeManualPairingCode: undefined,
|
|
83
87
|
matterbridgeFabricInformations: [],
|
|
84
88
|
matterbridgeSessionInformations: [],
|
|
85
89
|
matterbridgePaired: false,
|
|
@@ -87,7 +91,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
87
91
|
bridgeMode: '',
|
|
88
92
|
restartMode: '',
|
|
89
93
|
loggerLevel: "info" /* LogLevel.INFO */,
|
|
94
|
+
fileLogger: false,
|
|
90
95
|
matterLoggerLevel: Level.INFO,
|
|
96
|
+
matterFileLogger: false,
|
|
91
97
|
};
|
|
92
98
|
homeDirectory = '';
|
|
93
99
|
rootDirectory = '';
|
|
@@ -96,14 +102,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
96
102
|
globalModulesDirectory = '';
|
|
97
103
|
matterbridgeVersion = '';
|
|
98
104
|
matterbridgeLatestVersion = '';
|
|
105
|
+
matterbridgeQrPairingCode = undefined;
|
|
106
|
+
matterbridgeManualPairingCode = undefined;
|
|
99
107
|
matterbridgeFabricInformations = [];
|
|
100
108
|
matterbridgeSessionInformations = [];
|
|
101
109
|
matterbridgePaired = false;
|
|
102
110
|
matterbridgeConnected = false;
|
|
103
111
|
bridgeMode = '';
|
|
104
112
|
restartMode = '';
|
|
105
|
-
// public debugEnabled = false;
|
|
106
|
-
// public loggerLevel: LogLevel = LogLevel.INFO;
|
|
107
113
|
profile = getParameter('profile');
|
|
108
114
|
log;
|
|
109
115
|
matterbrideLoggerFile = 'matterbridge' + (getParameter('profile') ? '.' + getParameter('profile') : '') + '.log';
|
|
@@ -119,6 +125,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
119
125
|
hasCleanupStarted = false;
|
|
120
126
|
initialized = false;
|
|
121
127
|
execRunningCount = 0;
|
|
128
|
+
startMatterInterval;
|
|
122
129
|
cleanupTimeout1;
|
|
123
130
|
cleanupTimeout2;
|
|
124
131
|
checkUpdateInterval;
|
|
@@ -208,12 +215,19 @@ export class Matterbridge extends EventEmitter {
|
|
|
208
215
|
// Set the matterbridge directory
|
|
209
216
|
this.homeDirectory = os.homedir();
|
|
210
217
|
this.matterbridgeDirectory = path.join(this.homeDirectory, '.matterbridge');
|
|
211
|
-
//
|
|
212
|
-
|
|
213
|
-
|
|
218
|
+
// Initialize nodeStorage and nodeContext
|
|
219
|
+
// this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
|
|
220
|
+
this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
|
|
221
|
+
// this.log.debug('Creating node storage context for matterbridge');
|
|
222
|
+
this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
|
|
214
223
|
// Create matterbridge logger
|
|
215
224
|
this.log = new AnsiLogger({ logName: 'Matterbridge', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "info" /* LogLevel.INFO */ });
|
|
216
|
-
//
|
|
225
|
+
// Create the file logger for matterbridge (context: matterbridgeFileLog)
|
|
226
|
+
if (hasParameter('filelogger') || (await this.nodeContext.get('matterbridgeFileLog', false))) {
|
|
227
|
+
AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
|
|
228
|
+
this.matterbridgeInformation.fileLogger = true;
|
|
229
|
+
}
|
|
230
|
+
// Set matterbridge logger level (context: matterbridgeLogLevel)
|
|
217
231
|
if (hasParameter('logger')) {
|
|
218
232
|
const level = getParameter('logger');
|
|
219
233
|
if (level === 'debug') {
|
|
@@ -240,11 +254,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
240
254
|
}
|
|
241
255
|
}
|
|
242
256
|
else {
|
|
243
|
-
this.log.logLevel = "info" /* LogLevel.INFO
|
|
257
|
+
this.log.logLevel = await this.nodeContext.get('matterbridgeLogLevel', "info" /* LogLevel.INFO */);
|
|
244
258
|
}
|
|
245
259
|
MatterbridgeDevice.logLevel = this.log.logLevel;
|
|
246
260
|
this.log.debug('Matterbridge is starting...');
|
|
247
|
-
|
|
261
|
+
this.log.debug(`Matterbridge logLevel: ${this.log.logLevel} fileLoger: ${this.matterbridgeInformation.fileLogger}.`);
|
|
262
|
+
// Set matter.js logger level, format and logger (context: matterLogLevel)
|
|
248
263
|
if (hasParameter('matterlogger')) {
|
|
249
264
|
const level = getParameter('matterlogger');
|
|
250
265
|
if (level === 'debug') {
|
|
@@ -271,28 +286,19 @@ export class Matterbridge extends EventEmitter {
|
|
|
271
286
|
}
|
|
272
287
|
}
|
|
273
288
|
else {
|
|
274
|
-
Logger.defaultLogLevel = Level.INFO;
|
|
289
|
+
Logger.defaultLogLevel = await this.nodeContext.get('matterLogLevel', Level.INFO);
|
|
275
290
|
}
|
|
276
291
|
Logger.format = Format.ANSI;
|
|
277
292
|
Logger.setLogger('default', this.createMatterLogger());
|
|
278
|
-
// Create the file logger for matter.js
|
|
279
|
-
if (hasParameter('matterfilelogger')) {
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
catch (error) {
|
|
284
|
-
this.log.debug(`Error unlinking the log file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
|
|
285
|
-
}
|
|
286
|
-
Logger.addLogger('filelogger', await createFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile)), {
|
|
293
|
+
// Create the file logger for matter.js (context: matterFileLog)
|
|
294
|
+
if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
|
|
295
|
+
this.matterbridgeInformation.matterFileLogger = true;
|
|
296
|
+
Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
|
|
287
297
|
defaultLogLevel: Level.DEBUG,
|
|
288
298
|
logFormat: Format.PLAIN,
|
|
289
299
|
});
|
|
290
300
|
}
|
|
291
|
-
|
|
292
|
-
this.log.debug(`Creating node storage manager: ${CYAN}${this.nodeStorageName}${db}`);
|
|
293
|
-
this.nodeStorage = new NodeStorageManager({ dir: path.join(this.matterbridgeDirectory, this.nodeStorageName), writeQueue: false, expiredInterval: undefined, logging: false });
|
|
294
|
-
this.log.debug('Creating node storage context for matterbridge');
|
|
295
|
-
this.nodeContext = await this.nodeStorage.createStorage('matterbridge');
|
|
301
|
+
this.log.debug(`Matter logLevel: ${Logger.defaultLogLevel} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
|
|
296
302
|
// Initialize PluginManager
|
|
297
303
|
this.plugins = new PluginManager(this);
|
|
298
304
|
await this.plugins.loadFromStorage();
|
|
@@ -301,8 +307,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
301
307
|
// Get the plugins from node storage and create the plugins node storage contexts
|
|
302
308
|
for (const plugin of this.plugins) {
|
|
303
309
|
const packageJson = await this.plugins.parse(plugin);
|
|
304
|
-
if (packageJson === null) {
|
|
310
|
+
if (packageJson === null && !hasParameter('add')) {
|
|
305
311
|
// Try to reinstall the plugin from npm (for Docker pull and external plugins)
|
|
312
|
+
// We don't do this when the add parameter is set because we shut down the process after adding the plugin
|
|
306
313
|
this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
|
|
307
314
|
try {
|
|
308
315
|
await this.spawnCommand('npm', ['install', '-g', plugin.name]);
|
|
@@ -327,10 +334,20 @@ export class Matterbridge extends EventEmitter {
|
|
|
327
334
|
}
|
|
328
335
|
// Log system info and create .matterbridge directory
|
|
329
336
|
await this.logNodeAndSystemInfo();
|
|
330
|
-
this.log.notice(`Matterbridge version ${this.matterbridgeVersion}
|
|
331
|
-
`${
|
|
337
|
+
this.log.notice(`Matterbridge version ${this.matterbridgeVersion} ` +
|
|
338
|
+
`${hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge') ? 'mode bridge ' : ''}` +
|
|
339
|
+
`${hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge') ? 'mode childbridge ' : ''}` +
|
|
340
|
+
`${hasParameter('controller') ? 'mode controller ' : ''}` +
|
|
341
|
+
`${this.restartMode !== '' ? 'restart mode ' + this.restartMode + ' ' : ''}` +
|
|
342
|
+
`running on ${this.systemInformation.osType} (v.${this.systemInformation.osRelease}) platform ${this.systemInformation.osPlatform} arch ${this.systemInformation.osArch}`);
|
|
332
343
|
// Check node version and throw error
|
|
333
|
-
|
|
344
|
+
const minNodeVersion = 18;
|
|
345
|
+
const nodeVersion = process.versions.node;
|
|
346
|
+
const versionMajor = parseInt(nodeVersion.split('.')[0]);
|
|
347
|
+
if (versionMajor < minNodeVersion) {
|
|
348
|
+
this.log.error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
|
|
349
|
+
throw new Error(`Node version ${versionMajor} is not supported. Please upgrade to ${minNodeVersion} or above.`);
|
|
350
|
+
}
|
|
334
351
|
// Register SIGINT SIGTERM signal handlers
|
|
335
352
|
this.registerSignalHandlers();
|
|
336
353
|
// Parse command line
|
|
@@ -351,6 +368,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
351
368
|
- childbridge: start Matterbridge in childbridge mode
|
|
352
369
|
- port [port]: start the commissioning server on the given port (default 5540)
|
|
353
370
|
- mdnsinterface [name]: set the interface to use for the matter server mdnsInterface (default all interfaces)
|
|
371
|
+
- ipv4address [address]: set the ipv4 interface address to use for the matter listener (default all interfaces)
|
|
372
|
+
- ipv6address [address]: set the ipv6 interface address to use for the matter listener (default all interfaces)
|
|
354
373
|
- frontend [port]: start the frontend on the given port (default 8283)
|
|
355
374
|
- logger: set the matterbridge logger level: debug | info | notice | warn | error | fatal (default info)
|
|
356
375
|
- matterlogger: set the matter.js logger level: debug | info | notice | warn | error | fatal (default info)
|
|
@@ -511,8 +530,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
511
530
|
}
|
|
512
531
|
}, 60 * 60 * 1000);
|
|
513
532
|
if (hasParameter('test')) {
|
|
514
|
-
this.bridgeMode = '
|
|
515
|
-
MatterbridgeDevice.bridgeMode = '
|
|
533
|
+
this.bridgeMode = 'bridge';
|
|
534
|
+
MatterbridgeDevice.bridgeMode = 'bridge';
|
|
516
535
|
await this.startTest();
|
|
517
536
|
return;
|
|
518
537
|
}
|
|
@@ -521,7 +540,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
521
540
|
await this.startController();
|
|
522
541
|
return;
|
|
523
542
|
}
|
|
524
|
-
if
|
|
543
|
+
// Check if the bridge mode is set and start matterbridge in bridge mode if not set
|
|
544
|
+
if (!hasParameter('bridge') && !hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === '') {
|
|
545
|
+
this.log.info('Setting default matterbridge start mode to bridge');
|
|
546
|
+
await this.nodeContext?.set('bridgeMode', 'bridge');
|
|
547
|
+
}
|
|
548
|
+
if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
|
|
525
549
|
this.bridgeMode = 'bridge';
|
|
526
550
|
MatterbridgeDevice.bridgeMode = 'bridge';
|
|
527
551
|
if (!this.storageManager)
|
|
@@ -562,12 +586,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
562
586
|
plugin.addedDevices = undefined;
|
|
563
587
|
plugin.qrPairingCode = undefined;
|
|
564
588
|
plugin.manualPairingCode = undefined;
|
|
565
|
-
this.plugins.load(plugin, true, 'Matterbridge is starting'); //
|
|
589
|
+
this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
|
|
566
590
|
}
|
|
567
591
|
await this.startBridge();
|
|
568
592
|
return;
|
|
569
593
|
}
|
|
570
|
-
if (hasParameter('childbridge')) {
|
|
594
|
+
if (hasParameter('childbridge') || (!hasParameter('bridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'childbridge')) {
|
|
571
595
|
this.bridgeMode = 'childbridge';
|
|
572
596
|
MatterbridgeDevice.bridgeMode = 'childbridge';
|
|
573
597
|
if (!this.storageManager)
|
|
@@ -598,9 +622,9 @@ export class Matterbridge extends EventEmitter {
|
|
|
598
622
|
plugin.connected = false;
|
|
599
623
|
plugin.registeredDevices = undefined;
|
|
600
624
|
plugin.addedDevices = undefined;
|
|
601
|
-
plugin.qrPairingCode =
|
|
602
|
-
plugin.manualPairingCode =
|
|
603
|
-
this.plugins.load(plugin, true, 'Matterbridge is starting'); //
|
|
625
|
+
plugin.qrPairingCode = undefined;
|
|
626
|
+
plugin.manualPairingCode = undefined;
|
|
627
|
+
this.plugins.load(plugin, true, 'Matterbridge is starting'); // No await do it asyncronously
|
|
604
628
|
}
|
|
605
629
|
await this.startChildbridge();
|
|
606
630
|
return;
|
|
@@ -847,7 +871,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
847
871
|
this.log.debug(`Matterbridge Latest Version: ${this.matterbridgeLatestVersion}`);
|
|
848
872
|
await this.nodeContext?.set('matterbridgeLatestVersion', this.matterbridgeLatestVersion);
|
|
849
873
|
if (this.matterbridgeVersion !== this.matterbridgeLatestVersion) {
|
|
850
|
-
this.log.
|
|
874
|
+
this.log.notice(`Matterbridge is out of date. Current version: ${this.matterbridgeVersion}. Latest version: ${this.matterbridgeLatestVersion}.`);
|
|
875
|
+
}
|
|
876
|
+
else {
|
|
877
|
+
this.log.debug(`Matterbridge is up to date. Current version: ${this.matterbridgeVersion}. Latest version: ${this.matterbridgeLatestVersion}.`);
|
|
851
878
|
}
|
|
852
879
|
})
|
|
853
880
|
.catch((error) => {
|
|
@@ -870,15 +897,20 @@ export class Matterbridge extends EventEmitter {
|
|
|
870
897
|
.then(async (latestVersion) => {
|
|
871
898
|
plugin.latestVersion = latestVersion;
|
|
872
899
|
if (plugin.version !== latestVersion)
|
|
873
|
-
this.log.
|
|
900
|
+
this.log.notice(`The plugin ${plg}${plugin.name}${nt} is out of date. Current version: ${plugin.version}. Latest version: ${latestVersion}.`);
|
|
874
901
|
else
|
|
875
|
-
this.log.
|
|
902
|
+
this.log.debug(`The plugin ${plg}${plugin.name}${db} is up to date. Current version: ${plugin.version}. Latest version: ${latestVersion}.`);
|
|
876
903
|
})
|
|
877
904
|
.catch((error) => {
|
|
878
|
-
this.log.error(`Error getting ${plugin.name} latest version: ${error.message}`);
|
|
905
|
+
this.log.error(`Error getting ${plg}${plugin.name}${er} latest version: ${error.message}`);
|
|
879
906
|
// error.stack && this.log.debug(error.stack);
|
|
880
907
|
});
|
|
881
908
|
}
|
|
909
|
+
/**
|
|
910
|
+
* Creates a MatterLogger function to show the matter.js log messages in AnsiLogger (for the frontend).
|
|
911
|
+
*
|
|
912
|
+
* @returns {Function} The MatterLogger function.
|
|
913
|
+
*/
|
|
882
914
|
createMatterLogger() {
|
|
883
915
|
const matterLogger = new AnsiLogger({ logName: 'Matter', logTimestampFormat: 4 /* TimestampFormat.TIME_MILLIS */, logLevel: "debug" /* LogLevel.DEBUG */ });
|
|
884
916
|
return (_level, formattedLog) => {
|
|
@@ -910,6 +942,63 @@ export class Matterbridge extends EventEmitter {
|
|
|
910
942
|
}
|
|
911
943
|
};
|
|
912
944
|
}
|
|
945
|
+
/**
|
|
946
|
+
* Creates a Matter File Logger.
|
|
947
|
+
*
|
|
948
|
+
* @param {string} filePath - The path to the log file.
|
|
949
|
+
* @param {boolean} [unlink=false] - Whether to unlink the log file before creating a new one.
|
|
950
|
+
* @returns {Function} - A function that logs formatted messages to the log file.
|
|
951
|
+
*/
|
|
952
|
+
async createMatterFileLogger(filePath, unlink = false) {
|
|
953
|
+
// 2024-08-21 08:55:19.488 DEBUG InteractionMessenger Sending DataReport chunk with 28 attributes and 0 events: 1004 bytes
|
|
954
|
+
let fileSize = 0;
|
|
955
|
+
if (unlink) {
|
|
956
|
+
try {
|
|
957
|
+
await fs.unlink(filePath);
|
|
958
|
+
}
|
|
959
|
+
catch (error) {
|
|
960
|
+
this.log.debug(`Error unlinking the log file ${CYAN}${filePath}${db}: ${error instanceof Error ? error.message : error}`);
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
return async (_level, formattedLog) => {
|
|
964
|
+
if (fileSize > 100000000)
|
|
965
|
+
return;
|
|
966
|
+
fileSize += formattedLog.length;
|
|
967
|
+
if (fileSize > 100000000) {
|
|
968
|
+
await fs.appendFile(filePath, `Logging on file has been stoppped because the file size is greater then 100MB.` + os.EOL);
|
|
969
|
+
return;
|
|
970
|
+
}
|
|
971
|
+
const now = new Date();
|
|
972
|
+
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')}`;
|
|
973
|
+
const message = formattedLog.slice(24);
|
|
974
|
+
const parts = message.split(' ');
|
|
975
|
+
const logger = parts[1];
|
|
976
|
+
const finalMessage = parts.slice(2).join(' ') + os.EOL;
|
|
977
|
+
switch (_level) {
|
|
978
|
+
case Level.DEBUG:
|
|
979
|
+
await fs.appendFile(filePath, `[${timestamp}] [${logger}] [debug] ${finalMessage}`);
|
|
980
|
+
break;
|
|
981
|
+
case Level.INFO:
|
|
982
|
+
await fs.appendFile(filePath, `[${timestamp}] [${logger}] [info] ${finalMessage}`);
|
|
983
|
+
break;
|
|
984
|
+
case Level.NOTICE:
|
|
985
|
+
await fs.appendFile(filePath, `[${timestamp}] [${logger}] [notice] ${finalMessage}`);
|
|
986
|
+
break;
|
|
987
|
+
case Level.WARN:
|
|
988
|
+
await fs.appendFile(filePath, `[${timestamp}] [${logger}] [warn] ${finalMessage}`);
|
|
989
|
+
break;
|
|
990
|
+
case Level.ERROR:
|
|
991
|
+
await fs.appendFile(filePath, `[${timestamp}] [${logger}] [error] ${finalMessage}`);
|
|
992
|
+
break;
|
|
993
|
+
case Level.FATAL:
|
|
994
|
+
await fs.appendFile(filePath, `[${timestamp}] [${logger}] [fatal] ${finalMessage}`);
|
|
995
|
+
break;
|
|
996
|
+
default:
|
|
997
|
+
await fs.appendFile(filePath, `[${timestamp}] [${logger}] ${finalMessage}`);
|
|
998
|
+
break;
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
}
|
|
913
1002
|
/**
|
|
914
1003
|
* Update matterbridge and cleanup.
|
|
915
1004
|
*/
|
|
@@ -962,11 +1051,18 @@ export class Matterbridge extends EventEmitter {
|
|
|
962
1051
|
this.log.info(message);
|
|
963
1052
|
// Deregisters the SIGINT and SIGTERM signal handlers
|
|
964
1053
|
this.deregisterSignalHandlers();
|
|
1054
|
+
// Clear the start matter interval
|
|
1055
|
+
if (this.startMatterInterval) {
|
|
1056
|
+
clearInterval(this.startMatterInterval);
|
|
1057
|
+
this.startMatterInterval = undefined;
|
|
1058
|
+
this.log.debug('Start matter interval cleared');
|
|
1059
|
+
}
|
|
965
1060
|
// Clear the check update interval
|
|
966
|
-
if (this.checkUpdateInterval)
|
|
1061
|
+
if (this.checkUpdateInterval) {
|
|
967
1062
|
clearInterval(this.checkUpdateInterval);
|
|
968
|
-
|
|
969
|
-
|
|
1063
|
+
this.checkUpdateInterval = undefined;
|
|
1064
|
+
this.log.debug('Check update interval cleared');
|
|
1065
|
+
}
|
|
970
1066
|
// Clear the configure timeout
|
|
971
1067
|
if (this.configureTimeout) {
|
|
972
1068
|
clearTimeout(this.configureTimeout);
|
|
@@ -1033,6 +1129,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
1033
1129
|
await this.stopMatterServer();
|
|
1034
1130
|
// Closing matter storage
|
|
1035
1131
|
await this.stopMatterStorage();
|
|
1132
|
+
// Remove the matterfilelogger
|
|
1133
|
+
try {
|
|
1134
|
+
Logger.removeLogger('matterfilelogger');
|
|
1135
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
1136
|
+
}
|
|
1137
|
+
catch (error) {
|
|
1138
|
+
// this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
|
|
1139
|
+
}
|
|
1036
1140
|
// Serialize registeredDevices
|
|
1037
1141
|
if (this.nodeStorage && this.nodeContext) {
|
|
1038
1142
|
this.log.info('Saving registered devices...');
|
|
@@ -1192,8 +1296,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
1192
1296
|
this.log.error(`Error removing bridged device ${dev}${device.deviceName}${er} (${dev}${device.name}${er}) for plugin ${plg}${pluginName}${er}: matterAggregator not found`);
|
|
1193
1297
|
return;
|
|
1194
1298
|
}
|
|
1195
|
-
device.
|
|
1196
|
-
|
|
1299
|
+
if (device.number !== undefined) {
|
|
1300
|
+
device.setBridgedDeviceReachability(false);
|
|
1301
|
+
device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerReachableChangedEvent({ reachableNewValue: false });
|
|
1302
|
+
}
|
|
1197
1303
|
// device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerShutDownEvent({});
|
|
1198
1304
|
// device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerLeaveEvent({});
|
|
1199
1305
|
this.matterAggregator?.removeBridgedDevice(device);
|
|
@@ -1234,8 +1340,10 @@ export class Matterbridge extends EventEmitter {
|
|
|
1234
1340
|
return;
|
|
1235
1341
|
}
|
|
1236
1342
|
});
|
|
1237
|
-
device.
|
|
1238
|
-
|
|
1343
|
+
if (device.number !== undefined) {
|
|
1344
|
+
device.setBridgedDeviceReachability(false);
|
|
1345
|
+
device.getClusterServerById(BridgedDeviceBasicInformation.Cluster.id)?.triggerReachableChangedEvent({ reachableNewValue: false });
|
|
1346
|
+
}
|
|
1239
1347
|
plugin.aggregator.removeBridgedDevice(device);
|
|
1240
1348
|
}
|
|
1241
1349
|
this.log.info(`Removed bridged device(${plugin.registeredDevices}/${plugin.addedDevices}) ${dev}${device.deviceName}${nf} (${dev}${device.name}${nf}) for plugin ${plg}${pluginName}${nf}`);
|
|
@@ -1284,13 +1392,14 @@ export class Matterbridge extends EventEmitter {
|
|
|
1284
1392
|
// Plugins are configured by a timer when matter server is started and plugin.configured is set to true
|
|
1285
1393
|
this.log.debug('***Starting startMatterInterval in bridge mode');
|
|
1286
1394
|
let failCount = 0;
|
|
1287
|
-
|
|
1395
|
+
this.startMatterInterval = setInterval(async () => {
|
|
1288
1396
|
for (const plugin of this.plugins) {
|
|
1289
1397
|
// new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
|
|
1290
1398
|
if (!plugin.enabled)
|
|
1291
1399
|
continue;
|
|
1292
1400
|
if (plugin.error) {
|
|
1293
|
-
clearInterval(startMatterInterval);
|
|
1401
|
+
clearInterval(this.startMatterInterval);
|
|
1402
|
+
this.startMatterInterval = undefined;
|
|
1294
1403
|
this.log.debug('***Cleared startMatterInterval interval for Matterbridge for plugin in error state');
|
|
1295
1404
|
this.log.error(`The plugin ${plg}${plugin.name}${er} is in error state.`);
|
|
1296
1405
|
this.log.error('The bridge will not start until the problem is solved to prevent the controllers from deleting all registered devices.');
|
|
@@ -1307,7 +1416,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1307
1416
|
return;
|
|
1308
1417
|
}
|
|
1309
1418
|
}
|
|
1310
|
-
clearInterval(startMatterInterval);
|
|
1419
|
+
clearInterval(this.startMatterInterval);
|
|
1420
|
+
this.startMatterInterval = undefined;
|
|
1311
1421
|
this.log.debug('***Cleared startMatterInterval interval for Matterbridge');
|
|
1312
1422
|
await this.startMatterServer();
|
|
1313
1423
|
this.log.notice('Matter server started');
|
|
@@ -1348,14 +1458,15 @@ export class Matterbridge extends EventEmitter {
|
|
|
1348
1458
|
// Plugins are configured by a timer when matter server is started and plugin.configured is set to true
|
|
1349
1459
|
this.log.debug('***Starting start matter interval in childbridge mode...');
|
|
1350
1460
|
let failCount = 0;
|
|
1351
|
-
|
|
1461
|
+
this.startMatterInterval = setInterval(async () => {
|
|
1352
1462
|
let allStarted = true;
|
|
1353
1463
|
for (const plugin of this.plugins) {
|
|
1354
1464
|
// new code to not start the bridge if one plugin is in error cause the controllers will delete the devices loosing all the configuration
|
|
1355
1465
|
if (!plugin.enabled)
|
|
1356
1466
|
continue;
|
|
1357
1467
|
if (plugin.error) {
|
|
1358
|
-
clearInterval(startMatterInterval);
|
|
1468
|
+
clearInterval(this.startMatterInterval);
|
|
1469
|
+
this.startMatterInterval = undefined;
|
|
1359
1470
|
this.log.debug('***Cleared startMatterInterval interval for Matterbridge for plugin in error state');
|
|
1360
1471
|
this.log.error(`The plugin ${plg}${plugin.name}${er} is in error state.`);
|
|
1361
1472
|
this.log.error('The bridge will not start until the problem is solved to prevent the controllers from deleting all registered devices.');
|
|
@@ -1375,7 +1486,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1375
1486
|
}
|
|
1376
1487
|
if (!allStarted)
|
|
1377
1488
|
return;
|
|
1378
|
-
clearInterval(startMatterInterval);
|
|
1489
|
+
clearInterval(this.startMatterInterval);
|
|
1490
|
+
this.startMatterInterval = undefined;
|
|
1379
1491
|
this.log.debug('***Cleared startMatterInterval interval in childbridge mode');
|
|
1380
1492
|
await this.startMatterServer();
|
|
1381
1493
|
this.log.notice('Matter server started');
|
|
@@ -1800,8 +1912,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
1800
1912
|
this.log.debug(`Creating matter commissioning server for plugin ${plg}${pluginName}${db} with nodeLabel '${productName}' port ${this.port} passcode ${this.passcode} discriminator ${this.discriminator}`);
|
|
1801
1913
|
const commissioningServer = new CommissioningServer({
|
|
1802
1914
|
port: this.port++,
|
|
1803
|
-
|
|
1804
|
-
|
|
1915
|
+
listeningAddressIpv4: getParameter('ipv4address'),
|
|
1916
|
+
listeningAddressIpv6: getParameter('ipv6address'),
|
|
1805
1917
|
passcode: this.passcode,
|
|
1806
1918
|
discriminator: this.discriminator,
|
|
1807
1919
|
deviceName,
|
|
@@ -2028,16 +2140,15 @@ export class Matterbridge extends EventEmitter {
|
|
|
2028
2140
|
}
|
|
2029
2141
|
if (!commissioningServer.isCommissioned()) {
|
|
2030
2142
|
const { qrPairingCode, manualPairingCode } = commissioningServer.getPairingCode();
|
|
2031
|
-
await storageContext.set('qrPairingCode', qrPairingCode);
|
|
2032
|
-
await storageContext.set('manualPairingCode', manualPairingCode);
|
|
2033
|
-
await nodeContext.set('qrPairingCode', qrPairingCode);
|
|
2034
|
-
await nodeContext.set('manualPairingCode', manualPairingCode);
|
|
2035
2143
|
const QrCode = new QrCodeSchema();
|
|
2036
2144
|
this.log.info(`*The commissioning server on port ${commissioningServer.getPort()} for ${plg}${pluginName}${nf} is not commissioned. Pair it scanning the QR code:\n\n`);
|
|
2037
2145
|
// eslint-disable-next-line no-console
|
|
2038
|
-
|
|
2039
|
-
|
|
2146
|
+
if (this.log.logLevel === "debug" /* LogLevel.DEBUG */ || this.log.logLevel === "info" /* LogLevel.INFO */)
|
|
2147
|
+
console.log(`${QrCode.encode(qrPairingCode)}\n`);
|
|
2148
|
+
this.log.info(`${plg}${pluginName}${nf} \n\nqrPairingCode: ${qrPairingCode} \n\nManual pairing code: ${manualPairingCode}\n`);
|
|
2040
2149
|
if (pluginName === 'Matterbridge') {
|
|
2150
|
+
this.matterbridgeQrPairingCode = qrPairingCode;
|
|
2151
|
+
this.matterbridgeManualPairingCode = manualPairingCode;
|
|
2041
2152
|
this.matterbridgeFabricInformations = [];
|
|
2042
2153
|
this.matterbridgeSessionInformations = [];
|
|
2043
2154
|
this.matterbridgePaired = false;
|
|
@@ -2522,40 +2633,21 @@ export class Matterbridge extends EventEmitter {
|
|
|
2522
2633
|
// Endpoint to provide settings
|
|
2523
2634
|
this.expressApp.get('/api/settings', express.json(), async (req, res) => {
|
|
2524
2635
|
this.log.debug('The frontend sent /api/settings');
|
|
2525
|
-
if (!this.matterbridgeContext) {
|
|
2526
|
-
this.log.error('/api/settings matterbridgeContext not found');
|
|
2527
|
-
res.json({});
|
|
2528
|
-
return;
|
|
2529
|
-
}
|
|
2530
|
-
let qrPairingCode = '';
|
|
2531
|
-
let manualPairingCode = '';
|
|
2532
|
-
try {
|
|
2533
|
-
qrPairingCode = await this.matterbridgeContext.get('qrPairingCode');
|
|
2534
|
-
manualPairingCode = await this.matterbridgeContext.get('manualPairingCode');
|
|
2535
|
-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2536
|
-
}
|
|
2537
|
-
catch (error) {
|
|
2538
|
-
if (this.bridgeMode === 'bridge')
|
|
2539
|
-
this.log.warn('pairingCodes for /api/settings not found');
|
|
2540
|
-
}
|
|
2541
2636
|
this.matterbridgeInformation.bridgeMode = this.bridgeMode;
|
|
2542
2637
|
this.matterbridgeInformation.restartMode = this.restartMode;
|
|
2543
2638
|
this.matterbridgeInformation.loggerLevel = this.log.logLevel;
|
|
2544
2639
|
this.matterbridgeInformation.matterLoggerLevel = Logger.defaultLogLevel;
|
|
2545
2640
|
this.matterbridgeInformation.matterbridgePaired = this.matterbridgePaired;
|
|
2546
2641
|
this.matterbridgeInformation.matterbridgeConnected = this.matterbridgeConnected;
|
|
2642
|
+
this.matterbridgeInformation.matterbridgeQrPairingCode = this.matterbridgeQrPairingCode;
|
|
2643
|
+
this.matterbridgeInformation.matterbridgeManualPairingCode = this.matterbridgeManualPairingCode;
|
|
2547
2644
|
this.matterbridgeInformation.matterbridgeFabricInformations = this.matterbridgeFabricInformations;
|
|
2548
2645
|
this.matterbridgeInformation.matterbridgeSessionInformations = this.matterbridgeSessionInformations;
|
|
2549
2646
|
if (this.profile)
|
|
2550
2647
|
this.matterbridgeInformation.profile = this.profile;
|
|
2551
|
-
const response = { wssHost, ssl: hasParameter('ssl'), qrPairingCode, manualPairingCode, systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
|
|
2648
|
+
// const response = { wssHost, ssl: hasParameter('ssl'), qrPairingCode, manualPairingCode, systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
|
|
2649
|
+
const response = { wssHost, ssl: hasParameter('ssl'), systemInformation: this.systemInformation, matterbridgeInformation: this.matterbridgeInformation };
|
|
2552
2650
|
// this.log.debug('Response:', debugStringify(response));
|
|
2553
|
-
/*
|
|
2554
|
-
if (this.webSocketServer && this.webSocketServer.clients.size > 0 && !AnsiLogger.getGlobalCallback()) {
|
|
2555
|
-
AnsiLogger.setGlobalCallback(this.wssSendMessage.bind(this), LogLevel.DEBUG);
|
|
2556
|
-
this.log.debug('WebSocketServer logger global callback added');
|
|
2557
|
-
}
|
|
2558
|
-
*/
|
|
2559
2651
|
res.json(response);
|
|
2560
2652
|
});
|
|
2561
2653
|
// Endpoint to provide plugins
|
|
@@ -2681,9 +2773,16 @@ export class Matterbridge extends EventEmitter {
|
|
|
2681
2773
|
res.status(500).send('Error reading log file');
|
|
2682
2774
|
}
|
|
2683
2775
|
});
|
|
2684
|
-
// Endpoint to download the log
|
|
2685
|
-
this.expressApp.get('/api/download-mblog', (req, res) => {
|
|
2776
|
+
// Endpoint to download the matterbridge log
|
|
2777
|
+
this.expressApp.get('/api/download-mblog', async (req, res) => {
|
|
2686
2778
|
this.log.debug('The frontend sent /api/download-mblog');
|
|
2779
|
+
try {
|
|
2780
|
+
await fs.access(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), fs.constants.F_OK);
|
|
2781
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2782
|
+
}
|
|
2783
|
+
catch (error) {
|
|
2784
|
+
fs.appendFile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), 'Enable the log on file in the settings to enable the file logger');
|
|
2785
|
+
}
|
|
2687
2786
|
res.download(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), 'matterbridge.log', (error) => {
|
|
2688
2787
|
if (error) {
|
|
2689
2788
|
this.log.error(`Error downloading log file ${this.matterbrideLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
@@ -2691,9 +2790,16 @@ export class Matterbridge extends EventEmitter {
|
|
|
2691
2790
|
}
|
|
2692
2791
|
});
|
|
2693
2792
|
});
|
|
2694
|
-
// Endpoint to download the log
|
|
2695
|
-
this.expressApp.get('/api/download-mjlog', (req, res) => {
|
|
2793
|
+
// Endpoint to download the matter log
|
|
2794
|
+
this.expressApp.get('/api/download-mjlog', async (req, res) => {
|
|
2696
2795
|
this.log.debug('The frontend sent /api/download-mjlog');
|
|
2796
|
+
try {
|
|
2797
|
+
await fs.access(path.join(this.matterbridgeDirectory, this.matterLoggerFile), fs.constants.F_OK);
|
|
2798
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
2799
|
+
}
|
|
2800
|
+
catch (error) {
|
|
2801
|
+
fs.appendFile(path.join(this.matterbridgeDirectory, this.matterLoggerFile), 'Enable the log on file in the settings to enable the file logger');
|
|
2802
|
+
}
|
|
2697
2803
|
res.download(path.join(this.matterbridgeDirectory, this.matterLoggerFile), 'matter.log', (error) => {
|
|
2698
2804
|
if (error) {
|
|
2699
2805
|
this.log.error(`Error downloading log file ${this.matterLoggerFile}: ${error instanceof Error ? error.message : error}`);
|
|
@@ -2701,6 +2807,60 @@ export class Matterbridge extends EventEmitter {
|
|
|
2701
2807
|
}
|
|
2702
2808
|
});
|
|
2703
2809
|
});
|
|
2810
|
+
// Endpoint to download the matter storage file
|
|
2811
|
+
this.expressApp.get('/api/download-mjstorage', (req, res) => {
|
|
2812
|
+
this.log.debug('The frontend sent /api/download-mjstorage');
|
|
2813
|
+
res.download(path.join(this.matterbridgeDirectory, this.matterStorageName), 'matterbridge.json', (error) => {
|
|
2814
|
+
if (error) {
|
|
2815
|
+
this.log.error(`Error downloading log file ${this.matterStorageName}: ${error instanceof Error ? error.message : error}`);
|
|
2816
|
+
res.status(500).send('Error downloading the matter storage file');
|
|
2817
|
+
}
|
|
2818
|
+
});
|
|
2819
|
+
});
|
|
2820
|
+
// Endpoint to download the matterbridge storage directory
|
|
2821
|
+
this.expressApp.get('/api/download-mbstorage', async (req, res) => {
|
|
2822
|
+
this.log.debug('The frontend sent /api/download-mbstorage');
|
|
2823
|
+
await createZip(path.join(os.tmpdir(), `matterbridge.${this.nodeStorageName}.zip`), path.join(this.matterbridgeDirectory, this.nodeStorageName));
|
|
2824
|
+
res.download(path.join(os.tmpdir(), `matterbridge.${this.nodeStorageName}.zip`), `matterbridge.${this.nodeStorageName}.zip`, (error) => {
|
|
2825
|
+
if (error) {
|
|
2826
|
+
this.log.error(`Error downloading file ${`matterbridge.${this.nodeStorageName}.zip`}: ${error instanceof Error ? error.message : error}`);
|
|
2827
|
+
res.status(500).send('Error downloading the matterbridge storage file');
|
|
2828
|
+
}
|
|
2829
|
+
});
|
|
2830
|
+
});
|
|
2831
|
+
// Endpoint to download the matterbridge plugin directory
|
|
2832
|
+
this.expressApp.get('/api/download-pluginstorage', async (req, res) => {
|
|
2833
|
+
this.log.debug('The frontend sent /api/download-pluginstorage');
|
|
2834
|
+
await createZip(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), this.matterbridgePluginDirectory);
|
|
2835
|
+
res.download(path.join(os.tmpdir(), `matterbridge.pluginstorage.zip`), `matterbridge.pluginstorage.zip`, (error) => {
|
|
2836
|
+
if (error) {
|
|
2837
|
+
this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
|
|
2838
|
+
res.status(500).send('Error downloading the matterbridge plugin storage file');
|
|
2839
|
+
}
|
|
2840
|
+
});
|
|
2841
|
+
});
|
|
2842
|
+
// Endpoint to download the matterbridge plugin config files
|
|
2843
|
+
this.expressApp.get('/api/download-pluginconfig', async (req, res) => {
|
|
2844
|
+
this.log.debug('The frontend sent /api/download-pluginconfig');
|
|
2845
|
+
await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, '*.config.json')));
|
|
2846
|
+
// await createZip(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, 'certs', '*.*')), path.relative(process.cwd(), path.join(this.matterbridgeDirectory, '*.config.json')));
|
|
2847
|
+
res.download(path.join(os.tmpdir(), `matterbridge.pluginconfig.zip`), `matterbridge.pluginconfig.zip`, (error) => {
|
|
2848
|
+
if (error) {
|
|
2849
|
+
this.log.error(`Error downloading file matterbridge.pluginstorage.zip: ${error instanceof Error ? error.message : error}`);
|
|
2850
|
+
res.status(500).send('Error downloading the matterbridge plugin storage file');
|
|
2851
|
+
}
|
|
2852
|
+
});
|
|
2853
|
+
});
|
|
2854
|
+
// Endpoint to download the matterbridge plugin config files
|
|
2855
|
+
this.expressApp.get('/api/download-backup', async (req, res) => {
|
|
2856
|
+
this.log.debug('The frontend sent /api/download-backup');
|
|
2857
|
+
res.download(path.join(os.tmpdir(), `matterbridge.backup.zip`), `matterbridge.backup.zip`, (error) => {
|
|
2858
|
+
if (error) {
|
|
2859
|
+
this.log.error(`Error downloading file matterbridge.backup.zip: ${error instanceof Error ? error.message : error}`);
|
|
2860
|
+
res.status(500).send(`Error downloading file matterbridge.backup.zip: ${error instanceof Error ? error.message : error}`);
|
|
2861
|
+
}
|
|
2862
|
+
});
|
|
2863
|
+
});
|
|
2704
2864
|
// Endpoint to receive commands
|
|
2705
2865
|
this.expressApp.post('/api/command/:command/:param', express.json(), async (req, res) => {
|
|
2706
2866
|
const command = req.params.command;
|
|
@@ -2719,6 +2879,21 @@ export class Matterbridge extends EventEmitter {
|
|
|
2719
2879
|
res.json({ message: 'Command received' });
|
|
2720
2880
|
return;
|
|
2721
2881
|
}
|
|
2882
|
+
// Handle the command setbridgemode from Settings
|
|
2883
|
+
if (command === 'setbridgemode') {
|
|
2884
|
+
this.log.debug(`setbridgemode: ${param}`);
|
|
2885
|
+
await this.nodeContext?.set('bridgeMode', param);
|
|
2886
|
+
res.json({ message: 'Command received' });
|
|
2887
|
+
return;
|
|
2888
|
+
}
|
|
2889
|
+
// Handle the command backup from Settings
|
|
2890
|
+
if (command === 'backup') {
|
|
2891
|
+
this.log.notice(`Prepairing the backup...`);
|
|
2892
|
+
await createZip(path.join(os.tmpdir(), `matterbridge.backup.zip`), path.join(this.matterbridgeDirectory), path.join(this.matterbridgePluginDirectory));
|
|
2893
|
+
this.log.notice(`Backup ready to be downloaded.`);
|
|
2894
|
+
res.json({ message: 'Command received' });
|
|
2895
|
+
return;
|
|
2896
|
+
}
|
|
2722
2897
|
// Handle the command setmbloglevel from Settings
|
|
2723
2898
|
if (command === 'setmbloglevel') {
|
|
2724
2899
|
this.log.debug('Matterbridge log level:', param);
|
|
@@ -2777,6 +2952,46 @@ export class Matterbridge extends EventEmitter {
|
|
|
2777
2952
|
res.json({ message: 'Command received' });
|
|
2778
2953
|
return;
|
|
2779
2954
|
}
|
|
2955
|
+
// Handle the command setmbloglevel from Settings
|
|
2956
|
+
if (command === 'setmblogfile') {
|
|
2957
|
+
this.log.debug('Matterbridge file log:', param);
|
|
2958
|
+
this.matterbridgeInformation.fileLogger = param === 'true';
|
|
2959
|
+
await this.nodeContext?.set('matterbridgeFileLog', param === 'true');
|
|
2960
|
+
// Create the file logger for matterbridge
|
|
2961
|
+
if (param === 'true')
|
|
2962
|
+
AnsiLogger.setGlobalLogfile(path.join(this.matterbridgeDirectory, this.matterbrideLoggerFile), "debug" /* LogLevel.DEBUG */, true);
|
|
2963
|
+
else
|
|
2964
|
+
AnsiLogger.setGlobalLogfile(undefined);
|
|
2965
|
+
res.json({ message: 'Command received' });
|
|
2966
|
+
return;
|
|
2967
|
+
}
|
|
2968
|
+
// Handle the command setmbloglevel from Settings
|
|
2969
|
+
if (command === 'setmjlogfile') {
|
|
2970
|
+
this.log.debug('Matter file log:', param);
|
|
2971
|
+
this.matterbridgeInformation.matterFileLogger = param === 'true';
|
|
2972
|
+
await this.nodeContext?.set('matterFileLog', param === 'true');
|
|
2973
|
+
if (param === 'true') {
|
|
2974
|
+
try {
|
|
2975
|
+
Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
|
|
2976
|
+
defaultLogLevel: Level.DEBUG,
|
|
2977
|
+
logFormat: Format.PLAIN,
|
|
2978
|
+
});
|
|
2979
|
+
}
|
|
2980
|
+
catch (error) {
|
|
2981
|
+
this.log.debug(`Error adding the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
|
|
2982
|
+
}
|
|
2983
|
+
}
|
|
2984
|
+
else {
|
|
2985
|
+
try {
|
|
2986
|
+
Logger.removeLogger('matterfilelogger');
|
|
2987
|
+
}
|
|
2988
|
+
catch (error) {
|
|
2989
|
+
this.log.debug(`Error removing the matterfilelogger for file ${CYAN}${path.join(this.matterbridgeDirectory, this.matterLoggerFile)}${er}: ${error instanceof Error ? error.message : error}`);
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
2992
|
+
res.json({ message: 'Command received' });
|
|
2993
|
+
return;
|
|
2994
|
+
}
|
|
2780
2995
|
// Handle the command unregister from Settings
|
|
2781
2996
|
if (command === 'unregister') {
|
|
2782
2997
|
await this.unregisterAndShutdownProcess();
|