homebridge-gsh-kazari
Version:
114 lines (88 loc) • 3.21 kB
JavaScript
'use strict'
const flatten = require('array-flatten')
const Service = require('./Service.js')
const Prober = require('./Prober.js')
const Registry = function (server) {
this._server = server
this._services = []
}
Registry.prototype = {
publish: function (opts) {
opts = opts || {}
const service = new Service(opts)
service.on('service-publish', this._onServicePublish.bind(this))
service.on('service-unpublish', this._onServiceUnpublish.bind(this))
service.on('service-announce-request', this._onAnnounceRequest.bind(this))
service.on('service-packet-change', this._onServiceChange.bind(this))
service.start()
return service
},
unpublishAll: function (cb) {
this._tearDown(this._services, cb)
this._services = []
},
destroy: function () {
for (let i = 0; i < this._services.length; i++) { this._services[i].destroy() }
},
/**
* Stop the given services
*
* Besides removing a service from the mDNS registry, a "goodbye"
* message is sent for each service to let the network know about the
* shutdown.
*/
_tearDown: function (services, cb) {
if (!Array.isArray(services)) { services = [services] }
services = services.filter(function (service) {
return service._activated // ignore services not currently starting or started
})
const records = flatten.depth(services.map(function (service) {
service.deactivate()
const records = service._records(true)
records.forEach(function (record) {
record.ttl = 0 // prepare goodbye message
})
return records
}), 1)
if (records.length === 0) { return cb && cb() }
this._server.unregister(records)
this._server.mdns.respond(records, this._onTearDownComplete.bind(this, services, cb))
},
_onTearDownComplete: function (services, cb) {
for (let i = 0; i < services.length; i++) { services[i].published = false }
if (cb) { cb.apply(null, Array.prototype.slice.call(arguments, 2)) }
},
_onServiceChange: function (oldPackets) {
this._server.unregister(oldPackets)
},
/**
* Initial service announcement
*
* Used to announce new services when they are first registered.
*
* Broadcasts right away, then after 3 seconds, 9 seconds, 27 seconds,
* and so on, up to a maximum interval of one hour.
*/
_onAnnounceRequest: function (packet, silent, cb) {
this._server.register(packet)
if (!silent) {
this._server.mdns.respond(packet, cb)
}
},
_onServiceUnpublish: function (service, cb) {
const index = this._services.indexOf(service)
this._tearDown(service, cb)
if (index !== -1) { this._services.splice(index, 1) }
},
_onServicePublish: function (service) {
this._services.push(service)
if (service.probe) { (new Prober(this._server.mdns, service, this._onProbeComplete.bind(this, service))).start() } else { service.announce() }
},
_onProbeComplete: function (service, exists) {
if (!exists) { return service.announce() }
// Handle error
service.stop()
service.emit('error', new Error('Service name is already in use on the network'))
}
}
module.exports = Registry