@libp2p/mdns 9.0.13 → 9.0.14-0b4a2ee79

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.
package/src/mdns.ts ADDED
@@ -0,0 +1,166 @@
1
+ import { CustomEvent, EventEmitter } from '@libp2p/interface/events'
2
+ import { peerDiscovery } from '@libp2p/interface/peer-discovery'
3
+ import multicastDNS from 'multicast-dns'
4
+ import * as query from './query.js'
5
+ import { stringGen } from './utils.js'
6
+ import type { ComponentLogger, Logger } from '@libp2p/interface'
7
+ import type { PeerDiscovery, PeerDiscoveryEvents } from '@libp2p/interface/peer-discovery'
8
+ import type { PeerInfo } from '@libp2p/interface/peer-info'
9
+ import type { Startable } from '@libp2p/interface/src/startable.js'
10
+ import type { AddressManager } from '@libp2p/interface-internal/address-manager'
11
+
12
+ export interface MulticastDNSInit {
13
+ broadcast?: boolean
14
+ interval?: number
15
+ serviceTag?: string
16
+ peerName?: string
17
+ port?: number
18
+ ip?: string
19
+ }
20
+
21
+ export interface MulticastDNSComponents {
22
+ addressManager: AddressManager
23
+ logger: ComponentLogger
24
+ }
25
+
26
+ export class MulticastDNS extends EventEmitter<PeerDiscoveryEvents> implements PeerDiscovery, Startable {
27
+ public mdns?: multicastDNS.MulticastDNS
28
+
29
+ private readonly log: Logger
30
+ private readonly broadcast: boolean
31
+ private readonly interval: number
32
+ private readonly serviceTag: string
33
+ private readonly peerName: string
34
+ private readonly port: number
35
+ private readonly ip: string
36
+ private _queryInterval: ReturnType<typeof setInterval> | null
37
+ private readonly components: MulticastDNSComponents
38
+
39
+ constructor (components: MulticastDNSComponents, init: MulticastDNSInit = {}) {
40
+ super()
41
+
42
+ this.log = components.logger.forComponent('libp2p:mdns')
43
+ this.broadcast = init.broadcast !== false
44
+ this.interval = init.interval ?? (1e3 * 10)
45
+ this.serviceTag = init.serviceTag ?? '_p2p._udp.local'
46
+ this.ip = init.ip ?? '224.0.0.251'
47
+ this.peerName = init.peerName ?? stringGen(63)
48
+ // 63 is dns label limit
49
+ if (this.peerName.length >= 64) {
50
+ throw new Error('Peer name should be less than 64 chars long')
51
+ }
52
+ this.port = init.port ?? 5353
53
+ this.components = components
54
+ this._queryInterval = null
55
+ this._onMdnsQuery = this._onMdnsQuery.bind(this)
56
+ this._onMdnsResponse = this._onMdnsResponse.bind(this)
57
+ this._onMdnsWarning = this._onMdnsWarning.bind(this)
58
+ this._onMdnsError = this._onMdnsError.bind(this)
59
+ }
60
+
61
+ readonly [peerDiscovery] = this
62
+
63
+ readonly [Symbol.toStringTag] = '@libp2p/mdns'
64
+
65
+ isStarted (): boolean {
66
+ return Boolean(this.mdns)
67
+ }
68
+
69
+ /**
70
+ * Start sending queries to the LAN.
71
+ *
72
+ * @returns {void}
73
+ */
74
+ async start (): Promise<void> {
75
+ if (this.mdns != null) {
76
+ return
77
+ }
78
+
79
+ this.mdns = multicastDNS({ port: this.port, ip: this.ip })
80
+ this.mdns.on('query', this._onMdnsQuery)
81
+ this.mdns.on('response', this._onMdnsResponse)
82
+ this.mdns.on('warning', this._onMdnsWarning)
83
+ this.mdns.on('error', this._onMdnsError)
84
+
85
+ this._queryInterval = query.queryLAN(this.mdns, this.serviceTag, this.interval, {
86
+ log: this.log
87
+ })
88
+ }
89
+
90
+ _onMdnsQuery (event: multicastDNS.QueryPacket): void {
91
+ if (this.mdns == null) {
92
+ return
93
+ }
94
+
95
+ this.log.trace('received incoming mDNS query')
96
+ query.gotQuery(
97
+ event,
98
+ this.mdns,
99
+ this.peerName,
100
+ this.components.addressManager.getAddresses(),
101
+ this.serviceTag,
102
+ this.broadcast, {
103
+ log: this.log
104
+ }
105
+ )
106
+ }
107
+
108
+ _onMdnsResponse (event: multicastDNS.ResponsePacket): void {
109
+ this.log.trace('received mDNS query response')
110
+
111
+ try {
112
+ const foundPeer = query.gotResponse(event, this.peerName, this.serviceTag, {
113
+ log: this.log
114
+ })
115
+
116
+ if (foundPeer != null) {
117
+ this.log('discovered peer in mDNS query response %p', foundPeer.id)
118
+
119
+ this.dispatchEvent(new CustomEvent<PeerInfo>('peer', {
120
+ detail: foundPeer
121
+ }))
122
+ }
123
+ } catch (err) {
124
+ this.log.error('Error processing peer response', err)
125
+ }
126
+ }
127
+
128
+ _onMdnsWarning (err: Error): void {
129
+ this.log.error('mdns warning', err)
130
+ }
131
+
132
+ _onMdnsError (err: Error): void {
133
+ this.log.error('mdns error', err)
134
+ }
135
+
136
+ /**
137
+ * Stop sending queries to the LAN.
138
+ *
139
+ * @returns {Promise}
140
+ */
141
+ async stop (): Promise<void> {
142
+ if (this.mdns == null) {
143
+ return
144
+ }
145
+
146
+ this.mdns.removeListener('query', this._onMdnsQuery)
147
+ this.mdns.removeListener('response', this._onMdnsResponse)
148
+ this.mdns.removeListener('warning', this._onMdnsWarning)
149
+ this.mdns.removeListener('error', this._onMdnsError)
150
+
151
+ if (this._queryInterval != null) {
152
+ clearInterval(this._queryInterval)
153
+ this._queryInterval = null
154
+ }
155
+
156
+ await new Promise<void>((resolve) => {
157
+ if (this.mdns != null) {
158
+ this.mdns.destroy(resolve)
159
+ } else {
160
+ resolve()
161
+ }
162
+ })
163
+
164
+ this.mdns = undefined
165
+ }
166
+ }
package/src/query.ts CHANGED
@@ -1,16 +1,14 @@
1
- import { logger } from '@libp2p/logger'
2
1
  import { peerIdFromString } from '@libp2p/peer-id'
