Skip to content

Commit

Permalink
Add ability for browser to receiver updates to already discovered ser…
Browse files Browse the repository at this point in the history
…vices. (#19)

I was looking at adding the ability to automatically detect changes to
accessories and bridges, and needed the capability to receive TXT record
updates. The existing Browser implementation just ignores them, so this
pull request adds another event that will emit when a new message is
received for an already discovered service.

This change is 100% backwards compatible with existing implementations.
  • Loading branch information
NorthernMan54 authored Mar 24, 2024
1 parent 9e3d67b commit 07f5631
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 26 deletions.
6 changes: 5 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,10 @@ Options are the same as given in the `browser.find` function.

Emitted every time a new service is found that matches the browser.

#### `Event: update`

Emitted every time an update is received for existing service is found that matches the browser.

#### `Event: down`

Emitted every time an existing service emmits a goodbye message.
Expand All @@ -136,7 +140,7 @@ Broadcast the query again.

#### `Event: up`

Emitted when the service is up.
Emitted when the service is up, and if the txt record of the service is updated `service.updateTxt(object)`.

#### `Event: error`

Expand Down
22 changes: 20 additions & 2 deletions lib/Browser.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,11 @@ Browser.prototype.start = function () {
if (matches.length === 0) return

matches.forEach(function (service) {
if (self._serviceMap[service.fqdn]) return // ignore already registered services
self._addService(service)
if (self._serviceMap[service.fqdn]) {
self._updateService(service)
} else {
self._addService(service)
}
})
})
}
Expand All @@ -109,6 +112,21 @@ Browser.prototype._addService = function (service) {
this.emit('up', service)
}

Browser.prototype._updateService = function (service) {
let cachedService, index
this.services.some(function (s, i) {
if (dnsEqual(s.fqdn, service.fqdn)) {
cachedService = s
index = i
return true
}
return false
})
if (!cachedService) return
this.services[index] = service
this.emit('update', service)
}

Browser.prototype._removeService = function (fqdn) {
let service, index
this.services.some(function (s, i) {
Expand Down
72 changes: 49 additions & 23 deletions test/bonjour.js
Original file line number Diff line number Diff line change
Expand Up @@ -118,32 +118,58 @@ test('bonjour.find', function (bonjour, t) {
bonjour.publish({ name: 'Baz', type: 'test', port: 3000, txt: { foo: 'bar' } }).on('up', next())
})

test('bonjour.change', function (bonjour, t) {
const data = { init: true, found: false, timer: null }
const service = bonjour.publish({ name: 'Baz', type: 'test', port: 3000, txt: { foo: 'bar' } }).on('up', function () {
const browser = bonjour.find({ type: 'test' })
browser.on('up', function (s) {
data.browserData = s
test('bonjour.change and up event', function (bonjour, t) {
const data = { updateTxtSent: false, found: false, timer: null, serviceUp: false }
data.timer = setTimeout(function () {
t.equal(data.found, true)
bonjour.destroy()
t.end()
}, 3000) // Wait 3000 ms for any additional up messages when the updateTxt is sent
const service = bonjour.publish({ name: 'Baz', type: 'test', port: 3000, txt: { foo: 'originalUp' } }).on('up', function () {
if (!data.serviceUp) { // Workaround for Service.up firing when service.updateTxt is used
data.serviceUp = true
const browser = bonjour.find({ type: 'test' })
browser.on('up', function (s) {
t.equal(s.txt.foo, 'originalUp')
data.found = true
if (!data.updateTxtSent) {
data.updateTxtSent = true
service.updateTxt({ foo: 'updateUp' })
}
})
}
})
})

test('bonjour.change and update event', function (bonjour, t) {
const data = { updateTxtSent: false, success: false, timer: null, serviceUp: false }
data.timer = setTimeout(function () {
t.equal(data.success, true)
bonjour.destroy()
t.end()
}, 3000) // Wait for the record to update maximum 3000 ms
const service = bonjour.publish({ name: 'Baz', type: 'test', port: 3000, txt: { foo: 'original' } }).on('up', function () {
if (!data.serviceUp) { // Workaround for Service.up firing when service.updateTxt is used
data.serviceUp = true
const browser = bonjour.find({ type: 'test' })
browser.on('up', function (s) {
t.equal(s.txt.foo, 'original')
if (!data.updateTxtSent) {
data.updateTxtSent = true
service.updateTxt({ foo: 'update' })
}
})

if (data.init) {
t.equal(s.txt.foo, 'bar')
data.timer = setTimeout(function () {
t.equal(s.txt.foo, 'baz')
browser.on('update', function (s) {
if (s.txt.foo === 'update') { // Ignore updates that we are not interested in, have seen updates of just address information
t.equal(s.txt.foo, 'update')
data.success = true
clearTimeout(data.timer)
bonjour.destroy()
t.end()
}, 3000) // Wait for the record to update maximum 3000 ms
data.init = false
service.updateTxt({ foo: 'baz' })
}

if (!data.init && !data.found && s.txt.foo === 'baz') {
data.found = true
clearTimeout(data.timer)
t.equal(s.txt.foo, 'baz')
bonjour.destroy()
t.end()
}
})
}
})
}
})
})

Expand Down

0 comments on commit 07f5631

Please sign in to comment.