browser.js 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. "use strict";
  2. var __importDefault = (this && this.__importDefault) || function (mod) {
  3. return (mod && mod.__esModule) ? mod : { "default": mod };
  4. };
  5. Object.defineProperty(exports, "__esModule", { value: true });
  6. exports.Browser = void 0;
  7. const events_1 = require("events");
  8. const service_types_1 = require("./service-types");
  9. const dns_txt_1 = __importDefault(require("./dns-txt"));
  10. const dnsEqual = require('dns-equal');
  11. const TLD = '.local';
  12. const WILDCARD = '_services._dns-sd._udp' + TLD;
  13. class Browser extends events_1.EventEmitter {
  14. constructor(mdns, opts, onup) {
  15. super();
  16. this.onresponse = null;
  17. this.serviceMap = {};
  18. this.wildcard = false;
  19. this._services = [];
  20. if (typeof opts === 'function')
  21. return new Browser(mdns, null, opts);
  22. this.mdns = mdns;
  23. if (opts != null && opts.txt != null) {
  24. this.txt = new dns_txt_1.default(opts.txt);
  25. }
  26. else {
  27. this.txt = new dns_txt_1.default();
  28. }
  29. if (!opts || !opts.type) {
  30. this.name = WILDCARD;
  31. this.wildcard = true;
  32. }
  33. else {
  34. this.name = (0, service_types_1.toString)({ name: opts.type, protocol: opts.protocol || 'tcp' }) + TLD;
  35. if (opts.name)
  36. this.name = opts.name + '.' + this.name;
  37. this.wildcard = false;
  38. }
  39. if (onup)
  40. this.on('up', onup);
  41. this.start();
  42. }
  43. start() {
  44. if (this.onresponse || this.name === undefined)
  45. return;
  46. var self = this;
  47. var nameMap = {};
  48. if (!this.wildcard)
  49. nameMap[this.name] = true;
  50. this.onresponse = (packet, rinfo) => {
  51. if (self.wildcard) {
  52. packet.answers.forEach((answer) => {
  53. if (answer.type !== 'PTR' || answer.name !== self.name || answer.name in nameMap)
  54. return;
  55. nameMap[answer.data] = true;
  56. self.mdns.query(answer.data, 'PTR');
  57. });
  58. }
  59. Object.keys(nameMap).forEach(function (name) {
  60. self.goodbyes(name, packet).forEach(self.removeService.bind(self));
  61. var matches = self.buildServicesFor(name, packet, self.txt, rinfo);
  62. if (matches.length === 0)
  63. return;
  64. matches.forEach((service) => {
  65. if (self.serviceMap[service.fqdn])
  66. return;
  67. self.addService(service);
  68. });
  69. });
  70. };
  71. this.mdns.on('response', this.onresponse);
  72. this.update();
  73. }
  74. stop() {
  75. if (!this.onresponse)
  76. return;
  77. this.mdns.removeListener('response', this.onresponse);
  78. this.onresponse = null;
  79. }
  80. update() {
  81. this.mdns.query(this.name, 'PTR');
  82. }
  83. get services() {
  84. return this._services;
  85. }
  86. addService(service) {
  87. this._services.push(service);
  88. this.serviceMap[service.fqdn] = true;
  89. this.emit('up', service);
  90. }
  91. removeService(fqdn) {
  92. var service, index;
  93. this._services.some(function (s, i) {
  94. if (dnsEqual(s.fqdn, fqdn)) {
  95. service = s;
  96. index = i;
  97. return true;
  98. }
  99. });
  100. if (!service || index === undefined)
  101. return;
  102. this._services.splice(index, 1);
  103. delete this.serviceMap[fqdn];
  104. this.emit('down', service);
  105. }
  106. goodbyes(name, packet) {
  107. return packet.answers.concat(packet.additionals)
  108. .filter((rr) => rr.type === 'PTR' && rr.ttl === 0 && dnsEqual(rr.name, name))
  109. .map((rr) => rr.data);
  110. }
  111. buildServicesFor(name, packet, txt, referer) {
  112. var records = packet.answers.concat(packet.additionals).filter((rr) => rr.ttl > 0);
  113. return records
  114. .filter((rr) => rr.type === 'PTR' && dnsEqual(rr.name, name))
  115. .map((ptr) => {
  116. var service = {
  117. addresses: []
  118. };
  119. records
  120. .filter((rr) => {
  121. return (rr.type === 'SRV' || rr.type === 'TXT') && dnsEqual(rr.name, ptr.data);
  122. })
  123. .forEach((rr) => {
  124. if (rr.type === 'SRV') {
  125. var parts = rr.name.split('.');
  126. var name = parts[0];
  127. var types = (0, service_types_1.toType)(parts.slice(1, -1).join('.'));
  128. service.name = name;
  129. service.fqdn = rr.name;
  130. service.host = rr.data.target;
  131. service.referer = referer;
  132. service.port = rr.data.port;
  133. service.type = types.name;
  134. service.protocol = types.protocol;
  135. service.subtypes = types.subtypes;
  136. }
  137. else if (rr.type === 'TXT') {
  138. service.rawTxt = rr.data;
  139. service.txt = this.txt.decodeAll(rr.data);
  140. }
  141. });
  142. if (!service.name)
  143. return;
  144. records
  145. .filter((rr) => (rr.type === 'A' || rr.type === 'AAAA') && dnsEqual(rr.name, service.host))
  146. .forEach((rr) => service.addresses.push(rr.data));
  147. return service;
  148. })
  149. .filter((rr) => !!rr);
  150. }
  151. }
  152. exports.Browser = Browser;
  153. exports.default = Browser;
  154. //# sourceMappingURL=browser.js.map