|
76 | 76 | * ```
|
77 | 77 | */
|
78 | 78 |
|
79 |
| -import { CustomEvent, TypedEventEmitter } from '@libp2p/interface/events' |
80 |
| -import { peerDiscovery } from '@libp2p/interface/peer-discovery' |
81 |
| -import { logger } from '@libp2p/logger' |
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') |
91 |
| - |
92 |
| -export interface MulticastDNSInit { |
93 |
| - /** |
94 |
| - * (true/false) announce our presence through mDNS, default `true` |
95 |
| - */ |
96 |
| - broadcast?: boolean |
97 |
| - |
98 |
| - /** |
99 |
| - * query interval, default 10 \* 1000 (10 seconds) |
100 |
| - */ |
101 |
| - interval?: number |
102 |
| - |
103 |
| - /** |
104 |
| - * name of the service announce , default '_p2p._udp.local\` |
105 |
| - */ |
106 |
| - serviceTag?: string |
107 |
| - /** |
108 |
| - * Peer name to announce (should not be peeer id), default random string |
109 |
| - */ |
110 |
| - peerName?: string |
111 |
| - |
112 |
| - /** |
113 |
| - * UDP port to broadcast to |
114 |
| - */ |
115 |
| - port?: number |
116 |
| - |
117 |
| - /** |
118 |
| - * UDP IP to broadcast to |
119 |
| - */ |
120 |
| - ip?: string |
121 |
| -} |
122 |
| - |
123 |
| -export interface MulticastDNSComponents { |
124 |
| - 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 |
| - }) |
255 |
| - |
256 |
| - this.mdns = undefined |
257 |
| - } |
258 |
| -} |
| 79 | +import { MulticastDNS } from './mdns.js' |
| 80 | +import type { MulticastDNSInit, MulticastDNSComponents } from './mdns.js' |
| 81 | +import type { PeerDiscovery } from '@libp2p/interface/peer-discovery' |
259 | 82 |
|
260 | 83 | export function mdns (init: MulticastDNSInit = {}): (components: MulticastDNSComponents) => PeerDiscovery {
|
261 | 84 | return (components: MulticastDNSComponents) => new MulticastDNS(components, init)
|
|
0 commit comments