@libp2p/kad-dht 9.1.4 → 9.2.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 (54) hide show
  1. package/dist/index.min.js +20 -20
  2. package/dist/src/content-fetching/index.d.ts +0 -3
  3. package/dist/src/content-fetching/index.d.ts.map +1 -1
  4. package/dist/src/content-fetching/index.js +7 -12
  5. package/dist/src/content-fetching/index.js.map +1 -1
  6. package/dist/src/content-routing/index.d.ts +1 -2
  7. package/dist/src/content-routing/index.d.ts.map +1 -1
  8. package/dist/src/content-routing/index.js +9 -8
  9. package/dist/src/content-routing/index.js.map +1 -1
  10. package/dist/src/dual-kad-dht.d.ts +1 -2
  11. package/dist/src/dual-kad-dht.d.ts.map +1 -1
  12. package/dist/src/dual-kad-dht.js +7 -7
  13. package/dist/src/dual-kad-dht.js.map +1 -1
  14. package/dist/src/index.d.ts +16 -14
  15. package/dist/src/index.d.ts.map +1 -1
  16. package/dist/src/index.js +3 -3
  17. package/dist/src/index.js.map +1 -1
  18. package/dist/src/kad-dht.js +2 -2
  19. package/dist/src/kad-dht.js.map +1 -1
  20. package/dist/src/network.d.ts +3 -3
  21. package/dist/src/network.d.ts.map +1 -1
  22. package/dist/src/network.js +9 -9
  23. package/dist/src/network.js.map +1 -1
  24. package/dist/src/peer-routing/index.d.ts +3 -3
  25. package/dist/src/peer-routing/index.d.ts.map +1 -1
  26. package/dist/src/peer-routing/index.js +16 -34
  27. package/dist/src/peer-routing/index.js.map +1 -1
  28. package/dist/src/query/events.d.ts +10 -10
  29. package/dist/src/query/events.d.ts.map +1 -1
  30. package/dist/src/query/events.js +36 -19
  31. package/dist/src/query/events.js.map +1 -1
  32. package/dist/src/query/manager.d.ts +6 -4
  33. package/dist/src/query/manager.d.ts.map +1 -1
  34. package/dist/src/query/manager.js +9 -3
  35. package/dist/src/query/manager.js.map +1 -1
  36. package/dist/src/query/query-path.d.ts +2 -2
  37. package/dist/src/query/query-path.d.ts.map +1 -1
  38. package/dist/src/query/query-path.js +1 -1
  39. package/dist/src/query/query-path.js.map +1 -1
  40. package/dist/src/routing-table/index.js +1 -1
  41. package/dist/src/routing-table/index.js.map +1 -1
  42. package/dist/typedoc-urls.json +4 -3
  43. package/package.json +2 -1
  44. package/src/content-fetching/index.ts +7 -16
  45. package/src/content-routing/index.ts +10 -10
  46. package/src/dual-kad-dht.ts +13 -14
  47. package/src/index.ts +25 -14
  48. package/src/kad-dht.ts +2 -2
  49. package/src/network.ts +13 -13
  50. package/src/peer-routing/index.ts +19 -41
  51. package/src/query/events.ts +54 -21
  52. package/src/query/manager.ts +14 -6
  53. package/src/query/query-path.ts +3 -3
  54. package/src/routing-table/index.ts +1 -1
@@ -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,44 +144,19 @@ 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
 
151
- const key = await utils.convertPeerId(id)
152
- const peers = this.routingTable.closestPeers(key)
153
-
154
- // sanity check
155
- const match = peers.find((p) => p.equals(id))
156
-
157
- if (match != null) {
158
- try {
159
- const peer = await this.components.peerStore.get(id)
160
-
161
- this.log('found in peerStore')
162
- yield finalPeerEvent({
163
- from: this.components.peerId,
164
- peer: {
165
- id: peer.id,
166
- multiaddrs: peer.addresses.map((address) => address.multiaddr),
167
- protocols: []
168
- }
169
- })
170
-
171
- return
172
- } catch (err: any) {
173
- if (err.code !== 'ERR_NOT_FOUND') {
174
- throw err
175
- }
176
- }
177
- }
178
-
179
151
  const self = this // eslint-disable-line @typescript-eslint/no-this-alias
180
152
 
