matterbridge 3.4.5-dev-20251224-1bb63cb → 3.4.5-dev-20251224-ea793b4

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
@@ -34,9 +34,11 @@ Advantages:
34
34
 
35
35
  - [DevContainer]: Refactored Dev Container setup. The Matterbridge instance can now be paired on native Linux hosts or WSL 2 with Docker engine CLI integration. On Docker Desktop on Windows or macOS is not possible cause Docker Desktop runs inside a VM and not directly on the host so mDNS is not supported.
36
36
  - [DevContainer]: Since is now possible to pair from Dev Container, named volumes have been added to persist storage and plugins across rebuilds.
37
- - [mb_mdns]: Add query and advertise interval. Improved help for easy mDNS testing.
37
+ - [mb_mdns]: Added query and advertise interval. Improved help for easy mDNS testing.
38
38
  - [mb_mdns]: Advertise full DNS-SD record set (PTR/SRV/TXT/A/AAAA) for matterbridge.\_http.\_tcp.local on port 8283.
39
39
  - [mdns]: Added TXT/SRV/A/AAAA encoders into the Mdns class.
40
+ - [mb_mdns]: Added broadcast parameter to allow advertising when multicast is not available.
41
+ - [mb_mdns]: Added \_matterbridge.\_tcp.local to query and advertise.
40
42
 
41
43
  ### Changed
42
44
 
@@ -1,5 +1,4 @@
1
1
  import { getIntParameter, getParameter, getStringArrayParameter, hasParameter } from '../utils/commandLine.js';
2
- import { getIpv4InterfaceAddress, getIpv6InterfaceAddress } from '../utils/network.js';
3
2
  import { MDNS_MULTICAST_IPV4_ADDRESS, MDNS_MULTICAST_IPV6_ADDRESS, MDNS_MULTICAST_PORT } from './multicast.js';
4
3
  import { Mdns } from './mdns.js';
5
4
  {
@@ -60,119 +59,109 @@ Examples:
60
59
  mdnsIpv4.filters.push(...filters);
61
60
  mdnsIpv6.filters.push(...filters);
62
61
  }
