matterbridge 3.3.1-dev-20251009-008da25 → 3.3.1-dev-20251012-b3546f8

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/dist/cli.js CHANGED
@@ -3,7 +3,7 @@ if (process.argv.includes('--loader') || process.argv.includes('-loader'))
3
3
  import os from 'node:os';
4
4
  import { inspect } from 'node:util';
5
5
  import { AnsiLogger, BRIGHT, CYAN, db, RED, YELLOW } from 'node-ansi-logger';
6
- import { cliEmitter, setLastCpuUsage, setLastProcessCpuUsage } from './cliEmitter.js';
6
+ import { cliEmitter, setLastOsCpuUsage, setLastProcessCpuUsage } from './cliEmitter.js';
7
7
  import { history, historyIndex, historySize, setHistoryIndex } from './cliHistory.js';
8
8
  import { getIntParameter, hasParameter } from './utils/commandLine.js';
9
9
  import { Matterbridge } from './matterbridge.js';
@@ -21,6 +21,8 @@ let peakProcessCpu = 0;
21
21
  let peakRss = 0;
22
22
  let peakHeapUsed = 0;
23
23
  let peakHeapTotal = 0;
24
+ let peakExternal = 0;
25
+ let peakArrayBuffers = 0;
24
26
  const log = new AnsiLogger({ logName: 'Cli', logTimestampFormat: 4, logLevel: hasParameter('debug') ? "debug" : "info" });
