@libp2p/mdns 0.18.0 → 1.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,81 @@
1
+ import type { PeerData } from '@libp2p/interfaces/peer-data'
2
+ import type { PeerId } from '@libp2p/interfaces/peer-id'
3
+ import { logger } from '@libp2p/logger'
4
+ import { peerIdFromString } from '@libp2p/peer-id'
5
+ import { Multiaddr } from '@multiformats/multiaddr'
6
+ import type { Answer } from 'dns-packet'
7
+ import { SERVICE_TAG_LOCAL } from './constants.js'
8
+
9
+ const log = logger('libp2p:mdns:compat:utils')
10
+
11
+ export function findPeerDataInAnswers (answers: Answer[], ourPeerId: PeerId): PeerData | undefined {
12
+ const ptrRecord = answers.find(a => a.type === 'PTR' && a.name === SERVICE_TAG_LOCAL)
13
+
14
+ // Only deal with responses for our service tag
15
+ if (ptrRecord == null) {
16
+ return
17
+ }
18
+
19
+ log.trace('got response', SERVICE_TAG_LOCAL)
20
+
21
+ const txtRecord = answers.find(a => a.type === 'TXT')
22
+ if (txtRecord == null || txtRecord.type !== 'TXT') {
23
+ log('missing TXT record in response')
24
+ return
25
+ }
26
+
27
+ let peerIdStr: string
28
+ try {
29
+ peerIdStr = txtRecord.data[0].toString()
30
+ } catch (err) {
31
+ log('failed to extract peer ID from TXT record data', txtRecord, err)
32
+ return
33
+ }
34
+
35
+ let peerId: PeerId
36
+ try {
37
+ peerId = peerIdFromString(peerIdStr)
38
+ } catch (err) {
39
+ log('failed to create peer ID from TXT record data', peerIdStr, err)
40
+ return
41
+ }
42
+
43
+ if (ourPeerId.equals(peerId)) {
44
+ log('ignoring reply to myself')
45
+ return
46
+ }
47
+
48
+ const multiaddrs: Multiaddr[] = []
49
+ const hosts: { A: Record<string, string>, AAAA: Record<string, string> } = {
50
+ A: {},
51
+ AAAA: {}
52
+ }
53
+
54
+ answers.forEach(answer => {
55
+ if (answer.type === 'A') {
56
+ hosts.A[answer.name] = answer.data
57
+ }
58
+
59
+ if (answer.type === 'AAAA') {
60
+ hosts.AAAA[answer.name] = answer.data
61
+ }
62
+ })
63
+
64
+ answers.forEach(answer => {
65
+ if (answer.type === 'SRV') {
66
+ if (hosts.A[answer.data.target] != null) {
67
+ multiaddrs.push(new Multiaddr(`/ip4/${hosts.A[answer.data.target]}/tcp/${answer.data.port}/p2p/${peerId.toString()}`))
68
+ } else if (hosts.AAAA[answer.data.target] != null) {
69
+ multiaddrs.push(new Multiaddr(`/ip6/${hosts.AAAA[answer.data.target]}/tcp/${answer.data.port}/p2p/${peerId.toString()}`))
70
+ } else {
71
+ multiaddrs.push(new Multiaddr(`/dnsaddr/${answer.data.target}/tcp/${answer.data.port}/p2p/${peerId.toString()}`))
72
+ }
73
+ }
74
+ })
75
+
76
+ return {
77
+ id: peerId,
78
+ multiaddrs,
79
+ protocols: []
80
+ }
81
+ }
package/src/index.ts CHANGED
@@ -1,30 +1,25 @@
1
1
  import multicastDNS from 'multicast-dns'
2
- import { EventEmitter } from 'events'
3
- import debug from 'debug'
2
+ import { CustomEvent, EventEmitter } from '@libp2p/interfaces'
3
+ import { logger } from '@libp2p/logger'
4
4
  import * as query from './query.js'
5
5
  import { GoMulticastDNS } from './compat/index.js'
6
- import type { PeerId } from '@libp2p/interfaces/peer-id'
7
- import type PeerDiscovery from '@libp2p/interfaces/peer-discovery'
8
- import type { Multiaddr } from '@multiformats/multiaddr'
6
+ import type { PeerDiscovery, PeerDiscoveryEvents } from '@libp2p/interfaces/peer-discovery'
9
7
  import type { PeerData } from '@libp2p/interfaces/peer-data'
8
+ import { Components, Initializable } from '@libp2p/interfaces/components'
10
9
 
11
- const log = Object.assign(debug('libp2p:mdns'), {
12
- error: debug('libp2p:mdns:error')
13
- })
10
+ const log = logger('libp2p:mdns')
14
11
 
15
12
  export interface MulticastDNSOptions {
16
- peerId: PeerId
17
13
  broadcast?: boolean
18
14
  interval?: number
19
15
  serviceTag?: string
20
16
  port?: number
21
- multiaddrs?: Multiaddr[]
22
17
  compat?: boolean
23
18
  compatQueryPeriod?: number
24
19
  compatQueryInterval?: number
25
20
  }