63
- function cleanupAndLogAndExit() {
62
+ async function cleanupAndLogAndExit() {
63
+ if (hasParameter('advertise')) {
64
+ advertise(mdnsIpv4, 0);
65
+ advertise(mdnsIpv6, 0);
66
+ }
67
+ await new Promise((resolve) => setTimeout(resolve, 250));
64
68
  mdnsIpv4.stop();
65
69
  mdnsIpv6.stop();
70
+ await new Promise((resolve) => setTimeout(resolve, 250));
66
71
  mdnsIpv4.logDevices();
67
72
  mdnsIpv6.logDevices();
68
73
  process.exit(0);
69
74
  }
70
- const queryUdp4 = () => {
71
- mdnsIpv4.log.info('Sending mDNS query for services...');
72
- mdnsIpv4.sendQuery([
73
- { name: '_matterc._udp.local', type: 12, class: 1, unicastResponse: false },
74
- { name: '_matter._tcp.local', type: 12, class: 1, unicastResponse: false },
75
- { name: '_shelly._tcp.local', type: 12, class: 1, unicastResponse: false },
76
- { name: '_http._tcp.local', type: 12, class: 1, unicastResponse: false },
77
- { name: '_services._dns-sd._udp.local', type: 12, class: 1, unicastResponse: false },
78
- ]);
79
- };
80
- const advertiseUdp4 = () => {
81
- mdnsIpv4.log.info('Sending mDNS advertisement for matterbridge service...');
82
- const serviceType = '_http._tcp.local';
83
- const instanceName = 'matterbridge._http._tcp.local';
84
- const hostName = 'matterbridge.local';
85
- const port = 8283;
86
- const ttl = 120;
87
- const ptrInstanceRdata = mdnsIpv4.encodeDnsName(instanceName);
88
- const ptrServiceTypeRdata = mdnsIpv4.encodeDnsName(serviceType);
89
- const srvRdata = mdnsIpv4.encodeSrvRdata(0, 0, port, hostName);
90
- const txtRdata = mdnsIpv4.encodeTxtRdata([`version=${pkg.version}`, 'path=/']);
91
- const answers = [
92
- { name: '_services._dns-sd._udp.local', rtype: 12, rclass: 1, ttl, rdata: ptrServiceTypeRdata },
93
- { name: serviceType, rtype: 12, rclass: 1, ttl, rdata: ptrInstanceRdata },
94
- { name: instanceName, rtype: 33, rclass: 1 | 32768, ttl, rdata: srvRdata },
95
- { name: instanceName, rtype: 16, rclass: 1 | 32768, ttl, rdata: txtRdata },
96
- ];
97
- try {
98
- const ipv4 = getIpv4InterfaceAddress();
99
- if (ipv4 && ipv4 !== '0.0.0.0') {
100
- answers.push({ name: hostName, rtype: 1, rclass: 1 | 32768, ttl, rdata: mdnsIpv4.encodeA(ipv4) });
101
- }
102
- }
103
- catch {
104
- }
105
- try {
106
- const ipv6 = getIpv6InterfaceAddress();
107
- if (ipv6 && ipv6 !== '::') {
108
- answers.push({ name: hostName, rtype: 28, rclass: 1 | 32768, ttl, rdata: mdnsIpv4.encodeAAAA(ipv6) });
109
- }
110
- }
111
- catch {
112
- }
113
- mdnsIpv4.sendResponse(answers);
114
- };
115
- const queryUdp6 = () => {
116
- mdnsIpv6.log.info('Sending mDNS query for services...');
117
- mdnsIpv6.sendQuery([
75
+ const query = (mdns) => {
76
+ mdns.log.info('Sending mDNS query for services...');
77
+ mdns.sendQuery([
118
78
  { name: '_matterc._udp.local', type: 12, class: 1, unicastResponse: true },
119
79
  { name: '_matter._tcp.local', type: 12, class: 1, unicastResponse: true },
80
+ { name: '_matterbridge._tcp.local', type: 12, class: 1, unicastResponse: true },
120
81
  { name: '_shelly._tcp.local', type: 12, class: 1, unicastResponse: true },
121
82
  { name: '_http._tcp.local', type: 12, class: 1, unicastResponse: true },
122
83
  { name: '_services._dns-sd._udp.local', type: 12, class: 1, unicastResponse: true },
123
84
  ]);
124
85
  };
125
- const advertiseUdp6 = () => {
126
- mdnsIpv6.log.info('Sending mDNS advertisement for matterbridge service...');
127
- const serviceType = '_http._tcp.local';
128
- const instanceName = 'matterbridge._http._tcp.local';
86
+ const advertise = (mdns, ttl = 120) => {
87
+ mdns.log.info(`Sending mDNS advertisement for matterbridge service with TTL ${ttl ? ttl.toString() : 'goodbye'}...`);
88
+ const httpServiceType = '_http._tcp.local';
89
+ const matterbridgeServiceType = '_matterbridge._tcp.local';
90
+ const httpInstanceName = 'matterbridge._http._tcp.local';
91
+ const matterbridgeInstanceName = 'matterbridge._matterbridge._tcp.local';
129
92
  const hostName = 'matterbridge.local';
130
93
  const port = 8283;
131
- const ttl = 120;
132
- const ptrInstanceRdata = mdnsIpv6.encodeDnsName(instanceName);
133
- const ptrServiceTypeRdata = mdnsIpv6.encodeDnsName(serviceType);
134
- const srvRdata = mdnsIpv6.encodeSrvRdata(0, 0, port, hostName);
135
- const txtRdata = mdnsIpv6.encodeTxtRdata([`version=${pkg.version}`, 'path=/']);
94
+ const ptrHttpServiceTypeRdata = mdns.encodeDnsName(httpServiceType);
95
+ const ptrMatterbridgeServiceTypeRdata = mdns.encodeDnsName(matterbridgeServiceType);
96
+ const ptrHttpInstanceRdata = mdns.encodeDnsName(httpInstanceName);
97
+ const ptrMatterbridgeInstanceRdata = mdns.encodeDnsName(matterbridgeInstanceName);
98
+ const srvRdata = mdns.encodeSrvRdata(0, 0, port, hostName);
99
+ const txtRdata = mdns.encodeTxtRdata([`version=${pkg.version}`, 'path=/']);
136
100
  const answers = [
137
- { name: '_services._dns-sd._udp.local', rtype: 12, rclass: 1, ttl, rdata: ptrServiceTypeRdata },
138
- { name: serviceType, rtype: 12, rclass: 1, ttl, rdata: ptrInstanceRdata },
139
- { name: instanceName, rtype: 33, rclass: 1 | 32768, ttl, rdata: srvRdata },
140
- { name: instanceName, rtype: 16, rclass: 1 | 32768, ttl, rdata: txtRdata },
101
+ { name: '_services._dns-sd._udp.local', rtype: 12, rclass: 1, ttl, rdata: ptrHttpServiceTypeRdata },
102
+ { name: httpServiceType, rtype: 12, rclass: 1, ttl, rdata: ptrHttpInstanceRdata },
103
+ { name: '_services._dns-sd._udp.local', rtype: 12, rclass: 1, ttl, rdata: ptrMatterbridgeServiceTypeRdata },
104
+ { name: matterbridgeServiceType, rtype: 12, rclass: 1, ttl, rdata: ptrMatterbridgeInstanceRdata },
105
+ { name: httpInstanceName, rtype: 33, rclass: 1 | 32768, ttl, rdata: srvRdata },
106
+ { name: matterbridgeInstanceName, rtype: 33, rclass: 1 | 32768, ttl, rdata: srvRdata },
107
+ { name: httpInstanceName, rtype: 16, rclass: 1 | 32768, ttl, rdata: txtRdata },
108
+ { name: matterbridgeInstanceName, rtype: 16, rclass: 1 | 32768, ttl, rdata: txtRdata },
141
109
  ];
142
110
  try {
143
- const ipv4 = getIpv4InterfaceAddress();
111
+ const ipv4 = mdns.getIpv4InterfaceAddress(mdns.interfaceName);
144
112
  if (ipv4) {
145
- answers.push({ name: hostName, rtype: 1, rclass: 1 | 32768, ttl, rdata: mdnsIpv6.encodeA(ipv4) });
113
+ answers.push({ name: hostName, rtype: 1, rclass: 1 | 32768, ttl, rdata: mdns.encodeA(ipv4) });
146
114
  }
147
115
  }
148
- catch {
116
+ catch (error) {
117
+ mdns.log.warn(`Error sending mDNS advertisement for matterbridge service A record: ${error.message}`);
149
118
  }
150
119
  try {
151
- const ipv6 = getIpv6InterfaceAddress();
120
+ const ipv6 = mdns.getIpv6InterfaceAddress(mdns.interfaceName);
152
121
  if (ipv6) {
153
- answers.push({ name: hostName, rtype: 28, rclass: 1 | 32768, ttl, rdata: mdnsIpv6.encodeAAAA(ipv6) });
122
+ answers.push({ name: hostName, rtype: 28, rclass: 1 | 32768, ttl, rdata: mdns.encodeAAAA(ipv6) });
154
123
  }
155
124
  }
156
- catch {
125
+ catch (error) {
126
+ mdns.log.warn(`Error sending mDNS advertisement for matterbridge service AAAA record: ${error.message}`);
127
+ }
128
+ const response = mdns.sendResponse(answers);
129
+ if (hasParameter('broadcast')) {
130
+ try {
131
+ const address = mdns.socketType === 'udp4' ? mdns.getIpv4InterfaceAddress(mdns.interfaceName) : mdns.getIpv6InterfaceAddress(mdns.interfaceName);
132
+ const mask = mdns.socketType === 'udp4' ? mdns.getNetmask(address) : undefined;
133
+ const broadcastAddress = mdns.socketType === 'udp4' ? mdns.getIpv4BroadcastAddress(address, mask) : mdns.getIpv6BroadcastAddress();
134
+ mdns.log.info(`Broadcasting mDNS advertisement for matterbridge service to ${broadcastAddress}...`);
135
+ mdns.socket.send(response, 0, response.length, mdns.multicastPort, broadcastAddress, (error) => {
136
+ if (error) {
137
+ mdns.log.error(`Error broadcasting mDNS advertisement: ${error.message}`);
138
+ }
139
+ else {
140
+ mdns.log.info(`mDNS advertisement broadcasted successfully to ${broadcastAddress}`);
141
+ }
142
+ });
143
+ }
144
+ catch (error) {
145
+ mdns.log.error(`Error broadcasting mDNS advertisement: ${error.message}`);
146
+ }
157
147
  }
158
- mdnsIpv6.sendResponse(answers);
159
148
  };
160
- process.on('SIGINT', () => {
161
- cleanupAndLogAndExit();
149
+ process.on('SIGINT', async () => {
150
+ await cleanupAndLogAndExit();
162
151
  });
163
152
  mdnsIpv4.start();
164
153
  mdnsIpv4.on('ready', (address) => {
165
154
  mdnsIpv4.log.info(`mdnsIpv4 server ready on ${address.family} ${address.address}:${address.port}`);
166
155
  if (hasParameter('advertise')) {
167
- advertiseUdp4();
156
+ advertise(mdnsIpv4);
168
157
  setInterval(() => {
169
- advertiseUdp4();
158
+ advertise(mdnsIpv4);
170
159
  }, getIntParameter('advertise') || 10000).unref();
171
160
  }
172
161
  if (hasParameter('query')) {
173
- queryUdp4();
162
+ query(mdnsIpv4);
174
163
  setInterval(() => {
175
- queryUdp4();
164
+ query(mdnsIpv4);
176
165
  }, getIntParameter('query') || 10000).unref();
177
166
  }
178
167
  });
@@ -180,19 +169,19 @@ Examples:
180
169
  mdnsIpv6.on('ready', (address) => {
181
170
  mdnsIpv6.log.info(`mdnsIpv6 server ready on ${address.family} ${address.address}:${address.port}`);
182
171
  if (hasParameter('advertise')) {
183
- advertiseUdp6();
172
+ advertise(mdnsIpv6);
184
173
  setInterval(() => {
185
- advertiseUdp6();
174
+ advertise(mdnsIpv6);
186
175
  }, getIntParameter('advertise') || 10000).unref();
187
176
  }
188
177
  if (hasParameter('query')) {
189
- queryUdp6();
178
+ query(mdnsIpv6);
190
179
  setInterval(() => {
191
- queryUdp6();
180
+ query(mdnsIpv6);
192
181
  }, getIntParameter('query') || 10000).unref();
193
182
  }
194
183
  });
195
- setTimeout(() => {
196
- cleanupAndLogAndExit();
184
+ setTimeout(async () => {
185
+ await cleanupAndLogAndExit();
197
186
  }, 600000);
198
187
  }
@@ -1,4 +1,5 @@
1
1
  import { BLUE, CYAN, db, er, GREEN, idn, MAGENTA, nf, rs } from 'node-ansi-logger';
2
+ import { hasParameter } from '../utils/commandLine.js';
2
3
  import { Multicast } from './multicast.js';
3
4
  export var DnsRecordType;
4
5
  (function (DnsRecordType) {
@@ -433,8 +434,10 @@ export class Mdns extends Multicast {
433
434
  return Buffer.concat([qname, qfields]);
434
435
  });
435
436
  const query = Buffer.concat([header, ...questionBuffers]);
436
- const decoded = this.decodeMdnsMessage(query);
437
- this.logMdnsMessage(decoded);
437
+ if (hasParameter('v') || hasParameter('verbose')) {
438
+ const decoded = this.decodeMdnsMessage(query);
439
+ this.logMdnsMessage(decoded);
440
+ }
438
441
  this.socket.send(query, 0, query.length, this.multicastPort, this.multicastAddress, (error) => {
439
442
  if (error) {
440
443
  this.log.error(`Dgram mDNS server failed to send query message: ${error.message}`);
@@ -448,6 +451,7 @@ export class Mdns extends Multicast {
448
451
  this.emit('sent', query, this.multicastAddress, this.multicastPort);
449
452
  }
450
453
  });
454
+ return query;
451
455
  }
452
456
  sendResponse(answers) {
453
457
  if (!Array.isArray(answers) || answers.length === 0) {
@@ -470,6 +474,10 @@ export class Mdns extends Multicast {
470
474
  return Buffer.concat([aname, answerFixed, rdata]);
471
475
  });
472
476
  const response = Buffer.concat([header, ...answerBuffers]);
477
+ if (hasParameter('v') || hasParameter('verbose')) {
478
+ const decoded = this.decodeMdnsMessage(response);
479
+ this.logMdnsMessage(decoded);
480
+ }
473
481
  this.socket.send(response, 0, response.length, this.multicastPort, this.multicastAddress, (error) => {
474
482
  if (error) {
475
483
  const items = answers.map((a) => `- name ${MAGENTA}${a.name}${er} type ${MAGENTA}${this.dnsTypeToString(a.rtype)}${er} class ${MAGENTA}${this.dnsResponseClassToString(a.rclass)}${er} ttl ${MAGENTA}${a.ttl}${er}`).join('\n');
@@ -482,6 +490,7 @@ export class Mdns extends Multicast {
482
490
  this.emit('sent', response, this.multicastAddress, this.multicastPort);
483
491
  }
484
492
  });
493
+ return response;
485
494
  }
486
495
  dnsTypeToString(type) {
487
496
  const typeMap = {
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "matterbridge",
3
- "version": "3.4.5-dev-20251224-1bb63cb",
3
+ "version": "3.4.5-dev-20251224-ea793b4",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "matterbridge",
9
- "version": "3.4.5-dev-20251224-1bb63cb",
9
+ "version": "3.4.5-dev-20251224-ea793b4",
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.5-dev-20251224-1bb63cb",
3
+ "version": "3.4.5-dev-20251224-ea793b4",
4
4
  "description": "Matterbridge plugin manager for Matter",
5
5
  "author": "https://github.com/Luligu",
6
6
  "license": "Apache-2.0",