matterbridge 3.4.2-dev-20251202-c41a119 → 3.4.2-dev-20251204-a39ec9e

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 CHANGED
@@ -35,6 +35,9 @@ Advantages:
35
35
  - [frontend]: Added throttle and timeout to autoScroll in the logs.
36
36
  - [frontend]: Log filters are now applied to existing messages too.
37
37
  - [frontend]: Added close on success to Install dialog.
38
+ - [BroadcastServer]: Added check for port closed.
39
+ - [platform]: Added isShuttingDown property to MatterbridgePlatform.
40
+ - [delay]: Added --delay [seconds]. It will wait to start Matterbridge for the specified delay (default 2 minutes) if the system uptime is less then 5 minutes. It is a safe switch to avoid race conditions on start.
38
41
 
39
42
  ### Changed
40
43
 
@@ -45,6 +48,7 @@ Advantages:
45
48
 
46
49
  - [frontend]: Fixed persistance of autoScroll.
47
50
  - [frontend]: Fixed parameters info of Log panel in the Home page.
51
+ - [thread]: Bump `BroadcastServer` to v.2.0.1.
48
52
 
49
53
  <a href="https://www.buymeacoffee.com/luligugithub"><img src="https://matterbridge.io/bmc-button.svg" alt="Buy me a coffee" width="80"></a>
50
54
 
