onlxltd / bonjour-service Goto Github PK
View Code? Open in Web Editor NEWThis project forked from watson/bonjour
A Bonjour/Zeroconf protocol implementation in TypeScript
Home Page: https://npmjs.com/package/bonjour-service
License: MIT License
This project forked from watson/bonjour
A Bonjour/Zeroconf protocol implementation in TypeScript
Home Page: https://npmjs.com/package/bonjour-service
License: MIT License
Hey,
First of all thank you for your commitment to this library.
I'd like to access the field browser.services
in my application, but unfortunately the field is set to private
. However, the API documentation indicates that the field should be accessible publicly.
Thus, I wanted to ask if I could contribute a PR to fix this issue? For now, I'll just use a workaround for accessing the field, but it'd be nice to be able to remove this hack in the future.
I am looking forward to hearing from you!
Hi and thank you for the great work.
I create a new instance of 'bonjour-service'
const zeroconf = new Bonjour();
Then I publish a service, with the 'osc' (Open Sound Control) type:
const service = zeroconf.publish({
name: 'my_name',
port: 56032,
type: 'osc',
protocol: 'udp',
txt: {
test: 'TEST',
},
});
service.on('up', () => {
// This is fired, and 'published' entry is set to true.
console.log('Service is up', service);
});
And I listen to all published services with this code:
const browser = zeroconf.find();
browser.on('up', (service: any) => {
// This is not fired for my custom type.
console.log('UP', service.name, service.type);
});
If I define the type of the service to an official type (IANA link included in the README) like 'http', the browser immediately handles the publication. But, with my 'custom' type (not so custom, OSC protocol and zeroconf 'osc' type are widely used, in real-time video softwares for example), the browser doesn't receive anything. I checked in your code and the publication is well received, but no event is fired.
Do I miss something?
Thank you.
Editing this request as my understanding of multicast-dns
(and by extension bonjour-service
) has improved.
It's helpful that the Server
class exposes the global multicast-dns
instance, but it would also be good if that same paradigm extended to the Bonjour
class (exposing it's server
and registry
properties maybe as readonly).
It might also be a good time to make destroy
an idempotent operation.
This may be not a trivial feature to implement, because different DNS records making up a service have different TTL. TTL of .local
record is typically 2 minutes, and for other records it is usually much longer.
There is also another related problem. If a device with a service was unplugged (not shut down gracefully), its services will live forever in browser.services
.
In my app I tried to call browser.update()
to make sure that services are still online, but the browser drops responses from already discovered services:
matches.forEach((service: Service) => {
if (self.serviceMap[service.fqdn]) return // ignore already registered services
self.addService(service)
})
So on the side of the app there is no way to distinguish between a service went offline because its device was unplugged (with no goodbye packet) and a service that is online and diligently sends discovery responses.
Workaround is to recreate the browser object each time I want to call browser.update()
.
This might be duplicate of #9 or #13, if that's the case I'm sorry!
๐ฅ ๐ป Thanks in advance for great work with open sourcing this. ๐
I'm trying this on:
npx ts-node -v
: v10.9.2
node -v
: `v18.13.02.1.0 (6)
I'm trying to implement the react-native-zeroconf
library in my react native app and serve from my server with your bonjour-service
, but It does not seem that the announce from this library is reaching the network properly.
If I use the Discovery App I can see services such as Airplay and others, but not whatever I announce from this library.
If I try to scan for airplay
over tcp
with react-native-zeroconf
I get matches from within my iOS simulator I will see my apple TV which is only connected by bluetooth even.
index.ts
import Bonjour from "bonjour-service";
const init = async () => {
const instance = new Bonjour();
console.log("Publishing bonjour service");
const a = instance.publish({
name: "TestApp Desktop Server",
type: "testapp",
protocol: "tcp",
port: 3000,
});
while (true) {
// keep the process alive
await new Promise((resolve) => setTimeout(resolve, 4000));
console.log("instance", a);
await new Promise((resolve) => setTimeout(resolve, 2000));
console.log("Waiting...");
}
};
init();
It will output something like this:
instance Service {
_events: [Object: null prototype] {},
_eventsCount: 0,
_maxListeners: undefined,
probe: true,
published: true,
activated: true,
destroyed: false,
txtService: DnsTxt { binary: undefined },
name: 'TestApp Desktop Server',
protocol: 'tcp',
type: '_testapp._tcp',
port: 3000,
host: 'carambola-124.local',
fqdn: 'TestApp Desktop Server._testapp._tcp.local',
txt: undefined,
subtypes: undefined,
disableIPv6: false,
start: [Function: bound start],
stop: [Function: bound stop],
[Symbol(kCapture)]: false
}
Waiting...
If I use bounjour-service
as client it works, but not ideal for a react native environment, and it's weird that other applications cannot see the announcement either.
Can't get services that browser has found via browser.services
once I've done instance.find()
. Is this intended or am I missing something?
Should type
not be set to floopy-http
?
// @ts-check
const { hostname } = require('os');
const { Bonjour } = require('bonjour-service');
const bonjour = new Bonjour();
bonjour.publish({
type: 'floopy-http',
name: `Floopy-${hostname()}`,
port: 3000,
});
bonjour.find({
type: 'floopy-http'
}, service => {
console.log(service);
// {
// addresses: [],
// name: 'Floopy-Sophie-2',
// fqdn: 'Floopy-Sophie-2.local._floopy-http._tcp.local',
// host: 'Sophie-2.local',
// referer: { address: '192.168.1.163', family: 4, port: 5353, size: 230 },
// port: 3000,
// type: 'local',
// protocol: 'floopy-http',
// subtypes: [ 'tcp' ],
// rawTxt: [],
// txt: {}
// }
});
The BrowserConfig
interface requires type
but I don't think that's really meant to be required. The README says that all options are optional.
bonjour-service/src/lib/browser.ts
Line 15 in 67ed22f
This should be changed to:
export interface BrowserConfig {
type? : string // now optional
name? : string
protocol? : 'tcp' | 'udp'
subtypes? : string[]
txt? : KeyValue
}
Making this change myself gives me the expected behavior, which is looking for all service types.
I use multiple application but i find any other service but not the service created with this npm package:
https://play.google.com/store/apps/details?id=com.druk.servicebrowser
https://play.google.com/store/apps/details?id=ua.com.streamsoft.pingtools
I'm using Bonjour to connect a few components as a mesh network. As soon as they start and connect to hte network, each components publish a service and find all existing services using a custom type.
Sometimes a service will connect to the network after the existing services have finished their initial service announcement.
In that case the new service announce and gets discovered by the network but the existing services cannot be found by the new service as their initial announcement has already stopped.
Is there any mechanism I can use to make the new service discover the existing ones ?
From reading the RFC, I could see there's two possible options :
As a side note, I'm using different instance in each component for browsing and publishing as they should publish on a specific interface, but can browse on any interface :
this.bonjourBrowser = new Bonjour();
this.bonjourSender = new Bonjour({
loopback: false,
interface: 169.254.9.6,
});
this.bonjourSender.publish({
type: 'MyCustomType',
name: 'AUniqueComponentName',
port: 3000,
host: 169.254.9.6
});
this.bonjourBrowser.find(
{ type: 'MerckDevice' },
(service) => {
// Register new service
}
);
I am having a problem where my Browser instance can only discover services that have been started / registered after the Browser has been created and .find()
called.
What's strange is this is only on some machines. Some systems are fine. Firewall is disabled for testing. These machines are connected over LAN only.
The service is not published with bonjour-service, but a python application using https://github.com/python-zeroconf/python-zeroconf
Wondering if anyone else has experienced this with bonjour-service, or DNS-SD in general.
First off: THANK YOU! This works great! ๐ I'm using this in https://github.com/wimleers/homebridge-sma-home-manager.
This is what I have today:
bonjour.find({ type: 'http' }, function () {
// custom filtering logic
});
finds the result I need:
{
addresses: [ '2a02:1812:1416:6f00:240:adff:feb7:e999', '192.168.0.237' ],
subtypes: [],
rawTxt: [ <Buffer > ],
txt: {},
name: 'Website for SMA-Inverter: SMA3010955555-3',
fqdn: 'Website for SMA-Inverter: SMA3010955555-3._http._tcp.local',
host: 'SMA3010955555-3.local',
referer: { address: '192.168.0.237', family: 'IPv4', port: 5353, size: 177 },
port: 443,
type: 'http',
protocol: 'tcp'
}
But much of that custom filtering logic could easily be done by making .find()
and .findOne()
's options
argument more powerful, by expanding what src/lib/utils/filter-service.ts
does.
IOW:
bonjour.findOne({
type: 'http',
host: /SMAd+/,
name: /^Website for SMA-Inverter .*/
addressFamily: 'IPv4'
}, function () {
// no filtering logic needed anymore!
});
That'd result in my getting
{
addresses: [ '192.168.0.237' ],
subtypes: [],
rawTxt: [ <Buffer > ],
txt: {},
name: 'Website for SMA-Inverter: SMA3010955555-3',
fqdn: 'Website for SMA-Inverter: SMA3010955555-3._http._tcp.local',
host: 'SMA3010955555-3.local',
referer: { address: '192.168.0.237', family: 'IPv4', port: 5353, size: 177 },
port: 443,
type: 'http',
protocol: 'tcp'
}
โฆ with less logic needed on my end ๐
With version 1.2.0 we are getting this issue with Homebridge-config-ui-x
TypeError: Cannot convert undefined or null to object
at Function.keys (<anonymous>)
at equalTxt (/opt/homebridge/lib/node_modules/homebridge-config-ui-x/node_modules/bonjour-service/src/lib/utils/equal-txt.ts:2:24)
at Browser.updateService (/opt/homebridge/lib/node_modules/homebridge-config-ui-x/node_modules/bonjour-service/src/lib/browser.ts:145:21)
at /opt/homebridge/lib/node_modules/homebridge-config-ui-x/node_modules/bonjour-service/src/lib/browser.ts:108:30
at Array.forEach (<anonymous>)
at /opt/homebridge/lib/node_modules/homebridge-config-ui-x/node_modules/bonjour-service/src/lib/browser.ts:106:25
at Array.forEach (<anonymous>)
at EventEmitter.onresponse (/opt/homebridge/lib/node_modules/homebridge-config-ui-x/node_modules/bonjour-service/src/lib/browser.ts:98:34)
at EventEmitter.emit (node:events:514:28)
at Socket.<anonymous> (/opt/homebridge/lib/node_modules/homebridge-config-ui-x/node_modules/multicast-dns/index.js:49:43)
at Socket.emit (node:events:514:28)
at UDP.onMessage (node:dgram:941:8)
We resolved by dropping back to version 1.1.1
homebridge/homebridge-config-ui-x#1973
homebridge/homebridge-syno-spk#145
import Bonjour from 'bonjour-service'
const instance = new Bonjour()
// advertise an HTTP server on port 3000
instance.publish({ name: 'My Web Server', type: 'http', port: 3000 })
// browse for all http services
let browser =instance.find({ type: 'http' })
browser.on('up', function (service) {
console.log('server up:', service)
})
browser.on('down', function (service) { <---- It doesn't work when other service shutdown
console.log('server down:', service)
})
The find()
methods accepts subtypes
, but it does not filter for me and a code review showed also no sign that subtypes
is actually used in the browser.
multicast-dns 6.2.3
currently used which has known vulnerability shown at https://npmjs.com/advisories/1745.
Update multicast-dns
to latest version
Is there a particular reason that the library uses any
, rather then being more explicit with the types?
When using common linting rules, such as @typescript-eslint/no-unsafe-call
, when trying to call .stop()
on a Service
, linting will fail. Could the Service.stop
definition be changed to void | undefined
instead?
https://typescript-eslint.io/rules/no-unsafe-call/
Happy to provide a PR if a maintainer agrees.
The options parameter is specified to have the type ServiceConfig:
Line 16 in 26efb69
However, this parameter is passed directly to the multicast-dns server which has a very different type for its options.
{
multicast: true // use udp multicasting
interface: '192.168.0.2' // explicitly specify a network interface. defaults to all
port: 5353, // set the udp port
ip: '224.0.0.251', // set the udp ip
ttl: 255, // set the multicast ttl
loopback: true, // receive your own packets
reuseAddr: true // set the reuseAddr option when creating the socket (requires node >=0.11.13)
}
Hi, first of all, thanks for this rewrite. I'm using this lib in multiple projects, and it works great.
However, I do have a strange bug:
This is my query function:
bonjour.find({
type: "blackmagic",
txt: {
class: "AtemSwitcher"
},
}, (service) => {
console.log(service);
});
but I do also get answers from services which don't match the txt class:
{
addresses: [ '192.168.1.69' ],
rawTxt: [
<Buffer 74 78 74 76 65 72 73 3d 31>,
<Buffer 6e 61 6d 65 3d 42 6c 61 63 6b 6d 61 67 69 63 20 53 6d 61 72 74 56 69 65 77 20
44 75 6f>,
<Buffer 63 6c 61 73 73 3d 53 6d 61 72 74 56 69 65 77>,
<Buffer 70 72 6f 74 6f 63 6f 6c 20 76 65 72 73 69 6f 6e 3d 31 2e 33>,
<Buffer 69 6e 74 65 72 6e 61 6c 20 76 65 72 73 69 6f 6e 3d 46 57 3a 30 39 2d 45 4d 3a
65 34 32 31 37 63 39 38 2d 48 57 3a 31 33>,
<Buffer 75 6e 69 71 75 65 20 69 64 3d 37 63 32 65 30 64 31 34 63 65 38 38>
],
txt: {
txtvers: '1',
name: 'Blackmagic SmartView Duo',
class: 'SmartView',
'protocol version': '1.3',
'internal version': 'FW:09-EM:e4217c98-HW:13',
'unique id': '7c2e0d14ce88'
},
name: 'SmartView Duo',
fqdn: 'SmartView Duo._blackmagic._tcp.local',
host: 'SmartViewDuo-7c2e0d14ce88.local',
referer: { address: '192.168.1.69', family: 'IPv4', port: 5353, size: 315 },
port: 9992,
type: 'blackmagic',
protocol: 'tcp',
subtypes: []
}
[2022-05-05 10:13:53] info: Found Device via MDNS: SmartView Duo (192.168.1.69 / SmartView
Duo._blackmagic._tcp.local)
{
addresses: [ '192.168.1.50' ],
rawTxt: [
<Buffer 74 78 74 76 65 72 73 3d 31>,
<Buffer 6e 61 6d 65 3d 42 6c 61 63 6b 6d 61 67 69 63 20 41 54 45 4d 20 31 20 4d 2f 45
20 50 72 6f 64 75 63 74 69 6f 6e 20 53 74 75 64 69 6f 20 34 4b>,
<Buffer 63 6c 61 73 73 3d 41 74 65 6d 53 77 69 74 63 68 65 72>,
<Buffer 70 72 6f 74 6f 63 6f 6c 20 76 65 72 73 69 6f 6e 3d 30 2e 30>,
<Buffer 69 6e 74 65 72 6e 61 6c 20 76 65 72 73 69 6f 6e 3d 43 50 55 3a 30 30 2d 46 57
3a 30 30 33 39 2d 45 4d 3a 35 30 30 32 61 31 33 62>,
<Buffer 75 6e 69 71 75 65 20 69 64 3d 37 63 32 65 30 64 61 34 63 62 62 32>
],
txt: {
txtvers: '1',
name: 'Blackmagic ATEM 1 M/E Production Studio 4K',
class: 'AtemSwitcher',
'protocol version': '0.0',
'internal version': 'CPU:00-FW:0039-EM:5002a13b',
'unique id': '7c2e0da4cbb2'
},
name: 'ATEM 1 M/E Production Studio 4K',
fqdn: 'ATEM 1 M/E Production Studio 4K._blackmagic._tcp.local',
host: 'ATEM-4K1ME-7c2e0da4cbb2.local',
referer: { address: '192.168.1.50', family: 'IPv4', port: 5353, size: 355 },
port: 9910,
type: 'blackmagic',
protocol: 'tcp',
subtypes: []
}
I know that I can just add a simple if clause to the service up function, but I feel like this should be fixed in the lib directly ;-)
If you can give me a hint about what file to look at, I'm happy to make a PR.
I have the simple setup from the README.
Service.js:
import Bonjour from 'bonjour-service'
// some code to get my http server up and running
const instance = new Bonjour()
instance.publish({ name: 'My Web Server', type: 'http', port: 3000 })
Client.js:
import Bonjour from 'bonjour-service'
instance.find({ type: 'http' }, function (service) {
console.log('Found an HTTP server:', service) // this never triggers
})
When I publish and search services on the same computer (i am on macOS 12.1) they are discovered. But when I run the above code on two different machines eg. One computer is running Service.js
and another one is running Client.js
the find callback never triggers and no services are found.
I can confirm that my HTTP server is visible if I manually input the computer address and go for example to the GET /api
endpoint on another computer so they definitely see each other.
Any tips on debugging this?
unit tests seem not to be maintained and not run as part of the publishing process.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.