lib/advertise/mdns.js

const _ = require('lodash')
const { join } = require('path')
const mdns = require('mdns-js')
const { EventEmitter2 } = require('eventemitter2')

/**
 * Creates an instance of mDNS advertiser.
 * @constructor
 * @param {Object} options options object
 * @param {String} options.name Service name
 * @param {String} [options.type=https] Service type {@link http://www.dns-sd.org/serviceTypes.html|See mDNS Service Types}
 * @param {String} [options.protocol=tcp] Service protocol
 * @param {String} [options.nameSuffix] Service name suffix
 * @param {Array}  [options.subtypes] Service subtypes
 * @param {Number} [object.port=443] Service port
 * @param {Object} [object.txt] TXT record(s) of the service
 * @fires AdvertiseMdns#stop
 * @fires AdvertiseMdns#start
 * @fires AdvertiseMdns#error
 * @see {@link https://github.com/mdns-js/node-mdns-js/|mdns-js}
 */
class AdvertiseMdns extends EventEmitter2 {
  constructor (opts = {}) {
    super({
      wildcard: true
    })
    opts = _.defaultsDeep(opts, {
      type: 'https',
      protocol: 'tcp',
      subtypes: [],
      port: 443,
      txt: {},
      logger: false
    })
    /**
     * @prop {logger} logger the logger of this instance
     */
    if (_.isBoolean(opts.logger)) {
      opts.logger = new (require(join(__dirname, '..', 'logger')))({
        level: opts.logger === true ? 'debug' : 'fatal',
        pretty: opts.logger
      })
    }
    this.logger = opts.logger
    if (!opts.name) {
      let err = new Error('You must set a name property')
      return this.logger.error({
        err
      })
    }
    /**
     * @prop {Number} state State of the advertiser
     */
    this.state = 0
    /**
     * @prop {Object} options Advertiser options
     * @prop {Number} options.name Service name
     * @prop {String} options.protocol Service protocol
     * @prop {String} options.type Service type
     * @prop {Array}  options.subtypes Service subtypes
     * @prop {Number} options.port Service port
     * @prop {Object} advertiser mDNS advertiser
    */
    this.options = opts
    this.logger.debug({ name: 'options', options: this.options })
    /**
     * @see {@link https://github.com/mdns-js/node-mdns-js/|mdns-js}
     */
    this.advertiser = mdns.createAdvertisement(
      mdns[opts.protocol](`_${this.options.type}`),
      this.options.port,
      _.pick(this.options, [
        'name',
        'txt',
        'nameSuffix',
        'subtypes'
      ])
    )
    return this
  }

  get status () {
    return this.advertiser.status
  }

  start () {
    this.logger.debug({ name: 'advertise.mdns', msg: 'start' })
    if (this.advertiser) {
      /**
       * service search started
       * @event Mdns#start
       * @type {Object}
       */
      this.emit('start', this.options)
      this.advertiser.start()
    }
    return this
  }

  stop () {
    this.logger.debug({ name: 'advertise.mdns', msg: 'stop' })
    if (this.advertiser) {
      /**
       * service search finished
       * @event Mdns#stop
       * @type {Object}
       */
      this.emit('stop', this.advertiser)
      this.advertiser.stop()
    }
    return this
  }
}

module.exports = AdvertiseMdns