From 3ac120bc0f19ed9fd7aa079d053aa34bb4eea3aa Mon Sep 17 00:00:00 2001 From: Dominic Griesel Date: Fri, 7 Jun 2024 15:22:50 +0200 Subject: [PATCH] feat(mock-server): enable mDNS discovery --- packages/zwave-js/package.json | 1 + .../zwave-js/src/lib/driver/mDNSDiscovery.ts | 5 +++ packages/zwave-js/src/mockServer.ts | 44 ++++++++++++++++++- yarn.lock | 22 ++++++++++ 4 files changed, 70 insertions(+), 2 deletions(-) diff --git a/packages/zwave-js/package.json b/packages/zwave-js/package.json index 2d31a9ac861..0a5368cdc1f 100644 --- a/packages/zwave-js/package.json +++ b/packages/zwave-js/package.json @@ -87,6 +87,7 @@ "dependencies": { "@alcalzone/jsonl-db": "^3.1.1", "@alcalzone/pak": "^0.10.1", + "@homebridge/ciao": "^1.2.0", "@zwave-js/cc": "workspace:*", "@zwave-js/config": "workspace:*", "@zwave-js/core": "workspace:*", diff --git a/packages/zwave-js/src/lib/driver/mDNSDiscovery.ts b/packages/zwave-js/src/lib/driver/mDNSDiscovery.ts index dea6d1ba272..9d49511abda 100644 --- a/packages/zwave-js/src/lib/driver/mDNSDiscovery.ts +++ b/packages/zwave-js/src/lib/driver/mDNSDiscovery.ts @@ -15,6 +15,7 @@ export function discoverRemoteSerialPorts( reuseAddr: true, loopback: false, noInit: true, + ttl: 10, }); let timer: NodeJS.Timeout | undefined; @@ -31,9 +32,13 @@ export function discoverRemoteSerialPorts( return { txt: resp.answers.find( (n) => n.type === "TXT" && n.name === data, + ) ?? resp.additionals.find( + (n) => n.type === "TXT" && n.name === data, ), srv: resp.answers.find( (n) => n.type === "SRV" && n.name === data, + ) ?? resp.additionals.find( + (n) => n.type === "SRV" && n.name === data, ), }; }) diff --git a/packages/zwave-js/src/mockServer.ts b/packages/zwave-js/src/mockServer.ts index 16d82a0cdae..780e1be648c 100644 --- a/packages/zwave-js/src/mockServer.ts +++ b/packages/zwave-js/src/mockServer.ts @@ -1,3 +1,9 @@ +import { + type CiaoService, + Protocol, + type Responder as MdnsResponder, + getResponder as getMdnsResponder, +} from "@homebridge/ciao"; import { NotificationCCValues } from "@zwave-js/cc"; import { CommandClasses, @@ -9,6 +15,7 @@ import { type MockPortBinding, createAndOpenMockedZWaveSerialPort, } from "@zwave-js/serial/mock"; +import { getErrorMessage } from "@zwave-js/shared"; import { type ConfigurationCCCapabilities, MockController, @@ -70,6 +77,8 @@ export class MockServer { private serialport: ZWaveSerialPort | undefined; private binding: MockPortBinding | undefined; private server: Server | undefined; + private responder: MdnsResponder | undefined; + private service: CiaoService | undefined; private mockController: MockController | undefined; private mockNodes: MockNode[] | undefined; @@ -123,6 +132,19 @@ export class MockServer { }); }); + const port = this.options.port ?? 5555; + this.responder = getMdnsResponder(); + this.service = this.responder.createService({ + name: "zwave-mock-server", + type: "zwave", + protocol: Protocol.TCP, + port, + txt: { + manufacturer: "Z-Wave JS", + model: "Mock Server", + }, + }); + // Do not allow more than one client to connect this.server.maxConnections = 1; @@ -135,20 +157,38 @@ export class MockServer { this.server.listen( { host: this.options.interface, - port: this.options.port ?? 5555, + port, }, - () => { + async () => { const address: AddressInfo = this.server!.address() as any; console.log( `Server listening on tcp://${address.address}:${address.port}`, ); + promise.resolve(); + + // Advertise the service via mDNS + try { + await this.service!.advertise(); + console.log( + `Enabled mDNS service discovery.`, + ); + } catch (e) { + console.error( + `Failed to enable mDNS service discovery: ${ + getErrorMessage(e) + }`, + ); + } }, ); } public async stop(): Promise { console.log("Shutting down mock server..."); + await this.service?.end(); + await this.service?.destroy(); + await this.responder?.shutdown(); this.mockController?.destroy(); this.server?.close(); await this.serialport?.close(); diff --git a/yarn.lock b/yarn.lock index 95319d27f63..563a6d58446 100644 --- a/yarn.lock +++ b/yarn.lock @@ -788,6 +788,20 @@ __metadata: languageName: node linkType: hard +"@homebridge/ciao@npm:^1.2.0": + version: 1.2.0 + resolution: "@homebridge/ciao@npm:1.2.0" + dependencies: + debug: ^4.3.4 + fast-deep-equal: ^3.1.3 + source-map-support: ^0.5.21 + tslib: ^2.6.2 + bin: + ciao-bcs: lib/bonjour-conformance-testing.js + checksum: c2a30ee0d092464f5f6b88e9feeafe801d5d590652f39d46b28f9d22ded65f845747b9a824748295dd02cf467bfb1c44904c4eb3ed13251b5fb7b16b937debf7 + languageName: node + linkType: hard + "@humanwhocodes/config-array@npm:^0.11.14": version: 0.11.14 resolution: "@humanwhocodes/config-array@npm:0.11.14" @@ -8632,6 +8646,13 @@ resolve@^1.10.0: languageName: node linkType: hard +"tslib@npm:^2.6.2": + version: 2.6.3 + resolution: "tslib@npm:2.6.3" + checksum: 74fce0e100f1ebd95b8995fbbd0e6c91bdd8f4c35c00d4da62e285a3363aaa534de40a80db30ecfd388ed7c313c42d930ee0eaf108e8114214b180eec3dbe6f5 + languageName: node + linkType: hard + "tsutils@npm:^3.21.0": version: 3.21.0 resolution: "tsutils@npm:3.21.0" @@ -9294,6 +9315,7 @@ resolve@^1.10.0: dependencies: "@alcalzone/jsonl-db": ^3.1.1 "@alcalzone/pak": ^0.10.1 + "@homebridge/ciao": ^1.2.0 "@microsoft/api-extractor": ^7.43.0 "@types/fs-extra": ^11.0.4 "@types/node": ^18.19.31