@@ -10,6 +10,7 @@ export class BroadcastServer extends EventEmitter {
10
10
  log;
11
11
  channel;
12
12
  broadcastChannel;
13
+ closed = false;
13
14
  debug = hasParameter('debug') || hasParameter('verbose');
14
15
  verbose = hasParameter('verbose');
15
16
  constructor(name, log, channel = 'broadcast-channel') {
@@ -19,10 +20,29 @@ export class BroadcastServer extends EventEmitter {
19
20
  this.channel = channel;
20
21
  this.broadcastChannel = new BroadcastChannel(this.channel);
21
22
  this.broadcastChannel.onmessage = this.broadcastMessageHandler.bind(this);
23
+ this.broadcastChannel.onmessageerror = this.broadcastMessageErrorHandler.bind(this);
22
24
  }
23
25
  close() {
24
26
  this.broadcastChannel.onmessage = null;
27
+ this.broadcastChannel.onmessageerror = null;
25
28
  this.broadcastChannel.close();
29
+ this.closed = true;
30
+ }
31
+ broadcastMessageHandler(event) {
32
+ const msg = event.data;
33
+ if (msg.dst === this.name || msg.dst === 'all') {
34
+ if (this.verbose)
35
+ this.log.debug(`Server ${CYAN}${this.name}${db} received broadcast message: ${debugStringify(msg)}`);
36
+ this.emit('broadcast_message', msg);
37
+ }
38
+ else {
39
+ if (this.verbose)
40
+ this.log.debug(`Server ${CYAN}${this.name}${db} received unrelated broadcast message: ${debugStringify(msg)}`);
41
+ }
42
+ }
43
+ broadcastMessageErrorHandler(event) {
44
+ const msg = event.data;
45
+ this.log.error(`Server ${CYAN}${this.name}${db} received message error: ${debugStringify(msg)}`);
26
46
  }
27
47
  getUniqueId() {
28
48
  return Math.floor(Math.random() * 900000000) + 100000000;
@@ -55,19 +75,11 @@ export class BroadcastServer extends EventEmitter {
55
75
  isWorkerResponseOfType(value, type) {
56
76
  return this.isWorkerResponse(value) && value.type === type;
57
77
  }
58
- broadcastMessageHandler(event) {
59
- const msg = event.data;
60
- if (msg.dst === this.name || msg.dst === 'all') {
61
- if (this.verbose)
62
- this.log.debug(`Server ${CYAN}${this.name}${db} received broadcast message: ${debugStringify(msg)}`);
63
- this.emit('broadcast_message', msg);
64
- }
65
- else {
66
- if (this.verbose)
67
- this.log.debug(`Server ${CYAN}${this.name}${db} received unrelated broadcast message: ${debugStringify(msg)}`);
68
- }
69
- }
70
78
  broadcast(message) {
79
+ if (this.closed) {
80
+ this.log.error('Broadcast channel is closed');
81
+ return;
82
+ }
71
83
  if (message.id === undefined) {
72
84
  message.id = this.getUniqueId();
73
85
  }
@@ -85,6 +97,10 @@ export class BroadcastServer extends EventEmitter {
85
97
  }
86
98
  }
87
99
  request(message) {
100
+ if (this.closed) {
101
+ this.log.error('Broadcast channel is closed');
102
+ return;
103
+ }
88
104
  if (message.id === undefined) {
89
105
  message.id = this.getUniqueId();
90
106
  }
@@ -106,6 +122,10 @@ export class BroadcastServer extends EventEmitter {
106
122
  }
107
123
  }
108
124
  respond(message) {
125
+ if (this.closed) {
126
+ this.log.error('Broadcast channel is closed');
127
+ return;
128
+ }
109
129
  if (typeof message.timestamp === 'number') {
110
130
  message.elapsed = Date.now() - message.timestamp;
111
131
  }
@@ -130,6 +150,9 @@ export class BroadcastServer extends EventEmitter {
130
150
  }
131
151
  }
132
152
  async fetch(message, timeout = 250) {
153
+ if (this.closed) {
154
+ return Promise.reject(new Error('Broadcast channel is closed'));
155
+ }
133
156
  if (message.id === undefined) {
134
157
  message.id = this.getUniqueId();
135
158
  }
@@ -14,6 +14,7 @@ import { bridge } from '../matterbridgeDeviceTypes.js';
14
14
  import { PluginManager } from '../pluginManager.js';
15
15
  import { Frontend } from '../frontend.js';
16
16
  import { BroadcastServer } from '../broadcastServer.js';
17
+ import { MatterbridgeEndpoint } from '../matterbridgeEndpoint.js';
17
18
  export const originalProcessArgv = Object.freeze([...process.argv]);
18
19
  export const originalProcessEnv = Object.freeze({ ...process.env });
19
20
  export let loggerLogSpy;
@@ -32,6 +33,10 @@ export let addBridgedEndpointSpy;
32
33
  export let removeBridgedEndpointSpy;
33
34
  export let removeAllBridgedEndpointsSpy;
34
35
  export let addVirtualEndpointSpy;
36
+ export let setAttributeSpy;
37
+ export let updateAttributeSpy;
38
+ export let triggerEventSpy;
39
+ export let triggerSwitchEventSpy;
35
40
  export let installPluginSpy;
36
41
  export let uninstallPluginSpy;
37
42
  export let addPluginSpy;
@@ -99,6 +104,10 @@ export async function setupTest(name, debug = false) {
99
104
  removeBridgedEndpointSpy = jest.spyOn(Matterbridge.prototype, 'removeBridgedEndpoint');
100
105
  removeAllBridgedEndpointsSpy = jest.spyOn(Matterbridge.prototype, 'removeAllBridgedEndpoints');
101
106
  addVirtualEndpointSpy = jest.spyOn(Matterbridge.prototype, 'addVirtualEndpoint');
107
+ setAttributeSpy = jest.spyOn(MatterbridgeEndpoint.prototype, 'setAttribute');
108
+ updateAttributeSpy = jest.spyOn(MatterbridgeEndpoint.prototype, 'updateAttribute');
109
+ triggerEventSpy = jest.spyOn(MatterbridgeEndpoint.prototype, 'triggerEvent');
110
+ triggerSwitchEventSpy = jest.spyOn(MatterbridgeEndpoint.prototype, 'triggerSwitchEvent');
102
111
  installPluginSpy = jest.spyOn(PluginManager.prototype, 'install');
103
112
  uninstallPluginSpy = jest.spyOn(PluginManager.prototype, 'uninstall');
104
113
  addPluginSpy = jest.spyOn(PluginManager.prototype, 'add');
@@ -243,7 +252,7 @@ export async function createMatterbridgeEnvironment(name) {
243
252
  matterbridge.matterbridgePluginDirectory = path.join('jest', name, 'Matterbridge');
244
253
  matterbridge.matterbridgeCertDirectory = path.join('jest', name, '.mattercert');
245
254
  matterbridge.log.logLevel = "debug";
246
- log = new AnsiLogger({ logName: 'Plugin platform', logTimestampFormat: 4, logLevel: "debug" });
255
+ log = new AnsiLogger({ logName: name, logTimestampFormat: 4, logLevel: "debug" });
247
256
  frontend = matterbridge.frontend;
248
257
  plugins = matterbridge.plugins;
249
258
  devices = matterbridge.devices;
@@ -357,6 +366,7 @@ export function createTestEnvironment(name) {
357
366
  expect(name).toBeDefined();
358
367
  expect(typeof name).toBe('string');
359
368
  expect(name.length).toBeGreaterThanOrEqual(4);
369
+ log = new AnsiLogger({ logName: name, logTimestampFormat: 4, logLevel: "debug" });
360
370
  rmSync(path.join('jest', name), { recursive: true, force: true });
361
371
  environment = Environment.default;
362
372
  environment.vars.set('log.level', MatterLogLevel.DEBUG);
@@ -653,6 +653,11 @@ export class Matterbridge extends EventEmitter {
653
653
  this.log.info('Setting default matterbridge start mode to bridge');
654
654
  await this.nodeContext?.set('bridgeMode', 'bridge');
655
655
  }
656
+ if (hasParameter('delay') && os.uptime() <= 60 * 5) {
657
+ const delay = getIntParameter('delay') || 2000;
658
+ this.log.warn('Delay switch found with system uptime less than 5 minutes. Waiting for ' + delay + ' seconds before starting matterbridge...');
659
+ await wait(delay * 1000, 'Race condition delay', true);
660
+ }
656
661
  if (hasParameter('bridge') || (!hasParameter('childbridge') && (await this.nodeContext?.get('bridgeMode', '')) === 'bridge')) {
657
662
  this.bridgeMode = 'bridge';
658
663
  this.log.debug(`Starting matterbridge in mode ${this.bridgeMode}`);
@@ -23,6 +23,7 @@ export class MatterbridgePlatform {
23
23
  isLoaded = false;
24
24
  isStarted = false;
25
25
  isConfigured = false;
26
+ isShuttingDown = false;
26
27
  #selectDevices = new Map();
27
28
  #selectEntities = new Map();
28
29
  #contextReady;
@@ -957,11 +957,13 @@ export class PluginManager extends EventEmitter {
957
957
  }
958
958
  this.log.info(`Shutting down plugin ${plg}${plugin.name}${nf}: ${reason}...`);
959
959
  try {
960
+ plugin.platform.isShuttingDown = true;
960
961
  await plugin.platform.onShutdown(reason);
961
962
  plugin.platform.isReady = false;
962
963
  plugin.platform.isLoaded = false;
963
964
  plugin.platform.isStarted = false;
964
965
  plugin.platform.isConfigured = false;
966
+ plugin.platform.isShuttingDown = false;
965
967
  plugin.locked = undefined;
966
968
  plugin.error = undefined;
967
969
  plugin.loaded = undefined;
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.4.2-dev-20251202-c41a119",
3
+ "version": "3.4.2-dev-20251204-a39ec9e",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "matterbridge",
9
- "version": "3.4.2-dev-20251202-c41a119",
9
+ "version": "3.4.2-dev-20251204-a39ec9e",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@matter/main": "0.15.6",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.4.2-dev-20251202-c41a119",
3
+ "version": "3.4.2-dev-20251204-a39ec9e",
4
4
  "description": "Matterbridge plugin manager for Matter",
5
5
  "author": "https://github.com/Luligu",
6
6
  "license": "Apache-2.0",