bonjour-hap 3.10.3-beta.0 → 3.10.3-beta.2

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/index.d.ts CHANGED
@@ -149,7 +149,18 @@ export interface Bonjour {
149
149
  options: BonjourFindOptions,
150
150
  callback?: (service: BonjourService) => void
151
151
  ): Browser;
152
- destroy(): void;
152
+ /**
153
+ * Tear down the responder. Goodbye records are broadcast for every
154
+ * published service before the underlying mdns socket is closed.
155
+ * The optional callback fires once teardown is complete.
156
+ */
157
+ destroy(callback?: () => void): void;
158
+ /**
159
+ * Emitted when the underlying mdns socket reports an error or an
160
+ * outgoing response fails. If no listener is attached, the error is
161
+ * logged to `console.warn` so it does not crash the process.
162
+ */
163
+ on(event: "error", listener: (err: Error) => void): this;
153
164
  }
154
165
 
155
166
  export interface BonjourFactory {
package/index.js CHANGED
@@ -1,5 +1,7 @@
1
1
  'use strict'
2
2
 
3
+ const util = require('util')
4
+ const EventEmitter = require('events').EventEmitter
3
5
  const Registry = require('./lib/Registry.js')
4
6
  const Server = require('./lib/Server.js')
5
7
  const Browser = require('./lib/Browser.js')
@@ -7,11 +9,22 @@ const Browser = require('./lib/Browser.js')
7
9
  function Bonjour (opts) {
8
10
  if (!(this instanceof Bonjour)) { return new Bonjour(opts) }
9
11
 
12
+ EventEmitter.call(this)
13
+
10
14
  this._server = new Server(opts)
11
15
  this._registry = new Registry(this._server)
16
+ this._server.on('error', err => {
17
+ if (this.listenerCount('error') > 0) {
18
+ this.emit('error', err)
19
+ } else {
20
+ console.warn('bonjour-hap:', err.message || err)
21
+ }
22
+ })
12
23
  }
13
24
 
14
- Bonjour.prototype = {
25
+ util.inherits(Bonjour, EventEmitter)
26
+
27
+ Object.assign(Bonjour.prototype, {
15
28
  publish: function (opts) {
16
29
  return this._registry.publish(opts)
17
30
  },
@@ -33,10 +46,12 @@ Bonjour.prototype = {
33
46
  return browser
34
47
  },
35
48
 
36
- destroy: function () {
37
- this._registry.destroy()
38
- this._server.mdns.destroy()
49
+ destroy: function (cb) {
50
+ this._registry.destroy(() => {
51
+ this._server.mdns.destroy()
52
+ if (cb) cb()
53
+ })
39
54
  }
40
- }
55
+ })
41
56
 
42
57
  module.exports = Bonjour
package/lib/Browser.js CHANGED
@@ -3,6 +3,7 @@
3
3
  const util = require('util')
4
4
  const EventEmitter = require('events').EventEmitter
5
5
  const serviceName = require('multicast-dns-service-types')
6
+ const deepEqual = require('fast-deep-equal')
6
7
  const dnsEqual = require('./utils/dnsEqual')
7
8
  const dnsTxt = require('./utils/txtDecoder')
8
9
 
@@ -35,7 +36,7 @@ function Browser (mdns, opts, onup) {
35
36
  this._mdns = mdns
36
37
  this._onresponse = null
37
38
  this._serviceMap = {}
38
- this._txt = dnsTxt(opts.txt)
39
+ this._txt = dnsTxt(opts && opts.txt)
39
40
 
40
41
  if (!opts || !opts.type) {
41
42
  this._name = WILDCARD
@@ -67,7 +68,7 @@ Browser.prototype.start = function () {
67
68
  this._onresponse = function (packet, rinfo) {
68
69
  if (self._wildcard) {
69
70
  packet.answers.forEach(function (answer) {
70
- if (answer.type !== 'PTR' || answer.name !== self._name || answer.name in nameMap) return
71
+ if (answer.type !== 'PTR' || !dnsEqual(answer.name, self._name) || answer.data in nameMap) return
71
72
  nameMap[answer.data] = true
72
73
  self._mdns.query(answer.data, 'PTR')
73
74
  })
@@ -123,10 +124,19 @@ Browser.prototype._updateService = function (service) {
123
124
  return false
124
125
  })
125
126
  if (!cachedService) return
127
+ if (!serviceChanged(cachedService, service)) return
126
128
  this.services[index] = service
127
129
  this.emit('update', service)
128
130
  }
129
131
 
132
+ function serviceChanged (a, b) {
133
+ return a.host !== b.host ||
134
+ a.port !== b.port ||
135
+ !deepEqual(a.addresses, b.addresses) ||
136
+ !deepEqual(a.subtypes, b.subtypes) ||
137
+ !deepEqual(a.txt, b.txt)
138
+ }
139
+
130
140
  Browser.prototype._removeService = function (fqdn) {
131
141
  let service, index
132
142
  this.services.some(function (s, i) {
package/lib/Prober.js CHANGED
@@ -30,7 +30,7 @@ Prober.prototype = {
30
30
 
31
31
  start: function () {
32
32
  this.mdns.on('response', this.bound)
33
- setTimeout(this.try.bind(this), Math.random() * 250)
33
+ setTimeout(this.try.bind(this), Math.random() * 250).unref()
34
34
  },
35
35
 
36
36
  try: function () {
package/lib/Registry.js CHANGED
@@ -26,8 +26,13 @@ Registry.prototype = {
26
26
  this._services = []
27
27
  },
28
28
 
29
- destroy: function () {
30
- for (let i = 0; i < this._services.length; i++) { this._services[i].destroy() }
29
+ destroy: function (cb) {
30
+ const services = this._services.slice()
31
+ this._services = []
32
+ this._tearDown(services, () => {
33
+ for (let i = 0; i < services.length; i++) { services[i].destroy() }
34
+ if (cb) cb()
35
+ })
31
36
  },
32
37
 
33
38
  /**
@@ -46,7 +51,7 @@ Registry.prototype = {
46
51
 
47
52
  const records = services.map(function (service) {
48
53
  service.deactivate()
49
- const records = service._records(true)
54
+ const records = service._records()
50
55
  records.forEach(function (record) {
51
56
  record.ttl = 0 // prepare goodbye message
52
57
  })
package/lib/Server.js CHANGED
@@ -1,17 +1,23 @@
1
1
  'use strict'
2
2
 
3
+ const util = require('util')
4
+ const EventEmitter = require('events').EventEmitter
3
5
  const multicastdns = require('multicast-dns')
4
6
  const dnsEqual = require('./utils/dnsEqual')
5
7
  const helpers = require('./helpers.js')
6
8
 
7
9
  const Server = function (opts) {
10
+ EventEmitter.call(this)
8
11
  this.mdns = multicastdns(opts)
9
12
  this.mdns.setMaxListeners(0)
10
13
  this.registry = {}
11
14
  this.mdns.on('query', this._respondToQuery.bind(this))
15
+ this.mdns.on('error', err => this.emit('error', err))
12
16
  }
13
17
 
14
- Server.prototype = {
18
+ util.inherits(Server, EventEmitter)
19
+
20
+ Object.assign(Server.prototype, {
15
21
  _respondToQuery: function (query) {
16
22
  for (let i = 0; i < query.questions.length; i++) {
17
23
  const question = query.questions[i]
@@ -24,7 +30,7 @@ Server.prototype = {
24
30
  ? Object.keys(this.registry).map(this._recordsFor.bind(this, name)).flat()
25
31
  : this._recordsFor(name, type)
26
32
 
27
- if (answers.length === 0) return
33
+ if (answers.length === 0) continue
28
34
 
29
35
  // generate the additionals section
30
36
  let additionals = []
@@ -57,7 +63,7 @@ Server.prototype = {
57
63
  answers,
58
64
  additionals
59
65
  }, err => {
60
- if (err) throw err // TODO: Handle this (if no callback is given, the error will be ignored)
66
+ if (err) this.emit('error', err)
61
67
  })
62
68
  }
63
69
  },
@@ -89,7 +95,7 @@ Server.prototype = {
89
95
  if (!(type in this.registry)) { continue }
90
96
 
91
97
  this.registry[type] = this.registry[type].filter(r => {
92
- return r.name !== record.name
98
+ return !dnsEqual(r.name, record.name)
93
99
  })
94
100
  }
95
101
  },
@@ -103,6 +109,6 @@ Server.prototype = {
103
109
  })
104
110
  }
105
111
 
106
- }
112
+ })
107
113
 
108
114
  module.exports = Server
package/lib/Service.js CHANGED
@@ -83,7 +83,7 @@ const proto = {
83
83
 
84
84
  stop: function (cb) {
85
85
  if (!this._activated) {
86
- cb()
86
+ if (cb) cb()
87
87
  return
88
88
  }
89
89
 
@@ -109,19 +109,25 @@ const proto = {
109
109
  if (this.timer) { clearTimeout(this.timer) }
110
110
 
111
111
  this.delay = 1000
112
+ this._emitAnnounce(silent)
113
+ },
114
+
115
+ _emitAnnounce: function (silent) {
116
+ if (this._destroyed) { return }
112
117
  this.emit('service-announce-request', this.packet, silent || false, this.onAnnounceComplete.bind(this))
113
118
  },
114
119
 
115
120
  onAnnounceComplete: function () {
121
+ if (this._destroyed || !this._activated) return
122
+
116
123
  if (!this.published) {
117
- this._activated = true // not sure if this is needed here
118
124
  this.published = true
119
125
  this.emit('up')
120
126
  }
121
127
 
122
128
  this.delay = this.delay * REANNOUNCE_FACTOR
123
- if (this.delay < REANNOUNCE_MAX_MS && !this._destroyed && this._activated) {
124
- this.timer = setTimeout(this.announce.bind(this), this.delay).unref()
129
+ if (this.delay < REANNOUNCE_MAX_MS) {
130
+ this.timer = setTimeout(this._emitAnnounce.bind(this), this.delay).unref()
125
131
  } else {
126
132
  this.timer = undefined
127
133
  this.delay = undefined
@@ -145,12 +151,12 @@ const proto = {
145
151
  this.published = false
146
152
  },
147
153
 
148
- _records: function (teardown) {
154
+ _records: function () {
149
155
  const records = [this._rrPtr(), this._rrSrv(), this._rrTxt()]
150
156
 
151
157
  records.push(...this._addressRecords())
152
158
 
153
- if (!teardown && this.addUnsafeServiceEnumerationRecord) {
159
+ if (this.addUnsafeServiceEnumerationRecord) {
154
160
  records.push(this._rrMetaPtr())
155
161
  }
156
162
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bonjour-hap",
3
- "version": "3.10.3-beta.0",
3
+ "version": "3.10.3-beta.2",
4
4
  "description": "A Bonjour/Zeroconf implementation in pure JavaScript (for HAP)",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",