3
2
  import { isPrivate } from '@libp2p/utils/multiaddr/is-private'
4
3
  import { multiaddr, type Multiaddr, protocols } from '@multiformats/multiaddr'
4
+ import type { LoggerOptions } from '@libp2p/interface'
5
5
  import type { PeerInfo } from '@libp2p/interface/peer-info'
6
6
  import type { Answer, StringAnswer, TxtAnswer } from 'dns-packet'
7
7
  import type { MulticastDNS, QueryPacket, ResponsePacket } from 'multicast-dns'
8
8
 
9
- const log = logger('libp2p:mdns:query')
10
-
11
- export function queryLAN (mdns: MulticastDNS, serviceTag: string, interval: number): ReturnType<typeof setInterval> {
9
+ export function queryLAN (mdns: MulticastDNS, serviceTag: string, interval: number, options?: LoggerOptions): ReturnType<typeof setInterval> {
12
10
  const query = (): void => {
13
- log.trace('query', serviceTag)
11
+ options?.log.trace('query', serviceTag)
14
12
 
15
13
  mdns.query({
16
14
  questions: [{
@@ -25,7 +23,7 @@ export function queryLAN (mdns: MulticastDNS, serviceTag: string, interval: numb
25
23
  return setInterval(query, interval)
26
24
  }
27
25
 
28
- export function gotResponse (rsp: ResponsePacket, localPeerName: string, serviceTag: string): PeerInfo | undefined {
26
+ export function gotResponse (rsp: ResponsePacket, localPeerName: string, serviceTag: string, options?: LoggerOptions): PeerInfo | undefined {
29
27
  if (rsp.answers == null) {
30
28
  return
31
29
  }
@@ -70,21 +68,20 @@ export function gotResponse (rsp: ResponsePacket, localPeerName: string, service
70
68
  if (peerId == null) {
71
69
  throw new Error("Multiaddr doesn't contain PeerId")
72
70
  }
73
- log('peer found %p', peerId)
71
+ options?.log('peer found %p', peerId)
74
72
 
75
73
  return {
76
74
  id: peerIdFromString(peerId),
77
- multiaddrs: multiaddrs.map(addr => addr.decapsulateCode(protocols('p2p').code)),
78
- protocols: []
75
+ multiaddrs: multiaddrs.map(addr => addr.decapsulateCode(protocols('p2p').code))
79
76
  }
80
77
  } catch (e) {
81
- log.error('failed to parse mdns response', e)
78
+ options?.log.error('failed to parse mdns response', e)
82
79
  }
83
80
  }
84
81
 
85
- export function gotQuery (qry: QueryPacket, mdns: MulticastDNS, peerName: string, multiaddrs: Multiaddr[], serviceTag: string, broadcast: boolean): void {
82
+ export function gotQuery (qry: QueryPacket, mdns: MulticastDNS, peerName: string, multiaddrs: Multiaddr[], serviceTag: string, broadcast: boolean, options?: LoggerOptions): void {
86
83
  if (!broadcast) {
87
- log('not responding to mDNS query as broadcast mode is false')
84
+ options?.log('not responding to mDNS query as broadcast mode is false')
88
85
  return
89
86
  }
90
87
 
@@ -113,13 +110,13 @@ export function gotQuery (qry: QueryPacket, mdns: MulticastDNS, peerName: string
113
110
  // TXT record fields have a max data length of 255 bytes
114
111
  // see 6.1 - https://www.ietf.org/rfc/rfc6763.txt
115
112
  if (data.length > 255) {
116
- log('multiaddr %a is too long to use in mDNS query response', addr)
113
+ options?.log('multiaddr %a is too long to use in mDNS query response', addr)
117
114
  return
118
115
  }
119
116
 
120
117
  // spec mandates multiaddr contains peer id
121
118
  if (addr.getPeerId() == null) {
122
- log('multiaddr %a did not have a peer ID so cannot be used in mDNS query response', addr)
119
+ options?.log('multiaddr %a did not have a peer ID so cannot be used in mDNS query response', addr)
123
120
  return
124
121
  }
125
122
 
@@ -132,7 +129,7 @@ export function gotQuery (qry: QueryPacket, mdns: MulticastDNS, peerName: string
132
129
  })
133
130
  })
134
131
 
135
- log.trace('responding to query')
132
+ options?.log.trace('responding to query')
136
133
  mdns.respond(answers)
137
134
  }
138
135
  }
@@ -1,8 +0,0 @@
1
- {
2
- "MulticastDNSComponents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_mdns.MulticastDNSComponents.html",
3
- ".:MulticastDNSComponents": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_mdns.MulticastDNSComponents.html",
4
- "MulticastDNSInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_mdns.MulticastDNSInit.html",
5
- ".:MulticastDNSInit": "https://libp2p.github.io/js-libp2p/interfaces/_libp2p_mdns.MulticastDNSInit.html",
6
- "mdns": "https://libp2p.github.io/js-libp2p/functions/_libp2p_mdns.mdns.html",
7
- ".:mdns": "https://libp2p.github.io/js-libp2p/functions/_libp2p_mdns.mdns.html"
8
- }