Skip to content
This repository has been archived by the owner on Jul 21, 2023. It is now read-only.

feat: compatibility with go-libp2p-mdns - option 2 #81

Closed
wants to merge 11 commits into from
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,11 +35,11 @@
"homepage": "https://github.com/libp2p/js-libp2p-mdns",
"devDependencies": {
"aegir": "^18.0.2",
"async": "^2.6.1",
"chai": "^4.2.0",
"dirty-chai": "^2.0.1"
},
"dependencies": {
"async": "^2.6.2",
"debug": "^4.1.1",
"libp2p-tcp": "~0.13.0",
"multiaddr": "^6.0.2",
Expand Down
4 changes: 4 additions & 0 deletions src/compat/constants.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
'use strict'

exports.SERVICE_TAG = '_ipfs-discovery._udp'
exports.SERVICE_TAG_LOCAL = `${exports.SERVICE_TAG}.local`
94 changes: 94 additions & 0 deletions src/compat/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
'use strict'

const OS = require('os')
const assert = require('assert')
const MDNS = require('multicast-dns')
const TCP = require('libp2p-tcp')
const nextTick = require('async/nextTick')
const { SERVICE_TAG_LOCAL } = require('./constants')

const tcp = new TCP()

// Simply advertise ourselves every 10 seconds with a go-libp2p-mdns compatible
// MDNS response. We can't discover go-libp2p nodes but they'll discover and
// connect to us.
class GoMulticastDNS {
constructor (peerInfo, options) {
assert(peerInfo, 'missing peerInfo parameter')
this._peerInfo = peerInfo
this._peerIdStr = peerInfo.id.toB58String()
this._options = options || {}
this._onTick = this._onTick.bind(this)
}

start (callback) {
this._mdns = MDNS()
this._intervalId = setInterval(this._onTick, this._options.interval || 10000)
nextTick(() => callback())
}

_onTick () {
const multiaddrs = tcp.filter(this._peerInfo.multiaddrs.toArray())
// Only announce TCP for now
if (!multiaddrs.length) return

const answers = []
const peerServiceTagLocal = `${this._peerIdStr}.${SERVICE_TAG_LOCAL}`

answers.push({
name: SERVICE_TAG_LOCAL,
type: 'PTR',
class: 'IN',
ttl: 120,
data: peerServiceTagLocal
})

// Only announce TCP multiaddrs for now
const port = multiaddrs[0].toString().split('/')[4]

answers.push({
name: peerServiceTagLocal,
type: 'SRV',
class: 'IN',
ttl: 120,
data: {
priority: 10,
weight: 1,
port,
target: OS.hostname()
}
})

answers.push({
name: peerServiceTagLocal,
type: 'TXT',
class: 'IN',
ttl: 120,
data: [Buffer.from(this._peerIdStr)]
})

multiaddrs.forEach((ma) => {
const proto = ma.protoNames()[0]
if (proto === 'ip4' || proto === 'ip6') {
answers.push({
name: OS.hostname(),
type: proto === 'ip4' ? 'A' : 'AAAA',
class: 'IN',
ttl: 120,
data: ma.toString().split('/')[2]
})
}
})

this._mdns.respond(answers)
}

stop (callback) {
clearInterval(this._intervalId)
this._mdns.removeListener('query', this._onQuery)
this._mdns.destroy(callback)
}
}

module.exports = GoMulticastDNS
module.exports.tag = 'mdns'
27 changes: 23 additions & 4 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,12 @@
const multicastDNS = require('multicast-dns')
const EventEmitter = require('events').EventEmitter
const assert = require('assert')
const setImmediate = require('async/setImmediate')
const parallel = require('async/parallel')
const debug = require('debug')
const log = debug('libp2p:mdns')
const query = require('./query')
const GoMulticastDNS = require('./compat')

class MulticastDNS extends EventEmitter {
constructor (options) {
Expand All @@ -18,6 +21,10 @@ class MulticastDNS extends EventEmitter {
this.port = options.port || 5353
this.peerInfo = options.peerInfo
this._queryInterval = null

if (options.compat !== false) {
this._goMdns = new GoMulticastDNS(options.peerInfo)
}
}

start (callback) {
Expand All @@ -42,15 +49,27 @@ class MulticastDNS extends EventEmitter {
query.gotQuery(event, this.mdns, this.peerInfo, this.serviceTag, this.broadcast)
})

setImmediate(() => callback())
if (this._goMdns) {
this._goMdns.start(callback)
} else {
setImmediate(() => callback())
}
}

stop (callback) {
if (!this.mdns) {
callback(new Error('MulticastDNS service had not started yet'))
return callback(new Error('MulticastDNS service had not started yet'))
}

clearInterval(this._queryInterval)
this._queryInterval = null

if (this._goMdns) {
parallel([
cb => this._goMdns.stop(cb),
cb => this.mdns.destroy(cb)
], callback)
} else {
clearInterval(this._queryInterval)
this._queryInterval = null
this.mdns.destroy(callback)
this.mdns = undefined
}
Expand Down