Giter Club home page Giter Club logo

bonjour-service's People

Contributors

agents avatar altarbeastiful avatar dependabot[bot] avatar erossignon avatar gmaclennan avatar gregnr avatar hrueger avatar hypfer avatar jlucidar avatar jorrit avatar kkushimoto avatar marionebl avatar mdidon avatar mh-cbon avatar snyk-bot avatar watson avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

bonjour-service's Issues

'up' event not firing for 'custom' type

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.

It does not seem like publish() actually publishes publicly properly

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:

  • Mac OS Sonoma 14.2.1 on a M1 Apple Silicon
  • npx ts-node -v: v10.9.2
  • node -v: `v18.13.0
  • Discovery.app 2.1.0 (6)

Description

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.

My setup

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.
Screenshot 2024-01-05 at 19 24 39

'down' event not firing when other service shutdown

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)
})

Not discovering services on my local network

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?

subtypes are not used in find()!?

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.

`browser.services` is private despite being part of the public API documentation

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!

Browser does't respect TTL of services

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().

`BrowserConfig` Interface - Incorrect Required Property

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.

type : string

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.

Other services only detected if registered after Browser has been created

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.

TypeError: Cannot convert undefined or null to object

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

Support filtering on `host`, `name` and address family (IPv4 vs IPv6)

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 ๐Ÿ˜Š

"type" field not respected during publish

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 type of "options" in the Bonjour constructor is incorrect

The options parameter is specified to have the type ServiceConfig:

constructor(opts?: ServiceConfig | undefined) {

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)
}

Discover services that have already been announced or trigger again the announcement

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 :

  • Restart the announcement for existing service as a network change has happened
  • Existing services should answer PTR query triggered by the new service as they browse for matching service. Right now only the initial service announcement seems to answer those queries.

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
      }
);

Feature Request: Please consider refactoring Bonjour class.

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.

`find()` txt filtering does not work

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.