@libp2p/mdns 9.0.14 → 10.0.0
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/README.md +1 -1
- package/dist/index.min.js +10 -14
- package/dist/src/index.d.ts +3 -20
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -113
- package/dist/src/index.js.map +1 -1
- package/dist/src/mdns.d.ts +38 -0
- package/dist/src/mdns.d.ts.map +1 -0
- package/dist/src/mdns.js +119 -0
- package/dist/src/mdns.js.map +1 -0
- package/dist/src/query.d.ts +4 -4
- package/dist/src/query.d.ts.map +1 -1
- package/dist/src/query.js +11 -14
- package/dist/src/query.js.map +1 -1
- package/dist/src/utils.js.map +1 -1
- package/package.json +15 -11
- package/src/index.ts +4 -166
- package/src/mdns.ts +149 -0
- package/src/query.ts +12 -16
package/src/index.ts
CHANGED
|
@@ -76,185 +76,23 @@
|
|
|
76
76
|
* ```
|
|
77
77
|
*/
|
|
78
78
|
|
|
79
|
-
import {
|
|
80
|
-
import {
|
|
81
|
-
import {
|
|
82
|
-
import multicastDNS from 'multicast-dns'
|
|
83
|
-
import * as query from './query.js'
|
|
84
|
-
import { stringGen } from './utils.js'
|
|
85
|
-
import type { PeerDiscovery, PeerDiscoveryEvents } from '@libp2p/interface/peer-discovery'
|
|
86
|
-
import type { PeerInfo } from '@libp2p/interface/peer-info'
|
|
87
|
-
import type { Startable } from '@libp2p/interface/src/startable.js'
|
|
88
|
-
import type { AddressManager } from '@libp2p/interface-internal/address-manager'
|
|
89
|
-
|
|
90
|
-
const log = logger('libp2p:mdns')
|
|
79
|
+
import { MulticastDNS } from './mdns.js'
|
|
80
|
+
import type { ComponentLogger, PeerDiscovery } from '@libp2p/interface'
|
|
81
|
+
import type { AddressManager } from '@libp2p/interface-internal'
|
|
91
82
|
|
|
92
83
|
export interface MulticastDNSInit {
|
|
93
|
-
/**
|
|
94
|
-
* (true/false) announce our presence through mDNS, default `true`
|
|
95
|
-
*/
|
|
96
84
|
broadcast?: boolean
|
|
97
|
-
|
|
98
|
-
/**
|
|
99
|
-
* query interval, default 10 \* 1000 (10 seconds)
|
|
100
|
-
*/
|
|
101
85
|
interval?: number
|
|
102
|
-
|
|
103
|
-
/**
|
|
104
|
-
* name of the service announce , default '_p2p._udp.local\`
|
|
105
|
-
*/
|
|
106
86
|
serviceTag?: string
|
|
107
|
-
/**
|
|
108
|
-
* Peer name to announce (should not be peeer id), default random string
|
|
109
|
-
*/
|
|
110
87
|
peerName?: string
|
|
111
|
-
|
|
112
|
-
/**
|
|
113
|
-
* UDP port to broadcast to
|
|
114
|
-
*/
|
|
115
88
|
port?: number
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* UDP IP to broadcast to
|
|
119
|
-
*/
|
|
120
89
|
ip?: string
|
|
121
90
|
}
|
|
122
91
|
|
|
123
92
|
export interface MulticastDNSComponents {
|
|
124
93
|
addressManager: AddressManager
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
class MulticastDNS extends TypedEventEmitter<PeerDiscoveryEvents> implements PeerDiscovery, Startable {
|
|
128
|
-
public mdns?: multicastDNS.MulticastDNS
|
|
129
|
-
|
|
130
|
-
private readonly broadcast: boolean
|
|
131
|
-
private readonly interval: number
|
|
132
|
-
private readonly serviceTag: string
|
|
133
|
-
private readonly peerName: string
|
|
134
|
-
private readonly port: number
|
|
135
|
-
private readonly ip: string
|
|
136
|
-
private _queryInterval: ReturnType<typeof setInterval> | null
|
|
137
|
-
private readonly components: MulticastDNSComponents
|
|
138
|
-
|
|
139
|
-
constructor (components: MulticastDNSComponents, init: MulticastDNSInit = {}) {
|
|
140
|
-
super()
|
|
141
|
-
|
|
142
|
-
this.broadcast = init.broadcast !== false
|
|
143
|
-
this.interval = init.interval ?? (1e3 * 10)
|
|
144
|
-
this.serviceTag = init.serviceTag ?? '_p2p._udp.local'
|
|
145
|
-
this.ip = init.ip ?? '224.0.0.251'
|
|
146
|
-
this.peerName = init.peerName ?? stringGen(63)
|
|
147
|
-
// 63 is dns label limit
|
|
148
|
-
if (this.peerName.length >= 64) {
|
|
149
|
-
throw new Error('Peer name should be less than 64 chars long')
|
|
150
|
-
}
|
|
151
|
-
this.port = init.port ?? 5353
|
|
152
|
-
this.components = components
|
|
153
|
-
this._queryInterval = null
|
|
154
|
-
this._onMdnsQuery = this._onMdnsQuery.bind(this)
|
|
155
|
-
this._onMdnsResponse = this._onMdnsResponse.bind(this)
|
|
156
|
-
this._onMdnsWarning = this._onMdnsWarning.bind(this)
|
|
157
|
-
this._onMdnsError = this._onMdnsError.bind(this)
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
readonly [peerDiscovery] = this
|
|
161
|
-
|
|
162
|
-
readonly [Symbol.toStringTag] = '@libp2p/mdns'
|
|
163
|
-
|
|
164
|
-
isStarted (): boolean {
|
|
165
|
-
return Boolean(this.mdns)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Start sending queries to the LAN.
|
|
170
|
-
*
|
|
171
|
-
* @returns {void}
|
|
172
|
-
*/
|
|
173
|
-
async start (): Promise<void> {
|
|
174
|
-
if (this.mdns != null) {
|
|
175
|
-
return
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
this.mdns = multicastDNS({ port: this.port, ip: this.ip })
|
|
179
|
-
this.mdns.on('query', this._onMdnsQuery)
|
|
180
|
-
this.mdns.on('response', this._onMdnsResponse)
|
|
181
|
-
this.mdns.on('warning', this._onMdnsWarning)
|
|
182
|
-
this.mdns.on('error', this._onMdnsError)
|
|
183
|
-
|
|
184
|
-
this._queryInterval = query.queryLAN(this.mdns, this.serviceTag, this.interval)
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
_onMdnsQuery (event: multicastDNS.QueryPacket): void {
|
|
188
|
-
if (this.mdns == null) {
|
|
189
|
-
return
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
log.trace('received incoming mDNS query')
|
|
193
|
-
query.gotQuery(
|
|
194
|
-
event,
|
|
195
|
-
this.mdns,
|
|
196
|
-
this.peerName,
|
|
197
|
-
this.components.addressManager.getAddresses(),
|
|
198
|
-
this.serviceTag,
|
|
199
|
-
this.broadcast)
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
_onMdnsResponse (event: multicastDNS.ResponsePacket): void {
|
|
203
|
-
log.trace('received mDNS query response')
|
|
204
|
-
|
|
205
|
-
try {
|
|
206
|
-
const foundPeer = query.gotResponse(event, this.peerName, this.serviceTag)
|
|
207
|
-
|
|
208
|
-
if (foundPeer != null) {
|
|
209
|
-
log('discovered peer in mDNS query response %p', foundPeer.id)
|
|
210
|
-
|
|
211
|
-
this.dispatchEvent(new CustomEvent<PeerInfo>('peer', {
|
|
212
|
-
detail: foundPeer
|
|
213
|
-
}))
|
|
214
|
-
}
|
|
215
|
-
} catch (err) {
|
|
216
|
-
log.error('Error processing peer response', err)
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
_onMdnsWarning (err: Error): void {
|
|
221
|
-
log.error('mdns warning', err)
|
|
222
|
-
}
|
|
223
|
-
|
|
224
|
-
_onMdnsError (err: Error): void {
|
|
225
|
-
log.error('mdns error', err)
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/**
|
|
229
|
-
* Stop sending queries to the LAN.
|
|
230
|
-
*
|
|
231
|
-
* @returns {Promise}
|
|
232
|
-
*/
|
|
233
|
-
async stop (): Promise<void> {
|
|
234
|
-
if (this.mdns == null) {
|
|
235
|
-
return
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
this.mdns.removeListener('query', this._onMdnsQuery)
|
|
239
|
-
this.mdns.removeListener('response', this._onMdnsResponse)
|
|
240
|
-
this.mdns.removeListener('warning', this._onMdnsWarning)
|
|
241
|
-
this.mdns.removeListener('error', this._onMdnsError)
|
|
242
|
-
|
|
243
|
-
if (this._queryInterval != null) {
|
|
244
|
-
clearInterval(this._queryInterval)
|
|
245
|
-
this._queryInterval = null
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
await new Promise<void>((resolve) => {
|
|
249
|
-
if (this.mdns != null) {
|
|
250
|
-
this.mdns.destroy(resolve)
|
|
251
|
-
} else {
|
|
252
|
-
resolve()
|
|
253
|
-
}
|
|
254
|
-
})
|
|
94
|
+
logger: ComponentLogger
|
|
255
95
|
|
|
256
|
-
this.mdns = undefined
|
|
257
|
-
}
|
|
258
96
|
}
|
|
259
97
|
|
|
260
98
|
export function mdns (init: MulticastDNSInit = {}): (components: MulticastDNSComponents) => PeerDiscovery {
|
package/src/mdns.ts
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { CustomEvent, TypedEventEmitter, peerDiscoverySymbol } from '@libp2p/interface'
|
|
2
|
+
import multicastDNS from 'multicast-dns'
|
|
3
|
+
import * as query from './query.js'
|
|
4
|
+
import { stringGen } from './utils.js'
|
|
5
|
+
import type { MulticastDNSComponents, MulticastDNSInit } from './index.js'
|
|
6
|
+
import type { Logger, PeerDiscovery, PeerDiscoveryEvents, PeerInfo } from '@libp2p/interface'
|
|
7
|
+
import type { Startable } from '@libp2p/interface/src/startable.js'
|
|
8
|
+
|
|
9
|
+
export class MulticastDNS extends TypedEventEmitter<PeerDiscoveryEvents> implements PeerDiscovery, Startable {
|
|
10
|
+
public mdns?: multicastDNS.MulticastDNS
|
|
11
|
+
|
|
12
|
+
private readonly log: Logger
|
|
13
|
+
private readonly broadcast: boolean
|
|
14
|
+
private readonly interval: number
|
|
15
|
+
private readonly serviceTag: string
|
|
16
|
+
private readonly peerName: string
|
|
17
|
+
private readonly port: number
|
|
18
|
+
private readonly ip: string
|
|
19
|
+
private _queryInterval: ReturnType<typeof setInterval> | null
|
|
20
|
+
private readonly components: MulticastDNSComponents
|
|
21
|
+
|
|
22
|
+
constructor (components: MulticastDNSComponents, init: MulticastDNSInit = {}) {
|
|
23
|
+
super()
|
|
24
|
+
|
|
25
|
+
this.log = components.logger.forComponent('libp2p:mdns')
|
|
26
|
+
this.broadcast = init.broadcast !== false
|
|
27
|
+
this.interval = init.interval ?? (1e3 * 10)
|
|
28
|
+
this.serviceTag = init.serviceTag ?? '_p2p._udp.local'
|
|
29
|
+
this.ip = init.ip ?? '224.0.0.251'
|
|
30
|
+
this.peerName = init.peerName ?? stringGen(63)
|
|
31
|
+
// 63 is dns label limit
|
|
32
|
+
if (this.peerName.length >= 64) {
|
|
33
|
+
throw new Error('Peer name should be less than 64 chars long')
|
|
34
|
+
}
|
|
35
|
+
this.port = init.port ?? 5353
|
|
36
|
+
this.components = components
|
|
37
|
+
this._queryInterval = null
|
|
38
|
+
this._onMdnsQuery = this._onMdnsQuery.bind(this)
|
|
39
|
+
this._onMdnsResponse = this._onMdnsResponse.bind(this)
|
|
40
|
+
this._onMdnsWarning = this._onMdnsWarning.bind(this)
|
|
41
|
+
this._onMdnsError = this._onMdnsError.bind(this)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
readonly [peerDiscoverySymbol] = this
|
|
45
|
+
|
|
46
|
+
readonly [Symbol.toStringTag] = '@libp2p/mdns'
|
|
47
|
+
|
|
48
|
+
isStarted (): boolean {
|
|
49
|
+
return Boolean(this.mdns)
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Start sending queries to the LAN.
|
|
54
|
+
*
|
|
55
|
+
* @returns {void}
|
|
56
|
+
*/
|
|
57
|
+
async start (): Promise<void> {
|
|
58
|
+
if (this.mdns != null) {
|
|
59
|
+
return
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
this.mdns = multicastDNS({ port: this.port, ip: this.ip })
|
|
63
|
+
this.mdns.on('query', this._onMdnsQuery)
|
|
64
|
+
this.mdns.on('response', this._onMdnsResponse)
|
|
65
|
+
this.mdns.on('warning', this._onMdnsWarning)
|
|
66
|
+
this.mdns.on('error', this._onMdnsError)
|
|
67
|
+
|
|
68
|
+
this._queryInterval = query.queryLAN(this.mdns, this.serviceTag, this.interval, {
|
|
69
|
+
log: this.log
|
|
70
|
+
})
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
_onMdnsQuery (event: multicastDNS.QueryPacket): void {
|
|
74
|
+
if (this.mdns == null) {
|
|
75
|
+
return
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
this.log.trace('received incoming mDNS query')
|
|
79
|
+
query.gotQuery(
|
|
80
|
+
event,
|
|
81
|
+
this.mdns,
|
|
82
|
+
this.peerName,
|
|
83
|
+
this.components.addressManager.getAddresses(),
|
|
84
|
+
this.serviceTag,
|
|
85
|
+
this.broadcast, {
|
|
86
|
+
log: this.log
|
|
87
|
+
}
|
|
88
|
+
)
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
_onMdnsResponse (event: multicastDNS.ResponsePacket): void {
|
|
92
|
+
this.log.trace('received mDNS query response')
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
const foundPeer = query.gotResponse(event, this.peerName, this.serviceTag, {
|
|
96
|
+
log: this.log
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
if (foundPeer != null) {
|
|
100
|
+
this.log('discovered peer in mDNS query response %p', foundPeer.id)
|
|
101
|
+
|
|
102
|
+
this.dispatchEvent(new CustomEvent<PeerInfo>('peer', {
|
|
103
|
+
detail: foundPeer
|
|
104
|
+
}))
|
|
105
|
+
}
|
|
106
|
+
} catch (err) {
|
|
107
|
+
this.log.error('Error processing peer response', err)
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
_onMdnsWarning (err: Error): void {
|
|
112
|
+
this.log.error('mdns warning', err)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
_onMdnsError (err: Error): void {
|
|
116
|
+
this.log.error('mdns error', err)
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Stop sending queries to the LAN.
|
|
121
|
+
*
|
|
122
|
+
* @returns {Promise}
|
|
123
|
+
*/
|
|
124
|
+
async stop (): Promise<void> {
|
|
125
|
+
if (this.mdns == null) {
|
|
126
|
+
return
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
this.mdns.removeListener('query', this._onMdnsQuery)
|
|
130
|
+
this.mdns.removeListener('response', this._onMdnsResponse)
|
|
131
|
+
this.mdns.removeListener('warning', this._onMdnsWarning)
|
|
132
|
+
this.mdns.removeListener('error', this._onMdnsError)
|
|
133
|
+
|
|
134
|
+
if (this._queryInterval != null) {
|
|
135
|
+
clearInterval(this._queryInterval)
|
|
136
|
+
this._queryInterval = null
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
await new Promise<void>((resolve) => {
|
|
140
|
+
if (this.mdns != null) {
|
|
141
|
+
this.mdns.destroy(resolve)
|
|
142
|
+
} else {
|
|
143
|
+
resolve()
|
|
144
|
+
}
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
this.mdns = undefined
|
|
148
|
+
}
|
|
149
|
+
}
|
package/src/query.ts
CHANGED
|
@@ -1,16 +1,13 @@
|
|
|
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'
|
|
5
|
-
import type { PeerInfo } from '@libp2p/interface
|
|
4
|
+
import type { LoggerOptions, PeerInfo } from '@libp2p/interface'
|
|
6
5
|
import type { Answer, StringAnswer, TxtAnswer } from 'dns-packet'
|
|
7
6
|
import type { MulticastDNS, QueryPacket, ResponsePacket } from 'multicast-dns'
|
|
8
7
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
export function queryLAN (mdns: MulticastDNS, serviceTag: string, interval: number): ReturnType<typeof setInterval> {
|
|
8
|
+
export function queryLAN (mdns: MulticastDNS, serviceTag: string, interval: number, options?: LoggerOptions): ReturnType<typeof setInterval> {
|
|
12
9
|
const query = (): void => {
|
|
13
|
-
log.trace('query', serviceTag)
|
|
10
|
+
options?.log.trace('query', serviceTag)
|
|
14
11
|
|
|
15
12
|
mdns.query({
|
|
16
13
|
questions: [{
|
|
@@ -25,7 +22,7 @@ export function queryLAN (mdns: MulticastDNS, serviceTag: string, interval: numb
|
|
|
25
22
|
return setInterval(query, interval)
|
|
26
23
|
}
|
|
27
24
|
|
|
28
|
-
export function gotResponse (rsp: ResponsePacket, localPeerName: string, serviceTag: string): PeerInfo | undefined {
|
|
25
|
+
export function gotResponse (rsp: ResponsePacket, localPeerName: string, serviceTag: string, options?: LoggerOptions): PeerInfo | undefined {
|
|
29
26
|
if (rsp.answers == null) {
|
|
30
27
|
return
|
|
31
28
|
}
|
|
@@ -70,21 +67,20 @@ export function gotResponse (rsp: ResponsePacket, localPeerName: string, service
|
|
|
70
67
|
if (peerId == null) {
|
|
71
68
|
throw new Error("Multiaddr doesn't contain PeerId")
|
|
72
69
|
}
|
|
73
|
-
log('peer found %p', peerId)
|
|
70
|
+
options?.log('peer found %p', peerId)
|
|
74
71
|
|
|
75
72
|
return {
|
|
76
73
|
id: peerIdFromString(peerId),
|
|
77
|
-
multiaddrs: multiaddrs.map(addr => addr.decapsulateCode(protocols('p2p').code))
|
|
78
|
-
protocols: []
|
|
74
|
+
multiaddrs: multiaddrs.map(addr => addr.decapsulateCode(protocols('p2p').code))
|
|
79
75
|
}
|
|
80
76
|
} catch (e) {
|
|
81
|
-
log.error('failed to parse mdns response', e)
|
|
77
|
+
options?.log.error('failed to parse mdns response', e)
|
|
82
78
|
}
|
|
83
79
|
}
|
|
84
80
|
|
|
85
|
-
export function gotQuery (qry: QueryPacket, mdns: MulticastDNS, peerName: string, multiaddrs: Multiaddr[], serviceTag: string, broadcast: boolean): void {
|
|
81
|
+
export function gotQuery (qry: QueryPacket, mdns: MulticastDNS, peerName: string, multiaddrs: Multiaddr[], serviceTag: string, broadcast: boolean, options?: LoggerOptions): void {
|
|
86
82
|
if (!broadcast) {
|
|
87
|
-
log('not responding to mDNS query as broadcast mode is false')
|
|
83
|
+
options?.log('not responding to mDNS query as broadcast mode is false')
|
|
88
84
|
return
|
|
89
85
|
}
|
|
90
86
|
|
|
@@ -113,13 +109,13 @@ export function gotQuery (qry: QueryPacket, mdns: MulticastDNS, peerName: string
|
|
|
113
109
|
// TXT record fields have a max data length of 255 bytes
|
|
114
110
|
// see 6.1 - https://www.ietf.org/rfc/rfc6763.txt
|
|
115
111
|
if (data.length > 255) {
|
|
116
|
-
log('multiaddr %a is too long to use in mDNS query response', addr)
|
|
112
|
+
options?.log('multiaddr %a is too long to use in mDNS query response', addr)
|
|
117
113
|
return
|
|
118
114
|
}
|
|
119
115
|
|
|
120
116
|
// spec mandates multiaddr contains peer id
|
|
121
117
|
if (addr.getPeerId() == null) {
|
|
122
|
-
log('multiaddr %a did not have a peer ID so cannot be used in mDNS query response', addr)
|
|
118
|
+
options?.log('multiaddr %a did not have a peer ID so cannot be used in mDNS query response', addr)
|
|
123
119
|
return
|
|
124
120
|
}
|
|
125
121
|
|
|
@@ -132,7 +128,7 @@ export function gotQuery (qry: QueryPacket, mdns: MulticastDNS, peerName: string
|
|
|
132
128
|
})
|
|
133
129
|
})
|
|
134
130
|
|
|
135
|
-
log.trace('responding to query')
|
|
131
|
+
options?.log.trace('responding to query')
|
|
136
132
|
mdns.respond(answers)
|
|
137
133
|
}
|
|
138
134
|
}
|