26
21
 
27
- export class MulticastDNS extends EventEmitter implements PeerDiscovery {
22
+ export class MulticastDNS extends EventEmitter<PeerDiscoveryEvents> implements PeerDiscovery, Initializable {
28
23
  static tag = 'mdns'
29
24
 
30
25
  public mdns?: multicastDNS.MulticastDNS
@@ -33,24 +28,17 @@ export class MulticastDNS extends EventEmitter implements PeerDiscovery {
33
28
  private readonly interval: number
34
29
  private readonly serviceTag: string
35
30
  private readonly port: number
36
- private readonly peerId: PeerId
37
- private readonly peerMultiaddrs: Multiaddr[] // TODO: update this when multiaddrs change?
38
- private _queryInterval: NodeJS.Timer | null
31
+ private _queryInterval: ReturnType<typeof setInterval> | null
39
32
  private readonly _goMdns?: GoMulticastDNS
33
+ private components: Components = new Components()
40
34
 
41
- constructor (options: MulticastDNSOptions) {
35
+ constructor (options: MulticastDNSOptions = {}) {
42
36
  super()
43
37
 
44
- if (options.peerId == null) {
45
- throw new Error('needs own PeerId to work')
46
- }
47
-
48
38
  this.broadcast = options.broadcast !== false
49
39
  this.interval = options.interval ?? (1e3 * 10)
50
40
  this.serviceTag = options.serviceTag ?? 'ipfs.local'
51
41
  this.port = options.port ?? 5353
52
- this.peerId = options.peerId
53
- this.peerMultiaddrs = options.multiaddrs ?? []
54
42
  this._queryInterval = null
55
43
  this._onPeer = this._onPeer.bind(this)
56
44
  this._onMdnsQuery = this._onMdnsQuery.bind(this)
@@ -58,15 +46,19 @@ export class MulticastDNS extends EventEmitter implements PeerDiscovery {
58
46
 
59
47
  if (options.compat !== false) {
60
48
  this._goMdns = new GoMulticastDNS({
61
- multiaddrs: this.peerMultiaddrs,
62
- peerId: options.peerId,
63
49
  queryPeriod: options.compatQueryPeriod,
64
50
  queryInterval: options.compatQueryInterval
65
51
  })
66
- this._goMdns.on('peer', this._onPeer)
52
+ this._goMdns.addEventListener('peer', this._onPeer)
67
53
  }
68
54
  }
69
55
 
56
+ init (components: Components): void {
57
+ this.components = components
58
+
59
+ this._goMdns?.init(components)
60
+ }
61
+
70
62
  isStarted () {
71
63
  return Boolean(this.mdns)
72
64
  }
@@ -97,23 +89,36 @@ export class MulticastDNS extends EventEmitter implements PeerDiscovery {
97
89
  return
98
90
  }
99
91
 
100
- query.gotQuery(event, this.mdns, this.peerId, this.peerMultiaddrs, this.serviceTag, this.broadcast)
92
+ log.trace('received incoming mDNS query')
93
+ query.gotQuery(event, this.mdns, this.components.getPeerId(), this.components.getAddressManager().getAddresses(), this.serviceTag, this.broadcast)
101
94
  }
102
95
 
103
96
  _onMdnsResponse (event: multicastDNS.ResponsePacket) {
97
+ log.trace('received mDNS query response')
98
+
104
99
  try {
105
- const foundPeer = query.gotResponse(event, this.peerId, this.serviceTag)
100
+ const foundPeer = query.gotResponse(event, this.components.getPeerId(), this.serviceTag)
106
101
 
107
102
  if (foundPeer != null) {
108
- this.emit('peer', foundPeer)
103
+ log('discovered peer in mDNS qeury response %p', foundPeer.id)
104
+
105
+ this.dispatchEvent(new CustomEvent<PeerData>('peer', {
106
+ detail: foundPeer
107
+ }))
109
108
  }
110
109
  } catch (err) {
111
- log('Error processing peer response', err)
110
+ log.error('Error processing peer response', err)
112
111
  }
113
112
  }
114
113
 
115
- _onPeer (peerData: PeerData) {
116
- (this.mdns != null) && this.emit('peer', peerData)
114
+ _onPeer (evt: CustomEvent<PeerData>) {
115
+ if (this.mdns == null) {
116
+ return
117
+ }
118
+
119
+ this.dispatchEvent(new CustomEvent<PeerData>('peer', {
120
+ detail: evt.detail
121
+ }))
117
122
  }
118
123
 
119
124
  /**
@@ -128,7 +133,7 @@ export class MulticastDNS extends EventEmitter implements PeerDiscovery {
128
133
 
129
134
  this.mdns.removeListener('query', this._onMdnsQuery)
130
135
  this.mdns.removeListener('response', this._onMdnsResponse)
131
- this._goMdns?.removeListener('peer', this._onPeer)
136
+ this._goMdns?.removeEventListener('peer', this._onPeer)
132
137
 
133
138
  if (this._queryInterval != null) {
134
139
  clearInterval(this._queryInterval)
package/src/query.ts CHANGED
@@ -1,19 +1,18 @@
1
1
  import os from 'os'
2
- import debug from 'debug'
3
- import { Multiaddr, MultiaddrObject } from '@multiformats/multiaddr'
4
- import { base58btc } from 'multiformats/bases/base58'
5
- import { PeerId } from '@libp2p/peer-id'
2
+ import { logger } from '@libp2p/logger'
3
+ import { Multiaddr, MultiaddrObject, protocols } from '@multiformats/multiaddr'
4
+ import { peerIdFromString } from '@libp2p/peer-id'
5
+ import type { PeerId } from '@libp2p/interfaces/peer-id'
6
6
  import type { PeerData } from '@libp2p/interfaces/peer-data'
7
7
  import type { MulticastDNS, ResponsePacket, QueryPacket } from 'multicast-dns'
8
8
  import type { SrvAnswer, StringAnswer, TxtAnswer, Answer } from 'dns-packet'
9
9
 
10
- const log = Object.assign(debug('libp2p:mdns'), {
11
- error: debug('libp2p:mdns:error')
12
- })
10
+ const log = logger('libp2p:mdns:query')
13
11
 
14
12
  export function queryLAN (mdns: MulticastDNS, serviceTag: string, interval: number) {
15
13
  const query = () => {
16
14
  log('query', serviceTag)
15
+
17
16
  mdns.query({
18
17
  questions: [{
19
18
  name: serviceTag,
@@ -83,14 +82,16 @@ export function gotResponse (rsp: ResponsePacket, localPeerId: PeerId, serviceTa
83
82
  }
84
83
  })
85
84
 
86
- if (localPeerId.toString(base58btc) === b58Id) {
85
+ if (localPeerId.toString() === b58Id) {
87
86
  return // replied to myself, ignore
88
87
  }
89
88
 
90
- log('peer found -', b58Id)
89
+ const id = peerIdFromString(b58Id)
90
+
91
+ log('peer found %p', id)
91
92
 
92
93
  return {
93
- id: PeerId.fromString(b58Id),
94
+ id,
94
95
  multiaddrs,
95
96
  protocols: []
96
97
  }
@@ -98,11 +99,12 @@ export function gotResponse (rsp: ResponsePacket, localPeerId: PeerId, serviceTa
98
99
 
99
100
  export function gotQuery (qry: QueryPacket, mdns: MulticastDNS, peerId: PeerId, multiaddrs: Multiaddr[], serviceTag: string, broadcast: boolean) {
100
101
  if (!broadcast) {
102
+ log('not responding to mDNS query as broadcast mode is false')
101
103
  return
102
104
  }
103
105
 
104
106
  const addresses: MultiaddrObject[] = multiaddrs.reduce<MultiaddrObject[]>((acc, addr) => {
105
- if (addr.isThinWaistAddress()) {
107
+ if (addr.decapsulateCode(protocols('p2p').code).isThinWaistAddress()) {
106
108
  acc.push(addr.toOptions())
107
109
  }
108
110
  return acc
@@ -110,6 +112,7 @@ export function gotQuery (qry: QueryPacket, mdns: MulticastDNS, peerId: PeerId,
110
112
 
111
113
  // Only announce TCP for now
112
114
  if (addresses.length === 0) {
115
+ log('no thin waist addresses present, cannot respond to query')
113
116
  return
114
117
  }
115
118
 
@@ -121,14 +124,14 @@ export function gotQuery (qry: QueryPacket, mdns: MulticastDNS, peerId: PeerId,
121
124
  type: 'PTR',
122
125
  class: 'IN',
123
126
  ttl: 120,
124
- data: peerId.toString(base58btc) + '.' + serviceTag
127
+ data: peerId.toString() + '.' + serviceTag
125
128
  })
126
129
 
127
130
  // Only announce TCP multiaddrs for now
128
131
  const port = addresses[0].port
129
132
 
130
133
  answers.push({
131
- name: peerId.toString(base58btc) + '.' + serviceTag,
134
+ name: peerId.toString() + '.' + serviceTag,
132
135
  type: 'SRV',
133
136
  class: 'IN',
134
137
  ttl: 120,
@@ -141,11 +144,11 @@ export function gotQuery (qry: QueryPacket, mdns: MulticastDNS, peerId: PeerId,
141
144
  })
142
145
 
143
146
  answers.push({
144
- name: peerId.toString(base58btc) + '.' + serviceTag,
147
+ name: peerId.toString() + '.' + serviceTag,
145
148
  type: 'TXT',
146
149
  class: 'IN',
147
150
  ttl: 120,
148
- data: peerId.toString(base58btc)
151
+ data: peerId.toString()
149
152
  })
150
153
 
151
154
  addresses.forEach((addr) => {