181
153
  const findPeerQuery: QueryFunc = async function * ({ peer, signal }) {
182
154
  const request = new Message(MESSAGE_TYPE.FIND_NODE, id.toBytes(), 0)
183
155
 
184
- 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
+ })) {
185
160
  yield event
186
161
 
187
162
  if (event.name === 'PEER_RESPONSE') {
@@ -189,7 +164,7 @@ export class PeerRouting {
189
164
 
190
165
  // found the peer
191
166
  if (match != null) {
192
- yield finalPeerEvent({ from: event.from, peer: match })
167
+ yield finalPeerEvent({ from: event.from, peer: match }, options)
193
168
  }
194
169
  }
195
170
  }
@@ -197,7 +172,7 @@ export class PeerRouting {
197
172
 
198
173
  let foundPeer = false
199
174
 
200
- for await (const event of this.queryManager.run(id.toBytes(), peers, findPeerQuery, options)) {
175
+ for await (const event of this.queryManager.run(id.toBytes(), findPeerQuery, options)) {
201
176
  if (event.name === 'FINAL_PEER') {
202
177
  foundPeer = true
203
178
  }
@@ -206,7 +181,7 @@ export class PeerRouting {
206
181
  }
207
182
 
208
183
  if (!foundPeer) {
209
- 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)
210
185
  }
211
186
  }
212
187
 
@@ -214,7 +189,7 @@ export class PeerRouting {
214
189
  * Kademlia 'node lookup' operation on a key, which could be a the
215
190
  * bytes from a multihash or a peer ID
216
191
  */
217
- async * getClosestPeers (key: Uint8Array, options: QueryOptions = {}): AsyncGenerator<DialingPeerEvent | QueryEvent> {
192
+ async * getClosestPeers (key: Uint8Array, options: QueryOptions = {}): AsyncGenerator<DialPeerEvent | QueryEvent> {
218
193
  this.log('getClosestPeers to %b', key)
219
194
  const id = await utils.convertBuffer(key)
220
195
  const tablePeers = this.routingTable.closestPeers(id)
@@ -227,10 +202,13 @@ export class PeerRouting {
227
202
  self.log('closerPeersSingle %s from %p', uint8ArrayToString(key, 'base32'), peer)
228
203
  const request = new Message(MESSAGE_TYPE.FIND_NODE, key, 0)
229
204
 
230
- yield * self.network.sendRequest(peer, request, { signal })
205
+ yield * self.network.sendRequest(peer, request, {
206
+ ...options,
207
+ signal
208
+ })
231
209
  }
232
210
 
233
- for await (const event of this.queryManager.run(key, tablePeers, getCloserPeersQuery, options)) {
211
+ for await (const event of this.queryManager.run(key, getCloserPeersQuery, options)) {
234
212
  yield event
235
213
 
236
214
  if (event.name === 'PEER_RESPONSE') {
@@ -251,7 +229,7 @@ export class PeerRouting {
251
229
  multiaddrs: peer.addresses.map(({ multiaddr }) => multiaddr),
252
230
  protocols: peer.protocols
253
231
  }
254
- })
232
+ }, options)
255
233
  } catch (err: any) {
256
234
  if (err.code !== 'ERR_NOT_FOUND') {
257
235
  throw err
@@ -266,7 +244,7 @@ export class PeerRouting {
266
244
  *
267
245
  * Note: The peerStore is updated with new addresses found for the given peer.
268
246
  */
269
- async * getValueOrPeers (peer: PeerId, key: Uint8Array, options: AbortOptions = {}): AsyncGenerator<DialingPeerEvent | QueryEvent> {
247
+ async * getValueOrPeers (peer: PeerId, key: Uint8Array, options: AbortOptions = {}): AsyncGenerator<DialPeerEvent | QueryEvent> {
270
248
  for await (const event of this._getValueSingle(peer, key, options)) {
271
249
  if (event.name === 'PEER_RESPONSE') {
272
250
  if (event.record != null) {
@@ -277,7 +255,7 @@ export class PeerRouting {
277
255
  const errMsg = 'invalid record received, discarded'
278
256
  this.log(errMsg)
279
257
 
280
- 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)
281
259
  continue
282
260
  }
283
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
  }
@@ -9,12 +9,13 @@ import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
9
9
  import {
10
10
  ALPHA, K, DEFAULT_QUERY_TIMEOUT
11
11
  } from '../constants.js'
12
+ import { convertBuffer } from '../utils.js'
12
13
  import { queryPath } from './query-path.js'
13
14
  import type { QueryFunc } from './types.js'
14
- import type { QueryEvent } from '../index.js'
15
+ import type { QueryEvent, QueryOptions as RootQueryOptions } from '../index.js'
16
+ import type { RoutingTable } from '../routing-table/index.js'
15
17
  import type { Metric, Metrics } from '@libp2p/interface-metrics'
16
18
  import type { PeerId } from '@libp2p/interface-peer-id'
17
- import type { AbortOptions } from '@libp2p/interfaces'
18
19
  import type { Startable } from '@libp2p/interfaces/startable'
19
20
  import type { DeferredPromise } from 'p-defer'
20
21
 
@@ -27,6 +28,7 @@ export interface QueryManagerInit {
27
28
  disjointPaths?: number
28
29
  alpha?: number
29
30
  initialQuerySelfHasRun: DeferredPromise<void>
31
+ routingTable: RoutingTable
30
32
  }
31
33
 
32
34
  export interface QueryManagerComponents {
@@ -34,7 +36,7 @@ export interface QueryManagerComponents {
34
36
  metrics?: Metrics
35
37
  }
36
38
 
37
- export interface QueryOptions extends AbortOptions {
39
+ export interface QueryOptions extends RootQueryOptions {
38
40
  queryFuncTimeout?: number
39
41
  isSelfQuery?: boolean
40
42
  }
@@ -55,6 +57,7 @@ export class QueryManager implements Startable {
55
57
  queryTime: Metric
56
58
  }
57
59
 
60
+ private readonly routingTable: RoutingTable
58
61
  private initialQuerySelfHasRun?: DeferredPromise<void>
59
62
 
60
63
  constructor (components: QueryManagerComponents, init: QueryManagerInit) {
@@ -67,6 +70,7 @@ export class QueryManager implements Startable {
67
70
  this.lan = lan
68
71
  this.queries = 0
69
72
  this.initialQuerySelfHasRun = init.initialQuerySelfHasRun
73
+ this.routingTable = init.routingTable
70
74
 
71
75
  // allow us to stop queries on shut down
72
76
  this.shutDownController = new AbortController()
@@ -105,7 +109,7 @@ export class QueryManager implements Startable {
105
109
  this.shutDownController.abort()
106
110
  }
107
111
 
108
- async * run (key: Uint8Array, peers: PeerId[], queryFunc: QueryFunc, options: QueryOptions = {}): AsyncGenerator<QueryEvent> {
112
+ async * run (key: Uint8Array, queryFunc: QueryFunc, options: QueryOptions = {}): AsyncGenerator<QueryEvent> {
109
113
  if (!this.running) {
110
114
  throw new Error('QueryManager not started')
111
115
  }
@@ -138,7 +142,6 @@ export class QueryManager implements Startable {
138
142
  const log = logger(`libp2p:kad-dht:${this.lan ? 'lan' : 'wan'}:query:` + uint8ArrayToString(key, 'base58btc'))
139
143
 
140
144
  // query a subset of peers up to `kBucketSize / 2` in length
141
- const peersToQuery = peers.slice(0, Math.min(this.disjointPaths, peers.length))
142
145
  const startTime = Date.now()
143
146
  const cleanUp = new EventEmitter<CleanUpEvents>()
144
147
 
@@ -162,6 +165,10 @@ export class QueryManager implements Startable {
162
165
  this.queries++
163
166
  this.metrics?.runningQueries.update(this.queries)
164
167
 
168
+ const id = await convertBuffer(key)
169
+ const peers = this.routingTable.closestPeers(id)
170
+ const peersToQuery = peers.slice(0, Math.min(this.disjointPaths, peers.length))
171
+
165
172
  if (peers.length === 0) {
166
173
  log.error('Running query with no peers')
167
174
  return
@@ -184,7 +191,8 @@ export class QueryManager implements Startable {
184
191
  cleanUp,
185
192
  queryFuncTimeout: options.queryFuncTimeout,
186
193
  log,
187
- peersSeen
194
+ peersSeen,
195
+ onProgress: options.onProgress
188
196
  })
189
197
  })
190
198
 
@@ -7,7 +7,7 @@ import { xor } from 'uint8arrays/xor'
7
7
  import { convertPeerId, convertBuffer } from '../utils.js'
8
8
  import { queryErrorEvent } from './events.js'
9
9
  import type { CleanUpEvents } from './manager.js'
10
- import type { QueryEvent } from '../index.js'
10
+ import type { QueryEvent, QueryOptions } from '../index.js'
11
11
  import type { QueryFunc } from '../query/types.js'
12
12
  import type { PeerId } from '@libp2p/interface-peer-id'
13
13
  import type { EventEmitter } from '@libp2p/interfaces/events'
@@ -16,7 +16,7 @@ import type { PeerSet } from '@libp2p/peer-collections'
16
16
 
17
17
  const MAX_XOR = BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF')
18
18
 
19
- export interface QueryPathOptions {
19
+ export interface QueryPathOptions extends QueryOptions {
20
20
  /**
21
21
  * What are we trying to find
22
22
  */
@@ -160,7 +160,7 @@ export async function * queryPath (options: QueryPathOptions): AsyncGenerator<Qu
160
160
  return queryErrorEvent({
161
161
  from: peer,
162
162
  error: err
163
- })
163
+ }, options)
164
164
  }
165
165
  } finally {
166
166
  compoundSignal.clear()
@@ -244,7 +244,7 @@ export class RoutingTable implements Startable {
244
244
  // only evict peers if we are still running, otherwise we evict when dialing is
245
245
  // cancelled due to shutdown in progress
246
246
  this.log.error('could not ping peer %p', oldContact.peer, err)
247
- this.log('evicting old contact after ping failed %p', oldContact)
247
+ this.log('evicting old contact after ping failed %p', oldContact.peer)
248
248
  this.kb.remove(oldContact.id)
249
249
  }
250
250
  } finally {