@libp2p/kad-dht 9.1.5 → 9.3.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.
Files changed (46) hide show
  1. package/dist/index.min.js +18 -18
  2. package/dist/src/content-fetching/index.js +4 -4
  3. package/dist/src/content-fetching/index.js.map +1 -1
  4. package/dist/src/content-routing/index.d.ts +1 -2
  5. package/dist/src/content-routing/index.d.ts.map +1 -1
  6. package/dist/src/content-routing/index.js +8 -5
  7. package/dist/src/content-routing/index.js.map +1 -1
  8. package/dist/src/dual-kad-dht.d.ts +1 -2
  9. package/dist/src/dual-kad-dht.d.ts.map +1 -1
  10. package/dist/src/dual-kad-dht.js +58 -7
  11. package/dist/src/dual-kad-dht.js.map +1 -1
  12. package/dist/src/index.d.ts +19 -14
  13. package/dist/src/index.d.ts.map +1 -1
  14. package/dist/src/index.js +3 -3
  15. package/dist/src/index.js.map +1 -1
  16. package/dist/src/network.d.ts +3 -3
  17. package/dist/src/network.d.ts.map +1 -1
  18. package/dist/src/network.js +9 -9
  19. package/dist/src/network.js.map +1 -1
  20. package/dist/src/peer-routing/index.d.ts +3 -3
  21. package/dist/src/peer-routing/index.d.ts.map +1 -1
  22. package/dist/src/peer-routing/index.js +14 -8
  23. package/dist/src/peer-routing/index.js.map +1 -1
  24. package/dist/src/query/events.d.ts +10 -10
  25. package/dist/src/query/events.d.ts.map +1 -1
  26. package/dist/src/query/events.js +36 -19
  27. package/dist/src/query/events.js.map +1 -1
  28. package/dist/src/query/manager.d.ts +2 -3
  29. package/dist/src/query/manager.d.ts.map +1 -1
  30. package/dist/src/query/manager.js +2 -1
  31. package/dist/src/query/manager.js.map +1 -1
  32. package/dist/src/query/query-path.d.ts +2 -2
  33. package/dist/src/query/query-path.d.ts.map +1 -1
  34. package/dist/src/query/query-path.js +1 -1
  35. package/dist/src/query/query-path.js.map +1 -1
  36. package/dist/typedoc-urls.json +4 -3
  37. package/package.json +2 -1
  38. package/src/content-fetching/index.ts +4 -4
  39. package/src/content-routing/index.ts +9 -7
  40. package/src/dual-kad-dht.ts +77 -14
  41. package/src/index.ts +28 -14
  42. package/src/network.ts +13 -13
  43. package/src/peer-routing/index.ts +17 -11
  44. package/src/query/events.ts +54 -21
  45. package/src/query/manager.ts +4 -4
  46. package/src/query/query-path.ts +3 -3
@@ -6,12 +6,13 @@ import { EventEmitter, CustomEvent } from '@libp2p/interfaces/events'
6
6
  import { logger } from '@libp2p/logger'
7
7
  import drain from 'it-drain'
8
8
  import merge from 'it-merge'
9
+ import isPrivate from 'private-ip'
9
10
  import { DefaultKadDHT } from './kad-dht.js'
10
11
  import { queryErrorEvent } from './query/events.js'
11
12
  import type { DualKadDHT, KadDHT, KadDHTComponents, KadDHTInit, QueryEvent, QueryOptions } from './index.js'
12
13
  import type { PeerId } from '@libp2p/interface-peer-id'
13
14
  import type { PeerInfo } from '@libp2p/interface-peer-info'
14
- import type { AbortOptions } from '@libp2p/interfaces'
15
+ import type { Multiaddr } from '@multiformats/multiaddr'
15
16
  import type { CID } from 'multiformats/cid'
16
17
 
17
18
  const log = logger('libp2p:kad-dht')
@@ -26,11 +27,11 @@ class DHTContentRouting implements ContentRouting {
26
27
  this.dht = dht
27
28
  }
28
29
 
