matterbridge 3.1.1-dev-20250703-80c685d → 3.1.1-dev-20250704-aff5fcb
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 +5 -4
- package/dist/frontend.js +16 -7
- package/dist/matterbridge.js +17 -18
- package/dist/utils/spawn.js +61 -63
- package/npm-shrinkwrap.json +6 -6
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -8,12 +8,12 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
8
8
|
<img src="bmc-button.svg" alt="Buy me a coffee" width="120">
|
|
9
9
|
</a>
|
|
10
10
|
|
|
11
|
-
## [3.1.1] - 2025-07-
|
|
11
|
+
## [3.1.1] - 2025-07-08
|
|
12
12
|
|
|
13
13
|
### Development Breaking Changes
|
|
14
14
|
|
|
15
|
-
- [
|
|
16
|
-
- [MatterbridgeEndpoint]: Added the mode property: `server` will make the device indipendent from its plugin. It has its own server node: QRCode, Fabrics and Sessions are visible in the Devices section of the Home page. This a workaround for the Rvc Apple issue.
|
|
15
|
+
- [exports]: The single devices (i.e. Rvc, Evse etc...) are only exported from `matterbridge/devices`. Please update your imports to use the new export path. Refer to the [documentation](README-DEV.md) for details on imports.
|
|
16
|
+
- [MatterbridgeEndpoint]: Added the mode property: `server` will make the device indipendent from its plugin. It has its own server node: QRCode, Fabrics and Sessions are visible in the Devices section of the Home page. This is a workaround for the Rvc Apple issue. With mode=server the Rvc (like any other device) can be paired directly to the controller like a native not bridged Matter device.
|
|
17
17
|
|
|
18
18
|
### Added
|
|
19
19
|
|
|
@@ -27,8 +27,9 @@ If you like this project and find it useful, please consider giving it a star on
|
|
|
27
27
|
|
|
28
28
|
- [package]: Updated dependencies.
|
|
29
29
|
- [frontend]: Added all esa devices.
|
|
30
|
-
- [frontend]: New default values:
|
|
30
|
+
- [frontend]: New default values: devices on the home page and icon view on the devices page.
|
|
31
31
|
- [matter.js]: Bumped `matter.js` to 0.15.1 (https://github.com/project-chip/matter.js/discussions/2220). Great job matter.js!
|
|
32
|
+
- [imports]: Added more dynamic imports to Matterbridge and Frontend classes.
|
|
32
33
|
|
|
33
34
|
<a href="https://www.buymeacoffee.com/luligugithub">
|
|
34
35
|
<img src="bmc-button.svg" alt="Buy me a coffee" width="80">
|
package/dist/frontend.js
CHANGED
|
@@ -3,6 +3,7 @@ import https from 'node:https';
|
|
|
3
3
|
import os from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { promises as fs } from 'node:fs';
|
|
6
|
+
import EventEmitter from 'node:events';
|
|
6
7
|
import express from 'express';
|
|
7
8
|
import WebSocket, { WebSocketServer } from 'ws';
|
|
8
9
|
import multer from 'multer';
|
|
@@ -12,7 +13,6 @@ import { BridgedDeviceBasicInformation, PowerSource } from '@matter/main/cluster
|
|
|
12
13
|
import { createZip, isValidArray, isValidNumber, isValidObject, isValidString, isValidBoolean, withTimeout, hasParameter } from './utils/export.js';
|
|
13
14
|
import { plg } from './matterbridgeTypes.js';
|
|
14
15
|
import { capitalizeFirstLetter } from './matterbridgeEndpointHelpers.js';
|
|
15
|
-
import spawn from './utils/spawn.js';
|
|
16
16
|
export const WS_ID_LOG = 0;
|
|
17
17
|
export const WS_ID_REFRESH_NEEDED = 1;
|
|
18
18
|
export const WS_ID_RESTART_NEEDED = 2;
|
|
@@ -25,7 +25,7 @@ export const WS_ID_STATEUPDATE = 8;
|
|
|
25
25
|
export const WS_ID_CLOSE_SNACKBAR = 9;
|
|
26
26
|
export const WS_ID_SHELLY_SYS_UPDATE = 100;
|
|
27
27
|
export const WS_ID_SHELLY_MAIN_UPDATE = 101;
|
|
28
|
-
export class Frontend {
|
|
28
|
+
export class Frontend extends EventEmitter {
|
|
29
29
|
matterbridge;
|
|
30
30
|
log;
|
|
31
31
|
port = 8283;
|
|
@@ -35,6 +35,7 @@ export class Frontend {
|
|
|
35
35
|
httpsServer;
|
|
36
36
|
webSocketServer;
|
|
37
37
|
constructor(matterbridge) {
|
|
38
|
+
super();
|
|
38
39
|
this.matterbridge = matterbridge;
|
|
39
40
|
this.log = new AnsiLogger({ logName: 'Frontend', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
|
|
40
41
|
}
|
|
@@ -54,6 +55,7 @@ export class Frontend {
|
|
|
54
55
|
if (hasParameter('ingress')) {
|
|
55
56
|
this.httpServer.listen(this.port, '0.0.0.0', () => {
|
|
56
57
|
this.log.info(`The frontend http server is listening on ${UNDERLINE}http://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
|
|
58
|
+
this.emit('server_listening', 'http', this.port, '0.0.0.0');
|
|
57
59
|
});
|
|
58
60
|
}
|
|
59
61
|
else {
|
|
@@ -62,6 +64,7 @@ export class Frontend {
|
|
|
62
64
|
this.log.info(`The frontend http server is listening on ${UNDERLINE}http://${this.matterbridge.systemInformation.ipv4Address}:${this.port}${UNDERLINEOFF}${rs}`);
|
|
63
65
|
if (this.matterbridge.systemInformation.ipv6Address !== '')
|
|
64
66
|
this.log.info(`The frontend http server is listening on ${UNDERLINE}http://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
|
|
67
|
+
this.emit('server_listening', 'http', this.port);
|
|
65
68
|
});
|
|
66
69
|
}
|
|
67
70
|
this.httpServer.on('error', (error) => {
|
|
@@ -75,6 +78,7 @@ export class Frontend {
|
|
|
75
78
|
break;
|
|
76
79
|
}
|
|
77
80
|
this.initializeError = true;
|
|
81
|
+
this.emit('server_error', error);
|
|
78
82
|
return;
|
|
79
83
|
});
|
|
80
84
|
}
|
|
@@ -110,6 +114,7 @@ export class Frontend {
|
|
|
110
114
|
if (hasParameter('ingress')) {
|
|
111
115
|
this.httpsServer.listen(this.port, '0.0.0.0', () => {
|
|
112
116
|
this.log.info(`The frontend https server is listening on ${UNDERLINE}https://0.0.0.0:${this.port}${UNDERLINEOFF}${rs}`);
|
|
117
|
+
this.emit('server_listening', 'https', this.port, '0.0.0.0');
|
|
113
118
|
});
|
|
114
119
|
}
|
|
115
120
|
else {
|
|
@@ -118,6 +123,7 @@ export class Frontend {
|
|
|
118
123
|
this.log.info(`The frontend https server is listening on ${UNDERLINE}https://${this.matterbridge.systemInformation.ipv4Address}:${this.port}${UNDERLINEOFF}${rs}`);
|
|
119
124
|
if (this.matterbridge.systemInformation.ipv6Address !== '')
|
|
120
125
|
this.log.info(`The frontend https server is listening on ${UNDERLINE}https://[${this.matterbridge.systemInformation.ipv6Address}]:${this.port}${UNDERLINEOFF}${rs}`);
|
|
126
|
+
this.emit('server_listening', 'https', this.port);
|
|
121
127
|
});
|
|
122
128
|
}
|
|
123
129
|
this.httpsServer.on('error', (error) => {
|
|
@@ -131,6 +137,7 @@ export class Frontend {
|
|
|
131
137
|
break;
|
|
132
138
|
}
|
|
133
139
|
this.initializeError = true;
|
|
140
|
+
this.emit('server_error', error);
|
|
134
141
|
return;
|
|
135
142
|
});
|
|
136
143
|
}
|
|
@@ -175,6 +182,7 @@ export class Frontend {
|
|
|
175
182
|
});
|
|
176
183
|
this.webSocketServer.on('listening', () => {
|
|
177
184
|
this.log.info(`The WebSocketServer is listening on ${UNDERLINE}${wssHost}${UNDERLINEOFF}${rs}`);
|
|
185
|
+
this.emit('websocket_server_listening', wssHost);
|
|
178
186
|
});
|
|
179
187
|
this.webSocketServer.on('error', (ws, error) => {
|
|
180
188
|
this.log.error(`WebSocketServer error: ${error}`);
|
|
@@ -423,7 +431,8 @@ export class Frontend {
|
|
|
423
431
|
await fs.rename(file.path, filePath);
|
|
424
432
|
this.log.info(`File ${plg}${filename}${nf} uploaded successfully`);
|
|
425
433
|
if (filename.endsWith('.tgz')) {
|
|
426
|
-
|
|
434
|
+
const { spawnCommand } = await import('./utils/spawn.js');
|
|
435
|
+
await spawnCommand(this.matterbridge, 'npm', ['install', '-g', filePath, '--omit=dev', '--verbose']);
|
|
427
436
|
this.log.info(`Plugin package ${plg}${filename}${nf} installed successfully. Full restart required.`);
|
|
428
437
|
this.wssSendCloseSnackbarMessage(`Installing package ${filename}. Please wait...`);
|
|
429
438
|
this.wssSendSnackbarMessage(`Installed package ${filename}`, 10, 'success');
|
|
@@ -897,8 +906,8 @@ export class Frontend {
|
|
|
897
906
|
return;
|
|
898
907
|
}
|
|
899
908
|
this.wssSendSnackbarMessage(`Installing package ${data.params.packageName}...`, 0);
|
|
900
|
-
spawn
|
|
901
|
-
|
|
909
|
+
const { spawnCommand } = await import('./utils/spawn.js');
|
|
910
|
+
spawnCommand(this.matterbridge, 'npm', ['install', '-g', data.params.packageName, '--omit=dev', '--verbose'])
|
|
902
911
|
.then((response) => {
|
|
903
912
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response }));
|
|
904
913
|
this.wssSendCloseSnackbarMessage(`Installing package ${data.params.packageName}...`);
|
|
@@ -962,8 +971,8 @@ export class Frontend {
|
|
|
962
971
|
this.wssSendRefreshRequired('devices');
|
|
963
972
|
}
|
|
964
973
|
this.wssSendSnackbarMessage(`Uninstalling package ${data.params.packageName}...`, 0);
|
|
965
|
-
spawn
|
|
966
|
-
|
|
974
|
+
const { spawnCommand } = await import('./utils/spawn.js');
|
|
975
|
+
spawnCommand(this.matterbridge, 'npm', ['uninstall', '-g', data.params.packageName, '--verbose'])
|
|
967
976
|
.then((response) => {
|
|
968
977
|
client.send(JSON.stringify({ id: data.id, method: data.method, src: 'Matterbridge', dst: data.src, response }));
|
|
969
978
|
this.wssSendCloseSnackbarMessage(`Uninstalling package ${data.params.packageName}...`);
|
package/dist/matterbridge.js
CHANGED
|
@@ -3,7 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import { promises as fs } from 'node:fs';
|
|
4
4
|
import EventEmitter from 'node:events';
|
|
5
5
|
import { inspect } from 'node:util';
|
|
6
|
-
import { AnsiLogger, UNDERLINE, UNDERLINEOFF, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN } from 'node-ansi-logger';
|
|
6
|
+
import { AnsiLogger, UNDERLINE, UNDERLINEOFF, db, debugStringify, BRIGHT, RESET, er, nf, rs, wr, RED, GREEN, zb, CYAN, nt } from 'node-ansi-logger';
|
|
7
7
|
import { NodeStorageManager } from 'node-persist-manager';
|
|
8
8
|
import { DeviceTypeId, Endpoint, Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, VendorId, StorageService, Environment, ServerNode, UINT32_MAX, UINT16_MAX, Crypto, } from '@matter/main';
|
|
9
9
|
import { DeviceCommissioner, FabricAction, MdnsService, PaseClient } from '@matter/main/protocol';
|
|
@@ -11,7 +11,6 @@ import { AggregatorEndpoint } from '@matter/main/endpoints';
|
|
|
11
11
|
import { BasicInformationServer } from '@matter/main/behaviors/basic-information';
|
|
12
12
|
import { BridgedDeviceBasicInformationServer } from '@matter/main/behaviors/bridged-device-basic-information';
|
|
13
13
|
import { getParameter, getIntParameter, hasParameter, copyDirectory, withTimeout, waiter, isValidString, parseVersionString, isValidNumber, createDirectory } from './utils/export.js';
|
|
14
|
-
import { logInterfaces, getGlobalNodeModules } from './utils/network.js';
|
|
15
14
|
import { dev, plg, typ } from './matterbridgeTypes.js';
|
|
16
15
|
import { PluginManager } from './pluginManager.js';
|
|
17
16
|
import { DeviceManager } from './deviceManager.js';
|
|
@@ -19,7 +18,6 @@ import { MatterbridgeEndpoint } from './matterbridgeEndpoint.js';
|
|
|
19
18
|
import { bridge } from './matterbridgeDeviceTypes.js';
|
|
20
19
|
import { Frontend } from './frontend.js';
|
|
21
20
|
import { addVirtualDevices } from './helpers.js';
|
|
22
|
-
import spawn from './utils/spawn.js';
|
|
23
21
|
export class Matterbridge extends EventEmitter {
|
|
24
22
|
systemInformation = {
|
|
25
23
|
interfaceName: '',
|
|
@@ -385,15 +383,15 @@ export class Matterbridge extends EventEmitter {
|
|
|
385
383
|
}
|
|
386
384
|
Logger.format = MatterLogFormat.ANSI;
|
|
387
385
|
Logger.setLogger('default', this.createMatterLogger());
|
|
388
|
-
this.matterbridgeInformation.matterLoggerLevel = Logger.
|
|
386
|
+
this.matterbridgeInformation.matterLoggerLevel = Logger.level;
|
|
389
387
|
if (hasParameter('matterfilelogger') || (await this.nodeContext.get('matterFileLog', false))) {
|
|
390
388
|
this.matterbridgeInformation.matterFileLogger = true;
|
|
391
389
|
Logger.addLogger('matterfilelogger', await this.createMatterFileLogger(path.join(this.matterbridgeDirectory, this.matterLoggerFile), true), {
|
|
392
|
-
defaultLogLevel: Logger.
|
|
390
|
+
defaultLogLevel: Logger.level,
|
|
393
391
|
logFormat: MatterLogFormat.PLAIN,
|
|
394
392
|
});
|
|
395
393
|
}
|
|
396
|
-
this.log.debug(`Matter logLevel: ${Logger.
|
|
394
|
+
this.log.debug(`Matter logLevel: ${Logger.level} fileLoger: ${this.matterbridgeInformation.matterFileLogger}.`);
|
|
397
395
|
const networkInterfaces = os.networkInterfaces();
|
|
398
396
|
const availableAddresses = Object.entries(networkInterfaces);
|
|
399
397
|
const availableInterfaces = Object.keys(networkInterfaces);
|
|
@@ -494,7 +492,8 @@ export class Matterbridge extends EventEmitter {
|
|
|
494
492
|
if (packageJson === null && !hasParameter('add') && !hasParameter('remove') && !hasParameter('enable') && !hasParameter('disable') && !hasParameter('reset') && !hasParameter('factoryreset')) {
|
|
495
493
|
this.log.info(`Error parsing plugin ${plg}${plugin.name}${nf}. Trying to reinstall it from npm.`);
|
|
496
494
|
try {
|
|
497
|
-
|
|
495
|
+
const { spawnCommand } = await import('./utils/spawn.js');
|
|
496
|
+
await spawnCommand(this, 'npm', ['install', '-g', plugin.name, '--omit=dev', '--verbose']);
|
|
498
497
|
this.log.info(`Plugin ${plg}${plugin.name}${nf} reinstalled.`);
|
|
499
498
|
plugin.error = false;
|
|
500
499
|
}
|
|
@@ -605,6 +604,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
605
604
|
return;
|
|
606
605
|
}
|
|
607
606
|
if (hasParameter('loginterfaces')) {
|
|
607
|
+
const { logInterfaces } = await import('./utils/network.js');
|
|
608
608
|
this.log.info(`${plg}Matterbridge${nf} network interfaces log`);
|
|
609
609
|
logInterfaces();
|
|
610
610
|
this.shutdown = true;
|
|
@@ -667,7 +667,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
667
667
|
await matterStorageManager.createContext('root')?.clearAll();
|
|
668
668
|
await matterStorageManager.createContext('sessions')?.clearAll();
|
|
669
669
|
await matterStorageManager.createContext('persist')?.clearAll();
|
|
670
|
-
this.log.
|
|
670
|
+
this.log.notice(`Reset commissioning for plugin ${plg}${plugin.name}${nt} done! Remove the device from the controller.`);
|
|
671
671
|
}
|
|
672
672
|
}
|
|
673
673
|
else {
|
|
@@ -679,10 +679,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
679
679
|
}
|
|
680
680
|
if (getIntParameter('frontend') !== 0 || getIntParameter('frontend') === undefined)
|
|
681
681
|
await this.frontend.start(getIntParameter('frontend'));
|
|
682
|
+
clearTimeout(this.checkUpdateTimeout);
|
|
682
683
|
this.checkUpdateTimeout = setTimeout(async () => {
|
|
683
684
|
const { checkUpdates } = await import('./update.js');
|
|
684
685
|
checkUpdates(this);
|
|
685
686
|
}, 30 * 1000).unref();
|
|
687
|
+
clearInterval(this.checkUpdateInterval);
|
|
686
688
|
this.checkUpdateInterval = setInterval(async () => {
|
|
687
689
|
const { checkUpdates } = await import('./update.js');
|
|
688
690
|
checkUpdates(this);
|
|
@@ -853,6 +855,7 @@ export class Matterbridge extends EventEmitter {
|
|
|
853
855
|
this.globalModulesDirectory = this.matterbridgeInformation.globalModulesDirectory = await this.nodeContext.get('globalModulesDirectory', '');
|
|
854
856
|
if (this.globalModulesDirectory === '') {
|
|
855
857
|
try {
|
|
858
|
+
const { getGlobalNodeModules } = await import('./utils/network.js');
|
|
856
859
|
this.execRunningCount++;
|
|
857
860
|
this.matterbridgeInformation.globalModulesDirectory = this.globalModulesDirectory = await getGlobalNodeModules();
|
|
858
861
|
this.execRunningCount--;
|
|
@@ -905,9 +908,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
905
908
|
case MatterLogLevel.FATAL:
|
|
906
909
|
matterLogger.log("fatal", message);
|
|
907
910
|
break;
|
|
908
|
-
default:
|
|
909
|
-
matterLogger.log("debug", message);
|
|
910
|
-
break;
|
|
911
911
|
}
|
|
912
912
|
};
|
|
913
913
|
}
|
|
@@ -922,11 +922,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
922
922
|
}
|
|
923
923
|
}
|
|
924
924
|
return async (level, formattedLog) => {
|
|
925
|
-
if (fileSize > 100000000)
|
|
925
|
+
if (fileSize > 100000000) {
|
|
926
926
|
return;
|
|
927
|
+
}
|
|
927
928
|
fileSize += formattedLog.length;
|
|
928
929
|
if (fileSize > 100000000) {
|
|
929
|
-
await fs.appendFile(filePath, `Logging on file has been
|
|
930
|
+
await fs.appendFile(filePath, `Logging on file has been stopped because the file size is greater than 100MB.` + os.EOL);
|
|
930
931
|
return;
|
|
931
932
|
}
|
|
932
933
|
const now = new Date();
|
|
@@ -954,9 +955,6 @@ export class Matterbridge extends EventEmitter {
|
|
|
954
955
|
case MatterLogLevel.FATAL:
|
|
955
956
|
await fs.appendFile(filePath, `[${timestamp}] [${logger}] [fatal] ${finalMessage}`);
|
|
956
957
|
break;
|
|
957
|
-
default:
|
|
958
|
-
await fs.appendFile(filePath, `[${timestamp}] [${logger}] ${finalMessage}`);
|
|
959
|
-
break;
|
|
960
958
|
}
|
|
961
959
|
};
|
|
962
960
|
}
|
|
@@ -969,11 +967,12 @@ export class Matterbridge extends EventEmitter {
|
|
|
969
967
|
async updateProcess() {
|
|
970
968
|
this.log.info('Updating matterbridge...');
|
|
971
969
|
try {
|
|
972
|
-
|
|
970
|
+
const { spawnCommand } = await import('./utils/spawn.js');
|
|
971
|
+
await spawnCommand(this, 'npm', ['install', '-g', 'matterbridge', '--omit=dev', '--verbose']);
|
|
973
972
|
this.log.info('Matterbridge has been updated. Full restart required.');
|
|
974
973
|
}
|
|
975
974
|
catch (error) {
|
|
976
|
-
this.log.error(
|
|
975
|
+
this.log.error(`Error updating matterbridge: ${error instanceof Error ? error.message : error}`);
|
|
977
976
|
}
|
|
978
977
|
this.frontend.wssSendRestartRequired();
|
|
979
978
|
await this.cleanup('updating...', false);
|
package/dist/utils/spawn.js
CHANGED
|
@@ -1,68 +1,66 @@
|
|
|
1
1
|
import { hasParameter } from './commandLine.js';
|
|
2
|
-
export
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
if (
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
matterbridge.log.debug(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`);
|
|
30
|
-
resolve(true);
|
|
31
|
-
}
|
|
32
|
-
else {
|
|
33
|
-
matterbridge.log.error(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`);
|
|
34
|
-
reject(new Error(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`));
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
childProcess.on('exit', (code, signal) => {
|
|
38
|
-
matterbridge.frontend.wssSendMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', `child process exited with code ${code} and signal ${signal}`);
|
|
39
|
-
if (code === 0) {
|
|
40
|
-
matterbridge.log.debug(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`);
|
|
41
|
-
resolve(true);
|
|
42
|
-
}
|
|
43
|
-
else {
|
|
44
|
-
matterbridge.log.error(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`);
|
|
45
|
-
reject(new Error(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`));
|
|
46
|
-
}
|
|
47
|
-
});
|
|
48
|
-
childProcess.on('disconnect', () => {
|
|
49
|
-
matterbridge.log.debug(`Child process "${cmdLine}" has been disconnected from the parent`);
|
|
2
|
+
export async function spawnCommand(matterbridge, command, args) {
|
|
3
|
+
const { spawn } = await import('node:child_process');
|
|
4
|
+
const cmdLine = command + ' ' + args.join(' ');
|
|
5
|
+
if (process.platform === 'win32' && command === 'npm') {
|
|
6
|
+
const argstring = 'npm ' + args.join(' ');
|
|
7
|
+
args.splice(0, args.length, '/c', argstring);
|
|
8
|
+
command = 'cmd.exe';
|
|
9
|
+
}
|
|
10
|
+
if (hasParameter('sudo') || (process.platform !== 'win32' && command === 'npm' && !hasParameter('docker') && !hasParameter('nosudo'))) {
|
|
11
|
+
args.unshift(command);
|
|
12
|
+
command = 'sudo';
|
|
13
|
+
}
|
|
14
|
+
matterbridge.log.debug(`Spawn command ${command} with ${args.join(' ')}`);
|
|
15
|
+
return new Promise((resolve, reject) => {
|
|
16
|
+
const childProcess = spawn(command, args, {
|
|
17
|
+
stdio: ['inherit', 'pipe', 'pipe'],
|
|
18
|
+
});
|
|
19
|
+
childProcess.on('error', (err) => {
|
|
20
|
+
matterbridge.log.error(`Failed to start child process "${cmdLine}": ${err.message}`);
|
|
21
|
+
reject(err);
|
|
22
|
+
});
|
|
23
|
+
childProcess.on('close', (code, signal) => {
|
|
24
|
+
matterbridge.frontend.wssSendMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', `child process closed with code ${code} and signal ${signal}`);
|
|
25
|
+
if (code === 0) {
|
|
26
|
+
if (cmdLine.startsWith('npm install -g'))
|
|
27
|
+
matterbridge.log.notice(`Package ${cmdLine.replace('npm install -g ', '').replace('--verbose', '').replace('--omit=dev', '')} installed correctly`);
|
|
28
|
+
matterbridge.log.debug(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`);
|
|
50
29
|
resolve(true);
|
|
51
|
-
});
|
|
52
|
-
if (childProcess.stdout) {
|
|
53
|
-
childProcess.stdout.on('data', (data) => {
|
|
54
|
-
const message = data.toString().trim();
|
|
55
|
-
matterbridge.log.debug(`Spawn output (stdout): ${message}`);
|
|
56
|
-
matterbridge.frontend.wssSendMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', message);
|
|
57
|
-
});
|
|
58
30
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
matterbridge.log.debug(`Spawn verbose (stderr): ${message}`);
|
|
63
|
-
matterbridge.frontend.wssSendMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', message);
|
|
64
|
-
});
|
|
31
|
+
else {
|
|
32
|
+
matterbridge.log.error(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`);
|
|
33
|
+
reject(new Error(`Child process "${cmdLine}" closed with code ${code} and signal ${signal}`));
|
|
65
34
|
}
|
|
66
35
|
});
|
|
67
|
-
|
|
68
|
-
};
|
|
36
|
+
childProcess.on('exit', (code, signal) => {
|
|
37
|
+
matterbridge.frontend.wssSendMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', `child process exited with code ${code} and signal ${signal}`);
|
|
38
|
+
if (code === 0) {
|
|
39
|
+
matterbridge.log.debug(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`);
|
|
40
|
+
resolve(true);
|
|
41
|
+
}
|
|
42
|
+
else {
|
|
43
|
+
matterbridge.log.error(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`);
|
|
44
|
+
reject(new Error(`Child process "${cmdLine}" exited with code ${code} and signal ${signal}`));
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
childProcess.on('disconnect', () => {
|
|
48
|
+
matterbridge.log.debug(`Child process "${cmdLine}" has been disconnected from the parent`);
|
|
49
|
+
resolve(true);
|
|
50
|
+
});
|
|
51
|
+
if (childProcess.stdout) {
|
|
52
|
+
childProcess.stdout.on('data', (data) => {
|
|
53
|
+
const message = data.toString().trim();
|
|
54
|
+
matterbridge.log.debug(`Spawn output (stdout): ${message}`);
|
|
55
|
+
matterbridge.frontend.wssSendMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', message);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
if (childProcess.stderr) {
|
|
59
|
+
childProcess.stderr.on('data', (data) => {
|
|
60
|
+
const message = data.toString().trim();
|
|
61
|
+
matterbridge.log.debug(`Spawn verbose (stderr): ${message}`);
|
|
62
|
+
matterbridge.frontend.wssSendMessage('spawn', matterbridge.log.now(), 'Matterbridge:spawn', message);
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge",
|
|
3
|
-
"version": "3.1.1-dev-
|
|
3
|
+
"version": "3.1.1-dev-20250704-aff5fcb",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "matterbridge",
|
|
9
|
-
"version": "3.1.1-dev-
|
|
9
|
+
"version": "3.1.1-dev-20250704-aff5fcb",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@matter/main": "0.15.1",
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
"multer": "2.0.1",
|
|
17
17
|
"node-ansi-logger": "3.1.1",
|
|
18
18
|
"node-persist-manager": "2.0.0",
|
|
19
|
-
"ws": "8.18.
|
|
19
|
+
"ws": "8.18.3"
|
|
20
20
|
},
|
|
21
21
|
"bin": {
|
|
22
22
|
"matterbridge": "bin/matterbridge"
|
|
@@ -2126,9 +2126,9 @@
|
|
|
2126
2126
|
"license": "ISC"
|
|
2127
2127
|
},
|
|
2128
2128
|
"node_modules/ws": {
|
|
2129
|
-
"version": "8.18.
|
|
2130
|
-
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.
|
|
2131
|
-
"integrity": "sha512-
|
|
2129
|
+
"version": "8.18.3",
|
|
2130
|
+
"resolved": "https://registry.npmjs.org/ws/-/ws-8.18.3.tgz",
|
|
2131
|
+
"integrity": "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==",
|
|
2132
2132
|
"license": "MIT",
|
|
2133
2133
|
"engines": {
|
|
2134
2134
|
"node": ">=10.0.0"
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "matterbridge",
|
|
3
|
-
"version": "3.1.1-dev-
|
|
3
|
+
"version": "3.1.1-dev-20250704-aff5fcb",
|
|
4
4
|
"description": "Matterbridge plugin manager for Matter",
|
|
5
5
|
"author": "https://github.com/Luligu",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -105,6 +105,6 @@
|
|
|
105
105
|
"multer": "2.0.1",
|
|
106
106
|
"node-ansi-logger": "3.1.1",
|
|
107
107
|
"node-persist-manager": "2.0.0",
|
|
108
|
-
"ws": "8.18.
|
|
108
|
+
"ws": "8.18.3"
|
|
109
109
|
}
|
|
110
110
|
}
|