25
27
  const formatCpuUsage = (percent) => {
26
28
  return `${percent.toFixed(2).padStart(5, ' ')} %`;
@@ -55,12 +57,11 @@ async function startCpuMemoryCheck() {
55
57
  log.debug(`Cpu memory check started`);
56
58
  prevCpus = os.cpus();
57
59
  prevProcessCpu = process.cpuUsage();
58
- clearInterval(memoryCheckInterval);
59
60
  const interval = () => {
60
61
  const systemUptime = formatOsUpTime(Math.floor(os.uptime()));
61
62
  const processUptime = formatOsUpTime(Math.floor(process.uptime()));
62
63
  cliEmitter.emit('uptime', systemUptime, processUptime);
63
- const totalMememory = formatMemoryUsage(os.totalmem());
64
+ const totalMemory = formatMemoryUsage(os.totalmem());
64
65
  const freeMemory = formatMemoryUsage(os.freemem());
65
66
  const memoryUsageRaw = process.memoryUsage();
66
67
  const rss = formatMemoryUsage(memoryUsageRaw.rss);
@@ -83,7 +84,17 @@ async function startCpuMemoryCheck() {
83
84
  log.debug(`****${RED}${BRIGHT}HeapTotal peak detected.${db} Peak heapTotal from ${CYAN}${formatMemoryUsage(peakHeapTotal)}${db} to ${CYAN}${formatMemoryUsage(memoryUsageRaw.heapTotal)}${db}`);
84
85
  peakHeapTotal = memoryUsageRaw.heapTotal;
85
86
  }
86
- cliEmitter.emit('memory', totalMememory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers);
87
+ if (memoryUsageRaw.external > peakExternal) {
88
+ if (peakExternal && trace)
89
+ log.debug(`****${RED}${BRIGHT}External peak detected.${db} Peak external from ${CYAN}${formatMemoryUsage(peakExternal)}${db} to ${CYAN}${formatMemoryUsage(memoryUsageRaw.external)}${db}`);
90
+ peakExternal = memoryUsageRaw.external;
91
+ }
92
+ if (memoryUsageRaw.arrayBuffers > peakArrayBuffers) {
93
+ if (peakArrayBuffers && trace)
94
+ log.debug(`****${RED}${BRIGHT}ArrayBuffers peak detected.${db} Peak arrayBuffers from ${CYAN}${formatMemoryUsage(peakArrayBuffers)}${db} to ${CYAN}${formatMemoryUsage(memoryUsageRaw.arrayBuffers)}${db}`);
95
+ peakArrayBuffers = memoryUsageRaw.arrayBuffers;
96
+ }
97
+ cliEmitter.emit('memory', totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers);
87
98
  const currCpus = os.cpus();
88
99
  if (currCpus.length !== prevCpus.length) {
89
100
  prevCpus = currCpus;
@@ -98,16 +109,16 @@ async function startCpuMemoryCheck() {
98
109
  totalIdle += idleDiff;
99
110
  totalTick += totalDiff;
100
111
  });
101
- const cpuUsage = 100 - (totalIdle / totalTick) * 100;
102
- if (totalTick === 0 || isNaN(cpuUsage) || !isFinite(cpuUsage) || cpuUsage <= 0) {
112
+ const osCpuUsage = 100 - (totalIdle / totalTick) * 100;
113
+ if (totalTick === 0 || isNaN(osCpuUsage) || !isFinite(osCpuUsage) || osCpuUsage <= 0) {
103
114
  log.debug(`Cpu check failed, using previous cpus`);
104
115
  }
105
116
  else {
106
- setLastCpuUsage(cpuUsage);
107
- if (cpuUsage > peakCpu) {
108
- peakCpu = cpuUsage;
117
+ setLastOsCpuUsage(osCpuUsage);
118
+ if (osCpuUsage > peakCpu) {
119
+ peakCpu = osCpuUsage;
109
120
  if (peakCpu && trace)
110
- log.debug(`****${RED}${BRIGHT}Cpu peak detected.${db} Peak cpu from ${CYAN}${formatCpuUsage(peakCpu)}${db} to ${CYAN}${formatCpuUsage(cpuUsage)}${db}`);
121
+ log.debug(`****${RED}${BRIGHT}Cpu peak detected.${db} Peak cpu from ${CYAN}${formatCpuUsage(peakCpu)}${db} to ${CYAN}${formatCpuUsage(osCpuUsage)}${db}`);
111
122
  }
112
123
  }
113
124
  prevCpus = currCpus;
@@ -115,7 +126,7 @@ async function startCpuMemoryCheck() {
115
126
  const userMs = diff.user / 1000;
116
127
  const systemMs = diff.system / 1000;
117
128
  const totalMs = userMs + systemMs;
118
- const processCpuUsage = Number(((totalMs / memoryCheckIntervalMs) * 100).toFixed(2));
129
+ const processCpuUsage = Number((((totalMs / memoryCheckIntervalMs) * 100) / currCpus.length).toFixed(2));
119
130
  if (processCpuUsage > peakProcessCpu) {
120
131
  peakProcessCpu = processCpuUsage;
121
132
  if (peakProcessCpu && trace)
@@ -123,9 +134,10 @@ async function startCpuMemoryCheck() {
123
134
  }
124
135
  prevProcessCpu = process.cpuUsage();
125
136
  setLastProcessCpuUsage(processCpuUsage);
126
- cliEmitter.emit('cpu', cpuUsage, processCpuUsage);
137
+ cliEmitter.emit('cpu', osCpuUsage, processCpuUsage);
127
138
  const entry = history[historyIndex];
128
- entry.cpu = cpuUsage;
139
+ entry.timestamp = Date.now();
140
+ entry.cpu = osCpuUsage;
129
141
  entry.peakCpu = peakCpu;
130
142
  entry.processCpu = processCpuUsage;
131
143
  entry.peakProcessCpu = peakProcessCpu;
@@ -135,16 +147,29 @@ async function startCpuMemoryCheck() {
135
147
  entry.peakHeapUsed = peakHeapUsed;
136
148
  entry.heapTotal = memoryUsageRaw.heapTotal;
137
149
  entry.peakHeapTotal = peakHeapTotal;
138
- entry.timestamp = Date.now();
150
+ entry.external = memoryUsageRaw.external;
151
+ entry.peakExternal = peakExternal;
152
+ entry.arrayBuffers = memoryUsageRaw.arrayBuffers;
153
+ entry.peakArrayBuffers = peakArrayBuffers;
139
154
  setHistoryIndex((historyIndex + 1) % historySize);
140
155
  if (trace)
141
- log.debug(`***${YELLOW}${BRIGHT}Host cpu:${db} ${CYAN}${formatCpuUsage(cpuUsage)}${db} (peak ${formatCpuUsage(peakCpu)}) ${YELLOW}${BRIGHT}Process cpu:${db} ${CYAN}${formatCpuUsage(processCpuUsage)}${db} (peak ${formatCpuUsage(peakProcessCpu)}) ${YELLOW}${BRIGHT}Process memory:${db} rss ${CYAN}${rss}${db} (peak ${formatMemoryUsage(peakRss)}) heapUsed ${CYAN}${heapUsed}${db} (peak ${formatMemoryUsage(peakHeapUsed)}) heapTotal ${CYAN}${heapTotal}${db} (peak ${formatMemoryUsage(peakHeapTotal)}) external ${external} arrayBuffers ${arrayBuffers}`);
156
+ log.debug(`***${YELLOW}${BRIGHT}Host cpu:${db} ` +
157
+ `${CYAN}${formatCpuUsage(osCpuUsage)}${db} (peak ${formatCpuUsage(peakCpu)}) ` +
158
+ `${YELLOW}${BRIGHT}Process cpu:${db} ` +
159
+ `${CYAN}${formatCpuUsage(processCpuUsage)}${db} (peak ${formatCpuUsage(peakProcessCpu)}) ` +
160
+ `${YELLOW}${BRIGHT}Process memory:${db} ` +
161
+ `rss ${CYAN}${rss}${db} (peak ${formatMemoryUsage(peakRss)}) ` +
162
+ `heapUsed ${CYAN}${heapUsed}${db} (peak ${formatMemoryUsage(peakHeapUsed)}) ` +
163
+ `heapTotal ${CYAN}${heapTotal}${db} (peak ${formatMemoryUsage(peakHeapTotal)}) ` +
164
+ `external ${CYAN}${external}${db} (peak ${formatMemoryUsage(peakExternal)}) ` +
165
+ `arrayBuffers ${CYAN}${arrayBuffers}${db} (peak ${formatMemoryUsage(peakArrayBuffers)})`);
142
166
  };
143
167
  clearInterval(memoryCheckInterval);
144
168
  memoryCheckInterval = setInterval(interval, memoryCheckIntervalMs).unref();
145
169
  clearTimeout(memoryPeakResetTimeout);
146
170
  memoryPeakResetTimeout = setTimeout(() => {
147
- log.debug(`****${RED}${BRIGHT}Cpu and memory peaks reset after first 5 minutes.${db}`);
171
+ if (trace)
172
+ log.debug(`****${RED}${BRIGHT}Cpu and memory peaks reset after first 5 minutes.${db}`);
148
173
  peakCpu = 0;
149
174
  peakProcessCpu = 0;
150
175
  peakRss = 0;
@@ -154,7 +179,13 @@ async function startCpuMemoryCheck() {
154
179
  }
155
180
  async function stopCpuMemoryCheck() {
156
181
  if (trace) {
157
- log.debug(`***Cpu memory check stopped. Peak cpu: ${CYAN}${peakCpu.toFixed(2)} %${db}. Peak rss: ${CYAN}${formatMemoryUsage(peakRss)}${db}. Peak heapUsed: ${CYAN}${formatMemoryUsage(peakHeapUsed)}${db}. Peak heapTotal: ${CYAN}${formatMemoryUsage(peakHeapTotal)}${db}`);
182
+ log.debug(`***Cpu memory check stopped. ` +
183
+ `Peak cpu: ${CYAN}${peakCpu.toFixed(2)} %${db}. ` +
184
+ `Peak rss: ${CYAN}${formatMemoryUsage(peakRss)}${db}. ` +
185
+ `Peak heapUsed: ${CYAN}${formatMemoryUsage(peakHeapUsed)}${db}. ` +
186
+ `Peak heapTotal: ${CYAN}${formatMemoryUsage(peakHeapTotal)}${db}. ` +
187
+ `Peak external: ${CYAN}${formatMemoryUsage(peakExternal)}${db}. ` +
188
+ `Peak arrayBuffers: ${CYAN}${formatMemoryUsage(peakArrayBuffers)}${db}.`);
158
189
  }
159
190
  clearInterval(memoryCheckInterval);
160
191
  clearTimeout(memoryPeakResetTimeout);
@@ -2,10 +2,10 @@ if (process.argv.includes('--loader') || process.argv.includes('-loader'))
2
2
  console.log('\u001B[32mCli emitter loaded.\u001B[40;0m');
3
3
  import { EventEmitter } from 'node:events';
4
4
  export const cliEmitter = new EventEmitter();
5
- export let lastCpuUsage = 0;
5
+ export let lastOsCpuUsage = 0;
6
6
  export let lastProcessCpuUsage = 0;
7
- export function setLastCpuUsage(val) {
8
- lastCpuUsage = val;
7
+ export function setLastOsCpuUsage(val) {
8
+ lastOsCpuUsage = val;
9
9
  }
10
10
  export function setLastProcessCpuUsage(val) {
11
11
  lastProcessCpuUsage = val;
@@ -2,7 +2,7 @@ if (process.argv.includes('--loader') || process.argv.includes('-loader'))
2
2
  console.log('\u001B[32mCli history loaded.\u001B[40;0m');
3
3
  import { writeFileSync } from 'node:fs';
4
4
  import path from 'node:path';
5
- export const historySize = 2160;
5
+ export const historySize = 4320;
6
6
  export let historyIndex = 0;
7
7
  export function setHistoryIndex(index) {
8
8
  if (!Number.isFinite(index) || !Number.isSafeInteger(index)) {
@@ -14,6 +14,7 @@ export function setHistoryIndex(index) {
14
14
  historyIndex = index;
15
15
  }
16
16
  export const history = Array.from({ length: historySize }, () => ({
17
+ timestamp: 0,
17
18
  cpu: 0,
18
19
  peakCpu: 0,
19
20
  processCpu: 0,
@@ -24,7 +25,10 @@ export const history = Array.from({ length: historySize }, () => ({
24
25
  peakHeapUsed: 0,
25
26
  heapTotal: 0,
26
27
  peakHeapTotal: 0,
27
- timestamp: 0,
28
+ external: 0,
29
+ peakExternal: 0,
30
+ arrayBuffers: 0,
31
+ peakArrayBuffers: 0,
28
32
  }));
29
33
  export function generateHistoryPage(options = {}) {
30
34
  const pageTitle = options.pageTitle ?? 'Matterbridge CPU & Memory History';
@@ -50,9 +54,10 @@ export function generateHistoryPage(options = {}) {
50
54
  const peakRss = Math.max(...normalizedHistory.map((entry) => entry.peakRss ?? entry.rss));
51
55
  const peakHeapUsed = Math.max(...normalizedHistory.map((entry) => entry.peakHeapUsed ?? entry.heapUsed));
52
56
  const peakHeapTotal = Math.max(...normalizedHistory.map((entry) => entry.peakHeapTotal ?? entry.heapTotal));
57
+ const peakExternal = Math.max(...normalizedHistory.map((entry) => entry.peakExternal ?? entry.external));
58
+ const peakArrayBuffers = Math.max(...normalizedHistory.map((entry) => entry.peakArrayBuffers ?? entry.arrayBuffers));
53
59
  const firstTimestamp = normalizedHistory[0]?.timestamp ?? Date.now();
54
60
  const lastTimestamp = normalizedHistory[normalizedHistory.length - 1]?.timestamp ?? Date.now();
55
- const historySanitised = JSON.stringify(normalizedHistory).replace(/</g, '\\u003c').replace(/>/g, '\\u003e');
56
61
  const summary = {
57
62
  entries: normalizedHistory.length,
58
63
  timeRange: `${new Date(firstTimestamp).toLocaleString()} → ${new Date(lastTimestamp).toLocaleString()}`,
@@ -61,8 +66,9 @@ export function generateHistoryPage(options = {}) {
61
66
  peakRss,
62
67
  peakHeapUsed,
63
68
  peakHeapTotal,
69
+ peakExternal,
70
+ peakArrayBuffers,
64
71
  };
65
- const summarySanitised = JSON.stringify(summary).replace(/</g, '\\u003c').replace(/>/g, '\\u003e');
66
72
  const html = `<!DOCTYPE html>
67
73
  <html lang="en">
68
74
  <head>
@@ -271,8 +277,8 @@ export function generateHistoryPage(options = {}) {
271
277
  </div>
272
278
 
273
279
  <script type="module">
274
- const HISTORY_DATA = ${historySanitised};
275
- const SUMMARY_DATA = ${summarySanitised};
280
+ const HISTORY_DATA = ${JSON.stringify(normalizedHistory)};
281
+ const SUMMARY_DATA = ${JSON.stringify(summary)};
276
282
  let cleanup = () => {};
277
283
 
278
284
  const summaryContainer = document.getElementById('summary');
@@ -283,7 +289,9 @@ export function generateHistoryPage(options = {}) {
283
289
  { label: 'Process CPU Peak', value: SUMMARY_DATA.peakProcessCpu.toFixed(2) + ' %' },
284
290
  { label: 'RSS Peak', value: formatBytes(SUMMARY_DATA.peakRss) },
285
291
  { label: 'Heap Used Peak', value: formatBytes(SUMMARY_DATA.peakHeapUsed) },
286
- { label: 'Heap Total Peak', value: formatBytes(SUMMARY_DATA.peakHeapTotal) }
292
+ { label: 'Heap Total Peak', value: formatBytes(SUMMARY_DATA.peakHeapTotal) },
293
+ { label: 'External Peak', value: formatBytes(SUMMARY_DATA.peakExternal) },
294
+ { label: 'Array Buffers Peak', value: formatBytes(SUMMARY_DATA.peakArrayBuffers) }
287
295
  ];
288
296
 
289
297
  summaryEntries.forEach(function (itemData) {
@@ -326,7 +334,7 @@ export function generateHistoryPage(options = {}) {
326
334
  const cpuPeakValue = HISTORY_DATA.reduce(function (acc, entry) {
327
335
  return Math.max(acc, Number.isFinite(entry.peakCpu) ? entry.peakCpu : 0, Number.isFinite(entry.cpu) ? entry.cpu : 0);
328
336
  }, 0);
329
- const cpuPadding = cpuPeakValue <= 10 ? 2 : cpuPeakValue * 0.1;
337
+ const cpuMaxYAxis = cpuPeakValue > 0 ? cpuPeakValue * 1.05 : undefined;
330
338
 
331
339
  const processCpuPeakValue = HISTORY_DATA.reduce(function (acc, entry) {
332
340
  return Math.max(
@@ -335,7 +343,33 @@ export function generateHistoryPage(options = {}) {
335
343
  Number.isFinite(entry.processCpu) ? entry.processCpu : 0
336
344
  );
337
345
  }, 0);
338
- const processCpuPadding = processCpuPeakValue <= 10 ? 2 : processCpuPeakValue * 0.1;
346
+ const processCpuMaxYAxis = processCpuPeakValue > 0 ? processCpuPeakValue * 1.05 : undefined;
347
+ const useProcessCpuDecimals = (processCpuMaxYAxis ?? 0) <= 3;
348
+
349
+ // Compute memory chart dynamic minimum Y as (min observed MB) - 10%
350
+ const memoryMinMb = HISTORY_DATA.reduce(function (acc, entry) {
351
+ const values = [entry.rss, entry.heapTotal, entry.heapUsed].map(bytesToMb);
352
+ const finiteValues = values.filter(function (v) { return Number.isFinite(v); });
353
+ const minEntry = finiteValues.length ? Math.min.apply(Math, finiteValues) : acc;
354
+ return Math.min(acc, minEntry);
355
+ }, Number.POSITIVE_INFINITY);
356
+ const memoryMinYAxis = Number.isFinite(memoryMinMb) && memoryMinMb > 0 ? Math.max(0, memoryMinMb - memoryMinMb * 0.1) : 0;
357
+
358
+ // Compute memory chart dynamic maximum Y as (max observed MB including peaks) + 5%
359
+ const memoryMaxMb = HISTORY_DATA.reduce(function (acc, entry) {
360
+ const values = [
361
+ entry.rss,
362
+ entry.heapTotal,
363
+ entry.heapUsed,
364
+ entry.peakRss,
365
+ entry.peakHeapTotal,
366
+ entry.peakHeapUsed
367
+ ].map(bytesToMb);
368
+ const finiteValues = values.filter(function (v) { return Number.isFinite(v); });
369
+ const maxEntry = finiteValues.length ? Math.max.apply(Math, finiteValues) : acc;
370
+ return Math.max(acc, maxEntry);
371
+ }, 0);
372
+ const memoryMaxYAxis = Number.isFinite(memoryMaxMb) && memoryMaxMb > 0 ? memoryMaxMb * 1.05 : undefined;
339
373
 
340
374
  renderCharts();
341
375
 
@@ -364,7 +398,7 @@ export function generateHistoryPage(options = {}) {
364
398
  }
365
399
  ],
366
400
  minY: 0,
367
- maxY: cpuPeakValue + cpuPadding,
401
+ maxY: cpuMaxYAxis,
368
402
  yFormatter: function (value) {
369
403
  return value.toFixed(0) + ' %';
370
404
  }
@@ -397,9 +431,9 @@ export function generateHistoryPage(options = {}) {
397
431
  }
398
432
  ],
399
433
  minY: 0,
400
- maxY: processCpuPeakValue + processCpuPadding,
434
+ maxY: processCpuMaxYAxis,
401
435
  yFormatter: function (value) {
402
- return value.toFixed(0) + ' %';
436
+ return value.toFixed(useProcessCpuDecimals ? 1 : 0) + ' %';
403
437
  }
404
438
  });
405
439
 
@@ -423,7 +457,8 @@ export function generateHistoryPage(options = {}) {
423
457
  color: '#f472b6'
424
458
  }
425
459
  ],
426
- minY: 0,
460
+ minY: memoryMinYAxis,
461
+ maxY: memoryMaxYAxis,
427
462
  yFormatter: function (value) {
428
463
  return value.toFixed(0) + ' MB';
429
464
  }
package/dist/frontend.js CHANGED
@@ -3,9 +3,6 @@ if (process.argv.includes('--loader') || process.argv.includes('-loader'))
3
3
  import os from 'node:os';
4
4
  import path from 'node:path';
5
5
  import EventEmitter from 'node:events';
6
- import express from 'express';
7
- import WebSocket, { WebSocketServer } from 'ws';
8
- import multer from 'multer';
9
6
  import { AnsiLogger, stringify, debugStringify, CYAN, db, er, nf, rs, UNDERLINE, UNDERLINEOFF, YELLOW, nt, wr } from 'node-ansi-logger';
10
7
  import { Logger, LogLevel as MatterLogLevel, LogFormat as MatterLogFormat, Lifecycle, LogDestination, Diagnostic, Time, FabricIndex } from '@matter/main';
11
8
  import { BridgedDeviceBasicInformation } from '@matter/main/clusters/bridged-device-basic-information';
@@ -13,10 +10,14 @@ import { PowerSource } from '@matter/main/clusters/power-source';
13
10
  import { DeviceAdvertiser, DeviceCommissioner, FabricManager } from '@matter/main/protocol';
14
11
  import { CommissioningOptions } from '@matter/main/types';
15
12
  import { MATTER_LOGGER_FILE, MATTER_STORAGE_NAME, MATTERBRIDGE_DIAGNOSTIC_FILE, MATTERBRIDGE_HISTORY_FILE, MATTERBRIDGE_LOGGER_FILE, NODE_STORAGE_DIR, plg } from './matterbridgeTypes.js';
16
- import { createZip, isValidArray, isValidNumber, isValidObject, isValidString, isValidBoolean, withTimeout, hasParameter, wait, inspectError } from './utils/export.js';
13
+ import { isValidArray, isValidNumber, isValidObject, isValidString, isValidBoolean } from './utils/isvalid.js';
14
+ import { createZip } from './utils/createZip.js';
15
+ import { hasParameter } from './utils/commandLine.js';
16
+ import { withTimeout, wait } from './utils/wait.js';
17
+ import { inspectError } from './utils/error.js';
17
18
  import { formatMemoryUsage, formatOsUpTime } from './utils/network.js';
18
19
  import { capitalizeFirstLetter, getAttribute } from './matterbridgeEndpointHelpers.js';
19
- import { cliEmitter, lastCpuUsage, lastProcessCpuUsage } from './cliEmitter.js';
20
+ import { cliEmitter, lastOsCpuUsage, lastProcessCpuUsage } from './cliEmitter.js';
20
21
  import { generateHistoryPage } from './cliHistory.js';
21
22
  import { BroadcastServer } from './broadcastServer.js';
22
23
  export class Frontend extends EventEmitter {
@@ -94,9 +95,11 @@ export class Frontend extends EventEmitter {
94
95
  async start(port = 8283) {
95
96
  this.port = port;
96
97
  this.log.debug(`Initializing the frontend ${hasParameter('ssl') ? 'https' : 'http'} server on port ${YELLOW}${this.port}${db}`);
98
+ const multer = await import('multer');
97
99
  const uploadDir = path.join(this.matterbridge.matterbridgeDirectory, 'uploads');
98
- const upload = multer({ dest: uploadDir });
99
- this.expressApp = express();
100
+ const upload = multer.default({ dest: uploadDir });
101
+ const express = await import('express');
102
+ this.expressApp = express.default();
100
103
  this.expressApp.use(express.static(path.join(this.matterbridge.rootDirectory, 'frontend/build')));
101
104
  if (!hasParameter('ssl')) {
102
105
  const http = await import('node:http');
@@ -245,8 +248,9 @@ export class Frontend extends EventEmitter {
245
248
  return;
246
249
  });
247
250
  }
251
+ const ws = await import('ws');
248
252
  this.log.debug(`Creating WebSocketServer...`);
249
- this.webSocketServer = new WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
253
+ this.webSocketServer = new ws.WebSocketServer(hasParameter('ssl') ? { server: this.httpsServer } : { server: this.httpServer });
250
254
  this.webSocketServer.on('connection', (ws, request) => {
251
255
  const clientIp = request.socket.remoteAddress;
252
256
  let callbackLogLevel = "notice";
@@ -625,6 +629,7 @@ export class Frontend extends EventEmitter {
625
629
  }
626
630
  async stop() {
627
631
  this.log.debug('Stopping the frontend...');
632
+ const ws = await import('ws');
628
633
  if (this.expressApp) {
629
634
  this.expressApp.removeAllListeners();
630
635
  this.expressApp = undefined;
@@ -633,7 +638,7 @@ export class Frontend extends EventEmitter {
633
638
  if (this.webSocketServer) {
634
639
  this.log.debug('Closing WebSocket server...');
635
640
  this.webSocketServer.clients.forEach((client) => {
636
- if (client.readyState === WebSocket.OPEN) {
641
+ if (client.readyState === ws.WebSocket.OPEN) {
637
642
  client.close();
638
643
  }
639
644
  });
@@ -679,7 +684,7 @@ export class Frontend extends EventEmitter {
679
684
  this.matterbridge.systemInformation.freeMemory = formatMemoryUsage(os.freemem());
680
685
  this.matterbridge.systemInformation.systemUptime = formatOsUpTime(os.uptime());
681
686
  this.matterbridge.systemInformation.processUptime = formatOsUpTime(Math.floor(process.uptime()));
682
- this.matterbridge.systemInformation.cpuUsage = lastCpuUsage.toFixed(2) + ' %';
687
+ this.matterbridge.systemInformation.cpuUsage = lastOsCpuUsage.toFixed(2) + ' %';
683
688
  this.matterbridge.systemInformation.processCpuUsage = lastProcessCpuUsage.toFixed(2) + ' %';
684
689
  this.matterbridge.systemInformation.rss = formatMemoryUsage(process.memoryUsage().rss);
685
690
  this.matterbridge.systemInformation.heapTotal = formatMemoryUsage(process.memoryUsage().heapTotal);
@@ -999,7 +1004,7 @@ export class Frontend extends EventEmitter {
999
1004
  async wsMessageHandler(client, message) {
1000
1005
  let data;
1001
1006
  const sendResponse = (data) => {
1002
- if (client.readyState === WebSocket.OPEN) {
1007
+ if (client.readyState === client.OPEN) {
1003
1008
  if ('response' in data) {
1004
1009
  const { response, ...rest } = data;
1005
1010
  this.log.debug(`Sending api response message: ${debugStringify(rest)}`);
@@ -1721,6 +1726,8 @@ export class Frontend extends EventEmitter {
1721
1726
  }
1722
1727
  }
1723
1728
  wssSendLogMessage(level, time, name, message) {
1729
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1730
+ return;
1724
1731
  if (!level || !time || !name || !message)
1725
1732
  return;
1726
1733
  message = message.replace(/\x1B\[[0-9;]*[m|s|u|K]/g, '');
@@ -1745,10 +1752,14 @@ export class Frontend extends EventEmitter {
1745
1752
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'log', success: true, response: { level, time, name, message } });
1746
1753
  }
1747
1754
  wssSendRefreshRequired(changed, params) {
1755
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1756
+ return;
1748
1757
  this.log.debug('Sending a refresh required message to all connected clients');
1749
1758
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'refresh_required', success: true, response: { changed, ...params } });
1750
1759
  }
1751
1760
  wssSendRestartRequired(snackbar = true, fixed = false) {
1761
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1762
+ return;
1752
1763
  this.log.debug('Sending a restart required message to all connected clients');
1753
1764
  this.matterbridge.restartRequired = true;
1754
1765
  this.matterbridge.fixedRestartRequired = fixed;
@@ -1757,6 +1768,8 @@ export class Frontend extends EventEmitter {
1757
1768
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'restart_required', success: true, response: { fixed } });
1758
1769
  }
1759
1770
  wssSendRestartNotRequired(snackbar = true) {
1771
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1772
+ return;
1760
1773
  this.log.debug('Sending a restart not required message to all connected clients');
1761
1774
  this.matterbridge.restartRequired = false;
1762
1775
  if (snackbar === true)
@@ -1764,43 +1777,59 @@ export class Frontend extends EventEmitter {
1764
1777
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'restart_not_required', success: true });
1765
1778
  }
1766
1779
  wssSendUpdateRequired(devVersion = false) {
1780
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1781
+ return;
1767
1782
  this.log.debug('Sending an update required message to all connected clients');
1768
1783
  this.matterbridge.updateRequired = true;
1769
1784
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'update_required', success: true, response: { devVersion } });
1770
1785
  }
1771
1786
  wssSendCpuUpdate(cpuUsage, processCpuUsage) {
1787
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1788
+ return;
1772
1789
  if (hasParameter('debug'))
1773
1790
  this.log.debug('Sending a cpu update message to all connected clients');
1774
1791
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'cpu_update', success: true, response: { cpuUsage: Math.round(cpuUsage * 100) / 100, processCpuUsage: Math.round(processCpuUsage * 100) / 100 } });
1775
1792
  }
1776
1793
  wssSendMemoryUpdate(totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers) {
1794
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1795
+ return;
1777
1796
  if (hasParameter('debug'))
1778
1797
  this.log.debug('Sending a memory update message to all connected clients');
1779
1798
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'memory_update', success: true, response: { totalMemory, freeMemory, rss, heapTotal, heapUsed, external, arrayBuffers } });
1780
1799
  }
1781
1800
  wssSendUptimeUpdate(systemUptime, processUptime) {
1801
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1802
+ return;
1782
1803
  if (hasParameter('debug'))
1783
1804
  this.log.debug('Sending a uptime update message to all connected clients');
1784
1805
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'uptime_update', success: true, response: { systemUptime, processUptime } });
1785
1806
  }
1786
1807
  wssSendSnackbarMessage(message, timeout = 5, severity = 'info') {
1808
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1809
+ return;
1787
1810
  this.log.debug('Sending a snackbar message to all connected clients');
1788
1811
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'snackbar', success: true, response: { message, timeout, severity } });
1789
1812
  }
1790
1813
  wssSendCloseSnackbarMessage(message) {
1814
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1815
+ return;
1791
1816
  this.log.debug('Sending a close snackbar message to all connected clients');
1792
1817
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'close_snackbar', success: true, response: { message } });
1793
1818
  }
1794
1819
  wssSendAttributeChangedMessage(plugin, serialNumber, uniqueId, number, id, cluster, attribute, value) {
1820
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1821
+ return;
1795
1822
  this.log.debug('Sending an attribute update message to all connected clients');
1796
1823
  this.wssBroadcastMessage({ id: 0, src: 'Matterbridge', dst: 'Frontend', method: 'state_update', success: true, response: { plugin, serialNumber, uniqueId, number, id, cluster, attribute, value } });
1797
1824
  }
1798
1825
  wssBroadcastMessage(msg) {
1826
+ if (!this.listening || this.webSocketServer?.clients.size === 0)
1827
+ return;
1799
1828
  const stringifiedMsg = JSON.stringify(msg);
1800
1829
  if (msg.method !== 'log')
1801
1830
  this.log.debug(`Sending a broadcast message: ${debugStringify(msg)}`);
1802
1831
  this.webSocketServer?.clients.forEach((client) => {
1803
- if (client.readyState === WebSocket.OPEN) {
1832
+ if (client.readyState === client.OPEN) {
1804
1833
  client.send(stringifiedMsg);
1805
1834
  }
1806
1835
  });
@@ -871,26 +871,23 @@ export class Matterbridge extends EventEmitter {
871
871
  this.log.debug(`Command Line Arguments: ${cmdArgs}`);
872
872
  }
873
873
  async setLogLevel(logLevel) {
874
- if (this.log)
875
- this.log.logLevel = logLevel;
874
+ this.log.logLevel = logLevel;
876
875
  this.frontend.logLevel = logLevel;
877
876
  MatterbridgeEndpoint.logLevel = logLevel;
878
- if (this.devices)
879
- this.devices.logLevel = logLevel;
880
- if (this.plugins)
881
- this.plugins.logLevel = logLevel;
877
+ this.devices.logLevel = logLevel;
878
+ this.plugins.logLevel = logLevel;
882
879
  for (const plugin of this.plugins) {
883
880
  if (!plugin.platform || !plugin.platform.log || !plugin.platform.config)
884
881
  continue;
885
- plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" : this.log.logLevel;
886
- await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" : this.log.logLevel);
882
+ plugin.platform.log.logLevel = plugin.platform.config.debug === true ? "debug" : logLevel;
883
+ await plugin.platform.onChangeLoggerLevel(plugin.platform.config.debug === true ? "debug" : logLevel);
887
884
  }
888
885
  let callbackLogLevel = "notice";
889
- if (this.log.logLevel === "info" || Logger.level === MatterLogLevel.INFO)
886
+ if (logLevel === "info" || Logger.level === MatterLogLevel.INFO)
890
887
  callbackLogLevel = "info";
891
- if (this.log.logLevel === "debug" || Logger.level === MatterLogLevel.DEBUG)
888
+ if (logLevel === "debug" || Logger.level === MatterLogLevel.DEBUG)
892
889
  callbackLogLevel = "debug";
893
- AnsiLogger.setGlobalCallback(this.frontend.wssSendLogMessage.bind(this.frontend), callbackLogLevel);
890
+ AnsiLogger.setGlobalCallbackLevel(callbackLogLevel);
894
891
  this.log.debug(`WebSocketServer logger global callback set to ${callbackLogLevel}`);
895
892
  }
896
893
  getLogLevel() {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.3.1-dev-20251009-008da25",
3
+ "version": "3.3.1-dev-20251012-b3546f8",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "matterbridge",
9
- "version": "3.3.1-dev-20251009-008da25",
9
+ "version": "3.3.1-dev-20251012-b3546f8",
10
10
  "license": "Apache-2.0",
11
11
  "dependencies": {
12
12
  "@matter/main": "0.15.5",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.3.1-dev-20251009-008da25",
3
+ "version": "3.3.1-dev-20251012-b3546f8",
4
4
  "description": "Matterbridge plugin manager for Matter",
5
5
  "author": "https://github.com/Luligu",
6
6
  "license": "Apache-2.0",