29
- async provide (cid: CID): Promise<void> {
30
- await drain(this.dht.provide(cid))
30
+ async provide (cid: CID, options: QueryOptions = {}): Promise<void> {
31
+ await drain(this.dht.provide(cid, options))
31
32
  }
32
33
 
33
- async * findProviders (cid: CID, options: AbortOptions = {}): AsyncGenerator<PeerInfo, void, undefined> {
34
+ async * findProviders (cid: CID, options: QueryOptions = {}): AsyncGenerator<PeerInfo, void, undefined> {
34
35
  for await (const event of this.dht.findProviders(cid, options)) {
35
36
  if (event.name === 'PROVIDER') {
36
37
  yield * event.providers
@@ -38,11 +39,11 @@ class DHTContentRouting implements ContentRouting {
38
39
  }
39
40
  }
40
41
 
41
- async put (key: Uint8Array, value: Uint8Array, options?: AbortOptions): Promise<void> {
42
+ async put (key: Uint8Array, value: Uint8Array, options?: QueryOptions): Promise<void> {
42
43
  await drain(this.dht.put(key, value, options))
43
44
  }
44
45
 
45
- async get (key: Uint8Array, options?: AbortOptions): Promise<Uint8Array> {
46
+ async get (key: Uint8Array, options?: QueryOptions): Promise<Uint8Array> {
46
47
  for await (const event of this.dht.get(key, options)) {
47
48
  if (event.name === 'VALUE') {
48
49
  return event.value
@@ -63,7 +64,7 @@ class DHTPeerRouting implements PeerRouting {
63
64
  this.dht = dht
64
65
  }
65
66
 
66
- async findPeer (peerId: PeerId, options: AbortOptions = {}): Promise<PeerInfo> {
67
+ async findPeer (peerId: PeerId, options: QueryOptions = {}): Promise<PeerInfo> {
67
68
  for await (const event of this.dht.findPeer(peerId, options)) {
68
69
  if (event.name === 'FINAL_PEER') {
69
70
  return event.peer
@@ -73,7 +74,7 @@ class DHTPeerRouting implements PeerRouting {
73
74
  throw new CodeError('Not found', 'ERR_NOT_FOUND')
74
75
  }
75
76
 
76
- async * getClosestPeers (key: Uint8Array, options: AbortOptions = {}): AsyncIterable<PeerInfo> {
77
+ async * getClosestPeers (key: Uint8Array, options: QueryOptions = {}): AsyncIterable<PeerInfo> {
77
78
  for await (const event of this.dht.getClosestPeers(key, options)) {
78
79
  if (event.name === 'FINAL_PEER') {
79
80
  yield event.peer
@@ -82,6 +83,44 @@ class DHTPeerRouting implements PeerRouting {
82
83
  }
83
84
  }
84
85
 
86
+ // see https://github.com/multiformats/multiaddr/blob/master/protocols.csv
87
+ const P2P_CIRCUIT_CODE = 290
88
+ const DNS4_CODE = 54
89
+ const DNS6_CODE = 55
90
+ const DNSADDR_CODE = 56
91
+ const IP4_CODE = 4
92
+ const IP6_CODE = 41
93
+
94
+ function multiaddrIsPublic (multiaddr: Multiaddr): boolean {
95
+ const tuples = multiaddr.stringTuples()
96
+
97
+ // p2p-circuit should not enable server mode
98
+ for (const tuple of tuples) {
99
+ if (tuple[0] === P2P_CIRCUIT_CODE) {
100
+ return false
101
+ }
102
+ }
103
+
104
+ // dns4 or dns6 or dnsaddr
105
+ if (tuples[0][0] === DNS4_CODE || tuples[0][0] === DNS6_CODE || tuples[0][0] === DNSADDR_CODE) {
106
+ log('%m is public %s', multiaddr, true)
107
+
108
+ return true
109
+ }
110
+
111
+ // ip4 or ip6
112
+ if (tuples[0][0] === IP4_CODE || tuples[0][0] === IP6_CODE) {
113
+ const result = isPrivate(`${tuples[0][1]}`)
114
+ const isPublic = result == null || !result
115
+
116
+ log('%m is public %s', multiaddr, isPublic)
117
+
118
+ return isPublic
119
+ }
120
+
121
+ return false
122
+ }
123
+
85
124
  /**
86
125
  * A DHT implementation modelled after Kademlia with S/Kademlia modifications.
87
126
  * Original implementation in go: https://github.com/libp2p/go-libp2p-kad-dht.
@@ -124,6 +163,30 @@ export class DefaultDualKadDHT extends EventEmitter<PeerDiscoveryEvents> impleme
124
163
  detail: evt.detail
125
164
  }))
126
165
  })
166
+
167
+ components.events.addEventListener('self:peer:update', (evt) => {
168
+ log('received update of self-peer info')
169
+ const hasPublicAddress = evt.detail.peer.addresses
170
+ .some(({ multiaddr }) => {
171
+ const isPublic = multiaddrIsPublic(multiaddr)
172
+
173
+ log('%m is public %s', multiaddr, isPublic)
174
+
175
+ return isPublic
176
+ })
177
+
178
+ this.getMode()
179
+ .then(async mode => {
180
+ if (hasPublicAddress && mode === 'client') {
181
+ await this.setMode('server')
182
+ } else if (mode === 'server' && !hasPublicAddress) {
183
+ await this.setMode('client')
184
+ }
185
+ })
186
+ .catch(err => {
187
+ log.error('error setting dht server mode', err)
188
+ })
189
+ })
127
190
  }
128
191
 
129
192
  readonly [Symbol.toStringTag] = '@libp2p/dual-kad-dht'
@@ -207,7 +270,7 @@ export class DefaultDualKadDHT extends EventEmitter<PeerDiscoveryEvents> impleme
207
270
  )) {
208
271
  yield event
209
272
 
210
- if (event.name === 'DIALING_PEER') {
273
+ if (event.name === 'DIAL_PEER') {
211
274
  queriedPeers = true
212
275
  }
213
276
 
@@ -219,7 +282,7 @@ export class DefaultDualKadDHT extends EventEmitter<PeerDiscoveryEvents> impleme
219
282
  }
220
283
  }
221
284
 
222
- if (event.name === 'SENDING_QUERY') {
285
+ if (event.name === 'SEND_QUERY') {
223
286
  queriedPeers = true
224
287
  }
225
288
  }
@@ -232,7 +295,7 @@ export class DefaultDualKadDHT extends EventEmitter<PeerDiscoveryEvents> impleme
232
295
  yield queryErrorEvent({
233
296
  from: this.components.peerId,
234
297
  error: new CodeError('Not found', 'ERR_NOT_FOUND')
235
- })
298
+ }, options)
236
299
  }
237
300
  }
238
301
 
@@ -241,7 +304,7 @@ export class DefaultDualKadDHT extends EventEmitter<PeerDiscoveryEvents> impleme
241
304
  /**
242
305
  * Announce to the network that we can provide given key's value
243
306
  */
244
- async * provide (key: CID, options: AbortOptions = {}): AsyncGenerator<QueryEvent> {
307
+ async * provide (key: CID, options: QueryOptions = {}): AsyncGenerator<QueryEvent> {
245
308
  let sent = 0
246
309
  let success = 0
247
310
  const errors = []
@@ -256,7 +319,7 @@ export class DefaultDualKadDHT extends EventEmitter<PeerDiscoveryEvents> impleme
256
319
  for await (const event of merge(...dhts.map(dht => dht.provide(key, options)))) {
257
320
  yield event
258
321
 
259
- if (event.name === 'SENDING_QUERY') {
322
+ if (event.name === 'SEND_QUERY') {
260
323
  sent++
261
324
  }
262
325
 
@@ -304,7 +367,7 @@ export class DefaultDualKadDHT extends EventEmitter<PeerDiscoveryEvents> impleme
304
367
  )) {
305
368
  yield event
306
369
 
307
- if (event.name === 'SENDING_QUERY' || event.name === 'FINAL_PEER') {
370
+ if (event.name === 'SEND_QUERY' || event.name === 'FINAL_PEER') {
308
371
  queriedPeers = true
309
372
  }
310
373
  }
package/src/index.ts CHANGED
@@ -2,27 +2,30 @@ import { DefaultDualKadDHT } from './dual-kad-dht.js'
2
2
  import type { ProvidersInit } from './providers.js'
3
3
  import type { AddressManager } from '@libp2p/interface-address-manager'
4
4
  import type { ConnectionManager } from '@libp2p/interface-connection-manager'
5
+ import type { Libp2pEvents } from '@libp2p/interface-libp2p'
5
6
  import type { Metrics } from '@libp2p/interface-metrics'
6
7
  import type { PeerId } from '@libp2p/interface-peer-id'
7
8
  import type { PeerInfo } from '@libp2p/interface-peer-info'
8
9
  import type { PeerStore } from '@libp2p/interface-peer-store'
9
10
  import type { Registrar } from '@libp2p/interface-registrar'
10
11
  import type { AbortOptions } from '@libp2p/interfaces'
12
+ import type { EventEmitter } from '@libp2p/interfaces/events'
11
13
  import type { Datastore } from 'interface-datastore'
12
14
  import type { CID } from 'multiformats/cid'
15
+ import type { ProgressOptions, ProgressEvent } from 'progress-events'
13
16
 
14
17
  /**
15
18
  * The types of events emitted during DHT queries
16
19
  */
17
20
  export enum EventTypes {
18
- SENDING_QUERY = 0,
21
+ SEND_QUERY = 0,
19
22
  PEER_RESPONSE,
20
23
  FINAL_PEER,
21
24
  QUERY_ERROR,
22
25
  PROVIDER,
23
26
  VALUE,
24
- ADDING_PEER,
25
- DIALING_PEER
27
+ ADD_PEER,
28
+ DIAL_PEER
26
29
  }
27
30
 
28
31
  /**
@@ -45,17 +48,27 @@ export interface DHTRecord {
45
48
  timeReceived?: Date
46
49
  }
47
50
 
48
- export interface QueryOptions extends AbortOptions {
51
+ export type DHTProgressEvents =
52
+ ProgressEvent<'kad-dht:query:send-query', SendQueryEvent> |
53
+ ProgressEvent<'kad-dht:query:peer-response', PeerResponseEvent> |
54
+ ProgressEvent<'kad-dht:query:final-peer', FinalPeerEvent> |
55
+ ProgressEvent<'kad-dht:query:query-error', QueryErrorEvent> |
56
+ ProgressEvent<'kad-dht:query:provider', ProviderEvent> |
57
+ ProgressEvent<'kad-dht:query:value', ValueEvent> |
58
+ ProgressEvent<'kad-dht:query:add-peer', AddPeerEvent> |
59
+ ProgressEvent<'kad-dht:query:dial-peer', DialPeerEvent>
60
+
61
+ export interface QueryOptions extends AbortOptions, ProgressOptions {
49
62
  queryFuncTimeout?: number
50
63
  }
51
64
 
52
65
  /**
53
66
  * Emitted when sending queries to remote peers
54
67
  */
55
- export interface SendingQueryEvent {
68
+ export interface SendQueryEvent {
56
69
  to: PeerId
57
- type: EventTypes.SENDING_QUERY
58
- name: 'SENDING_QUERY'
70
+ type: EventTypes.SEND_QUERY
71
+ name: 'SEND_QUERY'
59
72
  messageName: keyof typeof MessageType
60
73
  messageType: MessageType
61
74
  }
@@ -118,22 +131,22 @@ export interface ValueEvent {
118
131
  /**
119
132
  * Emitted when peers are added to a query
120
133
  */
121
- export interface AddingPeerEvent {
122
- type: EventTypes.ADDING_PEER
123
- name: 'ADDING_PEER'
134
+ export interface AddPeerEvent {
135
+ type: EventTypes.ADD_PEER
136
+ name: 'ADD_PEER'
124
137
  peer: PeerId
125
138
  }
126
139
 
127
140
  /**
128
141
  * Emitted when peers are dialled as part of a query
129
142
  */
130
- export interface DialingPeerEvent {
143
+ export interface DialPeerEvent {
131
144
  peer: PeerId
132
- type: EventTypes.DIALING_PEER
133
- name: 'DIALING_PEER'
145
+ type: EventTypes.DIAL_PEER
146
+ name: 'DIAL_PEER'
134
147
  }
135
148
 
136
- export type QueryEvent = SendingQueryEvent | PeerResponseEvent | FinalPeerEvent | QueryErrorEvent | ProviderEvent | ValueEvent | AddingPeerEvent | DialingPeerEvent
149
+ export type QueryEvent = SendQueryEvent | PeerResponseEvent | FinalPeerEvent | QueryErrorEvent | ProviderEvent | ValueEvent | AddPeerEvent | DialPeerEvent
137
150
 
138
151
  export interface RoutingTable {
139
152
  size: number
@@ -300,6 +313,7 @@ export interface KadDHTComponents {
300
313
  metrics?: Metrics
301
314
  connectionManager: ConnectionManager
302
315
  datastore: Datastore
316
+ events: EventEmitter<Libp2pEvents>
303
317
  }
304
318
 
305
319
  export function kadDHT (init?: KadDHTInit): (components: KadDHTComponents) => DualKadDHT {
package/src/network.ts CHANGED
@@ -8,12 +8,12 @@ import * as lp from 'it-length-prefixed'
8
8
  import { pipe } from 'it-pipe'
9
9
  import { Message } from './message/index.js'
10
10
  import {
11
- dialingPeerEvent,
12
- sendingQueryEvent,
11
+ dialPeerEvent,
12
+ sendQueryEvent,
13
13
  peerResponseEvent,
14
14
  queryErrorEvent
15
15
  } from './query/events.js'
16
- import type { KadDHTComponents, QueryEvent } from './index.js'
16
+ import type { KadDHTComponents, QueryEvent, QueryOptions } from './index.js'
17
17
  import type { Stream } from '@libp2p/interface-connection'
18
18
  import type { PeerId } from '@libp2p/interface-peer-id'
19
19
  import type { PeerInfo } from '@libp2p/interface-peer-info'
@@ -82,14 +82,14 @@ export class Network extends EventEmitter<NetworkEvents> implements Startable {
82
82
  /**
83
83
  * Send a request and record RTT for latency measurements
84
84
  */
85
- async * sendRequest (to: PeerId, msg: Message, options: AbortOptions = {}): AsyncGenerator<QueryEvent> {
85
+ async * sendRequest (to: PeerId, msg: Message, options: QueryOptions = {}): AsyncGenerator<QueryEvent> {
86
86
  if (!this.running) {
87
87
  return
88
88
  }
89
89
 
90
90
  this.log('sending %s to %p', msg.type, to)
91
- yield dialingPeerEvent({ peer: to })
92
- yield sendingQueryEvent({ to, type: msg.type })
91
+ yield dialPeerEvent({ peer: to }, options)
92
+ yield sendQueryEvent({ to, type: msg.type }, options)
93
93
 
94
94
  let stream: Stream | undefined
95
95
 
@@ -105,9 +105,9 @@ export class Network extends EventEmitter<NetworkEvents> implements Startable {
105
105
  closer: response.closerPeers,
106
106
  providers: response.providerPeers,
107
107
  record: response.record
108
- })
108
+ }, options)
109
109
  } catch (err: any) {
110
- yield queryErrorEvent({ from: to, error: err })
110
+ yield queryErrorEvent({ from: to, error: err }, options)
111
111
  } finally {
112
112
  if (stream != null) {
113
113
  stream.close()
@@ -118,14 +118,14 @@ export class Network extends EventEmitter<NetworkEvents> implements Startable {
118
118
  /**
119
119
  * Sends a message without expecting an answer
120
120
  */
121
- async * sendMessage (to: PeerId, msg: Message, options: AbortOptions = {}): AsyncGenerator<QueryEvent> {
121
+ async * sendMessage (to: PeerId, msg: Message, options: QueryOptions = {}): AsyncGenerator<QueryEvent> {
122
122
  if (!this.running) {
123
123
  return
124
124
  }
125
125
 
126
126
  this.log('sending %s to %p', msg.type, to)
127
- yield dialingPeerEvent({ peer: to })
128
- yield sendingQueryEvent({ to, type: msg.type })
127
+ yield dialPeerEvent({ peer: to }, options)
128
+ yield sendQueryEvent({ to, type: msg.type }, options)
129
129
 
130
130
  let stream: Stream | undefined
131
131
 
@@ -135,9 +135,9 @@ export class Network extends EventEmitter<NetworkEvents> implements Startable {
135
135
 
136
136
  await this._writeMessage(stream, msg.serialize(), options)
137
137
 
138
- yield peerResponseEvent({ from: to, messageType: msg.type })
138
+ yield peerResponseEvent({ from: to, messageType: msg.type }, options)
139
139
  } catch (err: any) {
140
- yield queryErrorEvent({ from: to, error: err })
140
+ yield queryErrorEvent({ from: to, error: err }, options)
141
141
  } finally {
142
142
  if (stream != null) {
143
143
  stream.close()
@@ -13,7 +13,7 @@ import {
13
13
  valueEvent
14
14
  } from '../query/events.js'
15
15
  import * as utils from '../utils.js'
16
- import type { KadDHTComponents, DHTRecord, DialingPeerEvent, FinalPeerEvent, QueryEvent, Validators } from '../index.js'
16
+ import type { KadDHTComponents, DHTRecord, DialPeerEvent, FinalPeerEvent, QueryEvent, Validators } from '../index.js'
17
17
  import type { Network } from '../network.js'
18
18
  import type { QueryManager, QueryOptions } from '../query/manager.js'
19
19
  import type { QueryFunc } from '../query/types.js'
@@ -122,7 +122,7 @@ export class PeerRouting {
122
122
  throw new CodeError('public key missing', 'ERR_PUBLIC_KEY_MISSING')
123
123
  }
124
124
 
125
- yield valueEvent({ from: peer, value: recPeer.publicKey })
125
+ yield valueEvent({ from: peer, value: recPeer.publicKey }, options)
126
126
  }
127
127
  }
128
128
 
@@ -144,7 +144,7 @@ export class PeerRouting {
144
144
  yield finalPeerEvent({
145
145
  from: this.components.peerId,
146
146
  peer: pi
147
- })
147
+ }, options)
148
148
  return
149
149
  }
150
150
 
@@ -153,7 +153,10 @@ export class PeerRouting {
153
153
  const findPeerQuery: QueryFunc = async function * ({ peer, signal }) {
154
154
  const request = new Message(MESSAGE_TYPE.FIND_NODE, id.toBytes(), 0)
155
155
 
156
- for await (const event of self.network.sendRequest(peer, request, { signal })) {
156
+ for await (const event of self.network.sendRequest(peer, request, {
157
+ ...options,
158
+ signal
159
+ })) {
157
160
  yield event
158
161
 
159
162
  if (event.name === 'PEER_RESPONSE') {
@@ -161,7 +164,7 @@ export class PeerRouting {
161
164
 
162
165
  // found the peer
163
166
  if (match != null) {
164
- yield finalPeerEvent({ from: event.from, peer: match })
167
+ yield finalPeerEvent({ from: event.from, peer: match }, options)
165
168
  }
166
169
  }
167
170
  }
@@ -178,7 +181,7 @@ export class PeerRouting {
178
181
  }
179
182
 
180
183
  if (!foundPeer) {
181
- yield queryErrorEvent({ from: this.components.peerId, error: new CodeError('Not found', 'ERR_NOT_FOUND') })
184
+ yield queryErrorEvent({ from: this.components.peerId, error: new CodeError('Not found', 'ERR_NOT_FOUND') }, options)
182
185
  }
183
186
  }
184
187
 
@@ -186,7 +189,7 @@ export class PeerRouting {
186
189
  * Kademlia 'node lookup' operation on a key, which could be a the
187
190
  * bytes from a multihash or a peer ID
188
191
  */
189
- async * getClosestPeers (key: Uint8Array, options: QueryOptions = {}): AsyncGenerator<DialingPeerEvent | QueryEvent> {
192
+ async * getClosestPeers (key: Uint8Array, options: QueryOptions = {}): AsyncGenerator<DialPeerEvent | QueryEvent> {
190
193
  this.log('getClosestPeers to %b', key)
191
194
  const id = await utils.convertBuffer(key)
192
195
  const tablePeers = this.routingTable.closestPeers(id)
@@ -199,7 +202,10 @@ export class PeerRouting {
199
202
  self.log('closerPeersSingle %s from %p', uint8ArrayToString(key, 'base32'), peer)
200
203
  const request = new Message(MESSAGE_TYPE.FIND_NODE, key, 0)
201
204
 
202
- yield * self.network.sendRequest(peer, request, { signal })
205
+ yield * self.network.sendRequest(peer, request, {
206
+ ...options,
207
+ signal
208
+ })
203
209
  }
204
210
 
205
211
  for await (const event of this.queryManager.run(key, getCloserPeersQuery, options)) {
@@ -223,7 +229,7 @@ export class PeerRouting {
223
229
  multiaddrs: peer.addresses.map(({ multiaddr }) => multiaddr),
224
230
  protocols: peer.protocols
225
231
  }
226
- })
232
+ }, options)
227
233
  } catch (err: any) {
228
234
  if (err.code !== 'ERR_NOT_FOUND') {
229
235
  throw err
@@ -238,7 +244,7 @@ export class PeerRouting {
238
244
  *
239
245
  * Note: The peerStore is updated with new addresses found for the given peer.
240
246
  */
241
- async * getValueOrPeers (peer: PeerId, key: Uint8Array, options: AbortOptions = {}): AsyncGenerator<DialingPeerEvent | QueryEvent> {
247
+ async * getValueOrPeers (peer: PeerId, key: Uint8Array, options: AbortOptions = {}): AsyncGenerator<DialPeerEvent | QueryEvent> {
242
248
  for await (const event of this._getValueSingle(peer, key, options)) {
243
249
  if (event.name === 'PEER_RESPONSE') {
244
250
  if (event.record != null) {
@@ -249,7 +255,7 @@ export class PeerRouting {
249
255
  const errMsg = 'invalid record received, discarded'
250
256
  this.log(errMsg)
251
257
 
252
- yield queryErrorEvent({ from: event.from, error: new CodeError(errMsg, 'ERR_INVALID_RECORD') })
258
+ yield queryErrorEvent({ from: event.from, error: new CodeError(errMsg, 'ERR_INVALID_RECORD') }, options)
253
259
  continue
254
260
  }
255
261
  }
@@ -1,5 +1,6 @@
1
+ import { CustomEvent } from '@libp2p/interfaces/events'
1
2
  import { MESSAGE_TYPE_LOOKUP } from '../message/index.js'
2
- import type { SendingQueryEvent, PeerResponseEvent, DialingPeerEvent, AddingPeerEvent, ValueEvent, ProviderEvent, QueryErrorEvent, FinalPeerEvent } from '../index.js'
3
+ import type { SendQueryEvent, PeerResponseEvent, DialPeerEvent, AddPeerEvent, ValueEvent, ProviderEvent, QueryErrorEvent, FinalPeerEvent, QueryOptions } from '../index.js'
3
4
  import type { Message } from '../message/dht.js'
4
5
  import type { PeerId } from '@libp2p/interface-peer-id'
5
6
  import type { PeerInfo } from '@libp2p/interface-peer-info'
@@ -10,14 +11,18 @@ export interface QueryEventFields {
10
11
  type: Message.MessageType
11
12
  }
12
13
 
13
- export function sendingQueryEvent (fields: QueryEventFields): SendingQueryEvent {
14
- return {
14
+ export function sendQueryEvent (fields: QueryEventFields, options: QueryOptions = {}): SendQueryEvent {
15
+ const event: SendQueryEvent = {
15
16
  ...fields,
16
- name: 'SENDING_QUERY',
17
+ name: 'SEND_QUERY',
17
18
  type: 0,
18
19
  messageName: fields.type,
19
20
  messageType: MESSAGE_TYPE_LOOKUP.indexOf(fields.type.toString())
20
21
  }
22
+
23
+ options.onProgress?.(new CustomEvent('kad-dht:query:send-query', { detail: event }))
24
+
25
+ return event
21
26
  }
22
27
 
23
28
  export interface PeerResponseEventField {
@@ -28,8 +33,8 @@ export interface PeerResponseEventField {
28
33
  record?: Libp2pRecord
29
34
  }
30
35
 
31
- export function peerResponseEvent (fields: PeerResponseEventField): PeerResponseEvent {
32
- return {
36
+ export function peerResponseEvent (fields: PeerResponseEventField, options: QueryOptions = {}): PeerResponseEvent {
37
+ const event: PeerResponseEvent = {
33
38
  ...fields,
34
39
  name: 'PEER_RESPONSE',
35
40
  type: 1,
@@ -37,6 +42,10 @@ export function peerResponseEvent (fields: PeerResponseEventField): PeerResponse
37
42
  closer: (fields.closer != null) ? fields.closer : [],
38
43
  providers: (fields.providers != null) ? fields.providers : []
39
44
  }
45
+
46
+ options.onProgress?.(new CustomEvent('kad-dht:query:peer-response', { detail: event }))
47
+
48
+ return event
40
49
  }
41
50
 
42
51
  export interface FinalPeerEventFields {
@@ -44,12 +53,16 @@ export interface FinalPeerEventFields {
44
53
  peer: PeerInfo
45
54
  }
46
55
 
47
- export function finalPeerEvent (fields: FinalPeerEventFields): FinalPeerEvent {
48
- return {
56
+ export function finalPeerEvent (fields: FinalPeerEventFields, options: QueryOptions = {}): FinalPeerEvent {
57
+ const event: FinalPeerEvent = {
49
58
  ...fields,
50
59
  name: 'FINAL_PEER',
51
60
  type: 2
52
61
  }
62
+
63
+ options.onProgress?.(new CustomEvent('kad-dht:query:final-peer', { detail: event }))
64
+
65
+ return event
53
66
  }
54
67
 
55
68
  export interface ErrorEventFields {
@@ -57,12 +70,16 @@ export interface ErrorEventFields {
57
70
  error: Error
58
71
  }
59
72
 
60
- export function queryErrorEvent (fields: ErrorEventFields): QueryErrorEvent {
61
- return {
73
+ export function queryErrorEvent (fields: ErrorEventFields, options: QueryOptions = {}): QueryErrorEvent {
74
+ const event: QueryErrorEvent = {
62
75
  ...fields,
63
76
  name: 'QUERY_ERROR',
64
77
  type: 3
65
78
  }
79
+
80
+ options.onProgress?.(new CustomEvent('kad-dht:query:query-error', { detail: event }))
81
+
82
+ return event
66
83
  }
67
84
 
68
85
  export interface ProviderEventFields {
@@ -70,12 +87,16 @@ export interface ProviderEventFields {
70
87
  providers: PeerInfo[]
71
88
  }
72
89
 
73
- export function providerEvent (fields: ProviderEventFields): ProviderEvent {
74
- return {
90
+ export function providerEvent (fields: ProviderEventFields, options: QueryOptions = {}): ProviderEvent {
91
+ const event: ProviderEvent = {
75
92
  ...fields,
76
93
  name: 'PROVIDER',
77
94
  type: 4
78
95
  }
96
+
97
+ options.onProgress?.(new CustomEvent('kad-dht:query:provider', { detail: event }))
98
+
99
+ return event
79
100
  }
80
101
 
81
102
  export interface ValueEventFields {
@@ -83,34 +104,46 @@ export interface ValueEventFields {
83
104
  value: Uint8Array
84
105
  }
85
106
 
86
- export function valueEvent (fields: ValueEventFields): ValueEvent {
87
- return {
107
+ export function valueEvent (fields: ValueEventFields, options: QueryOptions = {}): ValueEvent {
108
+ const event: ValueEvent = {
88
109
  ...fields,
89
110
  name: 'VALUE',
90
111
  type: 5
91
112
  }
113
+
114
+ options.onProgress?.(new CustomEvent('kad-dht:query:value', { detail: event }))
115
+
116
+ return event
92
117
  }
93
118
 
94
119
  export interface PeerEventFields {
95
120
  peer: PeerId
96
121
  }
97
122
 
98
- export function addingPeerEvent (fields: PeerEventFields): AddingPeerEvent {
99
- return {
123
+ export function addPeerEvent (fields: PeerEventFields, options: QueryOptions = {}): AddPeerEvent {
124
+ const event: AddPeerEvent = {
100
125
  ...fields,
101
- name: 'ADDING_PEER',
126
+ name: 'ADD_PEER',
102
127
  type: 6
103
128
  }
129
+
130
+ options.onProgress?.(new CustomEvent('kad-dht:query:add-peer', { detail: event }))
131
+
132
+ return event
104
133
  }
105
134
 
106
- export interface DialingPeerEventFields {
135
+ export interface DialPeerEventFields {
107
136
  peer: PeerId
108
137
  }
109
138
 
110
- export function dialingPeerEvent (fields: DialingPeerEventFields): DialingPeerEvent {
111
- return {
139
+ export function dialPeerEvent (fields: DialPeerEventFields, options: QueryOptions = {}): DialPeerEvent {
140
+ const event: DialPeerEvent = {
112
141
  ...fields,
113
- name: 'DIALING_PEER',
142
+ name: 'DIAL_PEER',
114
143
  type: 7
115
144
  }
145
+
146
+ options.onProgress?.(new CustomEvent('kad-dht:query:dial-peer', { detail: event }))
147
+
148
+ return event
116
149
  }
@@ -12,11 +12,10 @@ import {
12
12
  import { convertBuffer } from '../utils.js'
13
13
  import { queryPath } from './query-path.js'
14
14
  import type { QueryFunc } from './types.js'
15
- import type { QueryEvent } from '../index.js'
15
+ import type { QueryEvent, QueryOptions as RootQueryOptions } from '../index.js'
16
16
  import type { RoutingTable } from '../routing-table/index.js'
17
17
  import type { Metric, Metrics } from '@libp2p/interface-metrics'
18
18
  import type { PeerId } from '@libp2p/interface-peer-id'
19
- import type { AbortOptions } from '@libp2p/interfaces'
20
19
  import type { Startable } from '@libp2p/interfaces/startable'
21
20
  import type { DeferredPromise } from 'p-defer'
22
21
 
@@ -37,7 +36,7 @@ export interface QueryManagerComponents {
37
36
  metrics?: Metrics
38
37
  }
39
38
 
40
- export interface QueryOptions extends AbortOptions {
39
+ export interface QueryOptions extends RootQueryOptions {
41
40
  queryFuncTimeout?: number
42
41
  isSelfQuery?: boolean
43
42
  }
@@ -192,7 +191,8 @@ export class QueryManager implements Startable {
192
191
  cleanUp,
193
192
  queryFuncTimeout: options.queryFuncTimeout,
194
193
  log,
195
- peersSeen
194
+ peersSeen,
195
+ onProgress: options.onProgress
196
196
  })
197
197
  })
198
198