@collight/dns-sd
Version:
A DNS Service Discovery implementation in modern TypeScript
3 lines (2 loc) • 2.56 kB
JavaScript
import{debug as l}from"../utils/debug.js";import{nameEquals as m}from"../utils/dns-utils.js";import"events";import"fast-deep-equal";import"multicast-dns";import{Service as c}from"./Service.js";const n=class n{constructor(e){this.startedServices=[],this.server=e}makeService(e){const t=new c(e);return t.registry=this,t}async publish(e){const t=this.makeService(e);return await t.start(),t}async unpublishAll(){await this.goodbye(this.startedServices).finally(()=>{this.startedServices=[]})}destroy(){for(const e of this.startedServices)e.destroyed=!0}async onServiceStart(e){if(this.startedServices.push(e),e.probe){if(e.probeAutoResolve){const t=e.name,r=e.fqdn.substring(t.length);let s=1;for(;s<=n.MAX_PROBE_AUTO_RESOLVE_ATTEMPTS&&await this.probe(e);)s++,e.name=`${t} (${s})`,e.fqdn=e.name+r;if(s>n.MAX_PROBE_AUTO_RESOLVE_ATTEMPTS){console.error(new Error(`Failed to resolve name conflicts after ${n.MAX_PROBE_AUTO_RESOLVE_ATTEMPTS} attempts.`)),e.stop();return}}else if(await this.probe(e)){e.stop(),console.error(new Error("Service name is already in use on the network"));return}}return this.announce(e),new Promise(t=>{e.on("up",t)})}async onServiceStop(e){await this.goodbye([e]).finally(()=>{const t=this.startedServices.indexOf(e);t!==-1&&this.startedServices.splice(t,1)})}async probe(e){let t=!1,r=0,s;return new Promise(o=>{const a=()=>{!e.started||e.destroyed||this.server.mdns.query(e.fqdn,"ANY",i=>{i&&console.warn("Error during probing:",i),t=!0,++r,s=setTimeout(r<3?a:d,250).unref()})},d=(i=!1)=>{this.server.mdns.off("response",f),clearTimeout(s),o(i)},f=i=>{t&&(i.answers.some(u=>m(u.name,e.fqdn))||i.additionals.some(u=>m(u.name,e.fqdn)))&&d(!0)};this.server.mdns.on("response",f),setTimeout(a,Math.random()*250)})}announce(e){const t=e.getRecords();this.server.register(t);let r=1e3;const s=()=>{!e.started||e.destroyed||(l("mdns broadcast:",t),this.server.mdns.respond(t,o=>{o&&console.warn("Error during announcement:",o),e.published||(e.published=!0,e.emit("up")),r=r*n.REANNOUNCE_FACTOR,r<n.REANNOUNCE_MAX_MS&&!e.destroyed&&setTimeout(s,r).unref()}))};s()}async goodbye(e){const t=e.filter(s=>s.published);if(t.length===0)return;const r=t.flatMap(s=>s.getRecords().map(o=>({...o,ttl:0})));if(r.length!==0)return this.server.unregister(r),new Promise((s,o)=>{l("mdns goodbye:",r),this.server.mdns.respond(r,a=>{for(const d of t)d.published=!1,d.emit("down");a?o(a):s()})})}};n.MAX_PROBE_AUTO_RESOLVE_ATTEMPTS=10,n.REANNOUNCE_MAX_MS=3600*1e3,n.REANNOUNCE_FACTOR=3;let h=n;export{h as Registry};
//# sourceMappingURL=Registry.js.map