@libp2p/kad-dht 15.1.2 → 15.1.3-ae595d8db

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 (113) hide show
  1. package/dist/index.min.js +2 -2
  2. package/dist/index.min.js.map +4 -4
  3. package/dist/src/constants.d.ts +2 -0
  4. package/dist/src/constants.d.ts.map +1 -1
  5. package/dist/src/constants.js +4 -0
  6. package/dist/src/constants.js.map +1 -1
  7. package/dist/src/content-fetching/index.d.ts +2 -2
  8. package/dist/src/content-fetching/index.d.ts.map +1 -1
  9. package/dist/src/content-fetching/index.js +6 -6
  10. package/dist/src/content-fetching/index.js.map +1 -1
  11. package/dist/src/content-routing/index.js +3 -3
  12. package/dist/src/content-routing/index.js.map +1 -1
  13. package/dist/src/errors.d.ts +0 -6
  14. package/dist/src/errors.d.ts.map +1 -1
  15. package/dist/src/errors.js +0 -9
  16. package/dist/src/errors.js.map +1 -1
  17. package/dist/src/index.d.ts +24 -5
  18. package/dist/src/index.d.ts.map +1 -1
  19. package/dist/src/index.js.map +1 -1
  20. package/dist/src/kad-dht.d.ts +8 -5
  21. package/dist/src/kad-dht.d.ts.map +1 -1
  22. package/dist/src/kad-dht.js +25 -18
  23. package/dist/src/kad-dht.js.map +1 -1
  24. package/dist/src/network.d.ts +1 -1
  25. package/dist/src/network.d.ts.map +1 -1
  26. package/dist/src/network.js +2 -1
  27. package/dist/src/network.js.map +1 -1
  28. package/dist/src/peer-distance-list.d.ts +4 -4
  29. package/dist/src/peer-distance-list.d.ts.map +1 -1
  30. package/dist/src/peer-distance-list.js +6 -6
  31. package/dist/src/peer-distance-list.js.map +1 -1
  32. package/dist/src/peer-routing/index.d.ts +6 -5
  33. package/dist/src/peer-routing/index.d.ts.map +1 -1
  34. package/dist/src/peer-routing/index.js +21 -32
  35. package/dist/src/peer-routing/index.js.map +1 -1
  36. package/dist/src/providers.d.ts +0 -3
  37. package/dist/src/providers.d.ts.map +1 -1
  38. package/dist/src/providers.js +11 -31
  39. package/dist/src/providers.js.map +1 -1
  40. package/dist/src/query/manager.d.ts.map +1 -1
  41. package/dist/src/query/manager.js +7 -3
  42. package/dist/src/query/manager.js.map +1 -1
  43. package/dist/src/query/query-path.d.ts.map +1 -1
  44. package/dist/src/query/query-path.js +11 -5
  45. package/dist/src/query/query-path.js.map +1 -1
  46. package/dist/src/query-self.d.ts.map +1 -1
  47. package/dist/src/query-self.js +2 -1
  48. package/dist/src/query-self.js.map +1 -1
  49. package/dist/src/record/validators.d.ts +2 -1
  50. package/dist/src/record/validators.d.ts.map +1 -1
  51. package/dist/src/record/validators.js +3 -3
  52. package/dist/src/record/validators.js.map +1 -1
  53. package/dist/src/reprovider.d.ts +1 -4
  54. package/dist/src/reprovider.d.ts.map +1 -1
  55. package/dist/src/reprovider.js +13 -13
  56. package/dist/src/reprovider.js.map +1 -1
  57. package/dist/src/routing-table/index.d.ts +6 -5
  58. package/dist/src/routing-table/index.d.ts.map +1 -1
  59. package/dist/src/routing-table/index.js +72 -44
  60. package/dist/src/routing-table/index.js.map +1 -1
  61. package/dist/src/routing-table/k-bucket.d.ts +20 -8
  62. package/dist/src/routing-table/k-bucket.d.ts.map +1 -1
  63. package/dist/src/routing-table/k-bucket.js +35 -16
  64. package/dist/src/routing-table/k-bucket.js.map +1 -1
  65. package/dist/src/routing-table/refresh.d.ts +5 -5
  66. package/dist/src/routing-table/refresh.d.ts.map +1 -1
  67. package/dist/src/routing-table/refresh.js +21 -15
  68. package/dist/src/routing-table/refresh.js.map +1 -1
  69. package/dist/src/rpc/handlers/find-node.d.ts.map +1 -1
  70. package/dist/src/rpc/handlers/find-node.js +40 -24
  71. package/dist/src/rpc/handlers/find-node.js.map +1 -1
  72. package/dist/src/rpc/handlers/get-providers.js +1 -1
  73. package/dist/src/rpc/handlers/get-providers.js.map +1 -1
  74. package/dist/src/rpc/handlers/get-value.js +1 -1
  75. package/dist/src/rpc/handlers/get-value.js.map +1 -1
  76. package/dist/src/rpc/index.d.ts +2 -1
  77. package/dist/src/rpc/index.d.ts.map +1 -1
  78. package/dist/src/rpc/index.js +50 -19
  79. package/dist/src/rpc/index.js.map +1 -1
  80. package/dist/src/topology-listener.d.ts +1 -1
  81. package/dist/src/topology-listener.d.ts.map +1 -1
  82. package/dist/src/topology-listener.js +1 -1
  83. package/dist/src/topology-listener.js.map +1 -1
  84. package/dist/src/utils.d.ts +3 -3
  85. package/dist/src/utils.d.ts.map +1 -1
  86. package/dist/src/utils.js +4 -3
  87. package/dist/src/utils.js.map +1 -1
  88. package/package.json +17 -17
  89. package/src/constants.ts +6 -0
  90. package/src/content-fetching/index.ts +7 -7
  91. package/src/content-routing/index.ts +3 -3
  92. package/src/errors.ts +0 -10
  93. package/src/index.ts +27 -5
  94. package/src/kad-dht.ts +28 -20
  95. package/src/network.ts +2 -1
  96. package/src/peer-distance-list.ts +7 -7
  97. package/src/peer-routing/index.ts +23 -34
  98. package/src/providers.ts +15 -33
  99. package/src/query/manager.ts +7 -3
  100. package/src/query/query-path.ts +11 -5
  101. package/src/query-self.ts +3 -1
  102. package/src/record/validators.ts +4 -3
  103. package/src/reprovider.ts +13 -16
  104. package/src/routing-table/index.ts +74 -45
  105. package/src/routing-table/k-bucket.ts +54 -20
  106. package/src/routing-table/refresh.ts +21 -16
  107. package/src/rpc/handlers/find-node.ts +41 -27
  108. package/src/rpc/handlers/get-providers.ts +1 -1
  109. package/src/rpc/handlers/get-value.ts +1 -1
  110. package/src/rpc/index.ts +54 -23
  111. package/src/topology-listener.ts +1 -1
  112. package/src/utils.ts +5 -4
  113. package/dist/typedoc-urls.json +0 -63
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@libp2p/kad-dht",
3
- "version": "15.1.2",
3
+ "version": "15.1.3-ae595d8db",
4
4
  "description": "JavaScript implementation of the Kad-DHT for libp2p",
5
5
  "license": "Apache-2.0 OR MIT",
6
6
  "homepage": "https://github.com/libp2p/js-libp2p/tree/main/packages/kad-dht#readme",
@@ -47,21 +47,20 @@
47
47
  "doc-check": "aegir doc-check"
48
48
  },
49
49
  "dependencies": {
50
- "@libp2p/crypto": "^5.1.4",
51
- "@libp2p/interface": "^2.10.2",
52
- "@libp2p/interface-internal": "^2.3.14",
53
- "@libp2p/peer-collections": "^6.0.30",
54
- "@libp2p/peer-id": "^5.1.5",
55
- "@libp2p/ping": "^2.0.32",
56
- "@libp2p/record": "^4.0.6",
57
- "@libp2p/utils": "^6.6.5",
50
+ "@libp2p/crypto": "5.1.5-ae595d8db",
51
+ "@libp2p/interface": "2.10.3-ae595d8db",
52
+ "@libp2p/interface-internal": "2.3.15-ae595d8db",
53
+ "@libp2p/peer-collections": "6.0.31-ae595d8db",
54
+ "@libp2p/peer-id": "5.1.6-ae595d8db",
55
+ "@libp2p/ping": "2.0.33-ae595d8db",
56
+ "@libp2p/record": "4.0.7-ae595d8db",
57
+ "@libp2p/utils": "6.6.6-ae595d8db",
58
58
  "@multiformats/multiaddr": "^12.4.0",
59
59
  "any-signal": "^4.1.1",
60
60
  "interface-datastore": "^8.3.1",
61
61
  "it-all": "^3.0.8",
62
62
  "it-drain": "^3.0.9",
63
63
  "it-length": "^3.0.8",
64
- "it-length-prefixed": "^10.0.1",
65
64
  "it-map": "^3.1.3",
66
65
  "it-merge": "^3.0.11",
67
66
  "it-parallel": "^3.0.11",
@@ -69,8 +68,8 @@
69
68
  "it-protobuf-stream": "^2.0.2",
70
69
  "it-pushable": "^3.2.3",
71
70
  "it-take": "^3.0.8",
72
- "mortice": "^3.0.6",
73
- "multiformats": "^13.3.4",
71
+ "main-event": "^1.0.1",
72
+ "multiformats": "^13.3.6",
74
73
  "p-defer": "^4.0.1",
75
74
  "p-event": "^6.0.1",
76
75
  "progress-events": "^1.0.1",
@@ -81,26 +80,27 @@
81
80
  "uint8arrays": "^5.1.0"
82
81
  },
83
82
  "devDependencies": {
84
- "@libp2p/interface-compliance-tests": "^6.4.8",
85
- "@libp2p/logger": "^5.1.18",
86
- "@libp2p/peer-store": "^11.2.2",
83
+ "@libp2p/interface-compliance-tests": "6.4.9-ae595d8db",
84
+ "@libp2p/logger": "5.1.19-ae595d8db",
85
+ "@libp2p/peer-store": "11.2.3-ae595d8db",
87
86
  "@types/lodash.random": "^3.2.9",
88
87
  "@types/lodash.range": "^3.2.9",
89
88
  "@types/sinon": "^17.0.4",
90
89
  "@types/which": "^3.0.4",
91
- "aegir": "^47.0.6",
90
+ "aegir": "^47.0.14",
92
91
  "benchmark": "^2.1.4",
93
92
  "datastore-core": "^10.0.2",
94
93
  "delay": "^6.0.0",
95
94
  "execa": "^9.5.3",
96
95
  "it-filter": "^3.1.3",
97
96
  "it-last": "^3.0.8",
97
+ "it-length-prefixed": "^10.0.1",
98
98
  "it-pair": "^2.0.6",
99
99
  "it-stream-types": "^2.0.2",
100
100
  "lodash.random": "^3.2.0",
101
101
  "lodash.range": "^3.2.0",
102
102
  "p-retry": "^6.2.1",
103
- "protons": "^7.6.0",
103
+ "protons": "^7.6.1",
104
104
  "sinon": "^20.0.0",
105
105
  "sinon-ts": "^2.0.0",
106
106
  "which": "^5.0.0"
package/src/constants.ts CHANGED
@@ -27,8 +27,14 @@ export const REPROVIDE_MAX_QUEUE_SIZE = 16_384
27
27
  // How often to check if records need re-providing
28
28
  export const REPROVIDE_INTERVAL = hour
29
29
 
30
+ // How long to reprovide for
31
+ export const REPROVIDE_TIMEOUT = hour
32
+
30
33
  export const READ_MESSAGE_TIMEOUT = 10 * second
31
34
 
35
+ // How long to process newly connected peers for
36
+ export const ON_PEER_CONNECT_TIMEOUT = 10 * second
37
+
32
38
  // The number of records that will be retrieved on a call to getMany()
33
39
  export const GET_MANY_RECORD_COUNT = 16
34
40
 
@@ -22,7 +22,7 @@ import type { Network, SendMessageOptions } from '../network.js'
22
22
  import type { PeerRouting } from '../peer-routing/index.js'
23
23
  import type { QueryManager } from '../query/manager.js'
24
24
  import type { QueryFunc } from '../query/types.js'
25
- import type { Logger, RoutingOptions } from '@libp2p/interface'
25
+ import type { AbortOptions, Logger, RoutingOptions } from '@libp2p/interface'
26
26
 
27
27
  export interface ContentFetchingInit {
28
28
  validators: Validators
@@ -68,19 +68,19 @@ export class ContentFetching {
68
68
  * Attempt to retrieve the value for the given key from
69
69
  * the local datastore
70
70
  */
71
- async getLocal (key: Uint8Array): Promise<Libp2pRecord> {
71
+ async getLocal (key: Uint8Array, options?: AbortOptions): Promise<Libp2pRecord> {
72
72
  this.log('getLocal %b', key)
73
73
 
74
74
  const dsKey = bufferToRecordKey(this.datastorePrefix, key)
75
75
 
76
76
  this.log('fetching record for key %k', dsKey)
77
77
 
78
- const raw = await this.components.datastore.get(dsKey)
78
+ const raw = await this.components.datastore.get(dsKey, options)
79
79
  this.log('found %k in local datastore', dsKey)
80
80
 
81
81
  const rec = Libp2pRecord.deserialize(raw)
82
82
 
83
- await verifyRecord(this.validators, rec)
83
+ await verifyRecord(this.validators, rec, options)
84
84
 
85
85
  return rec
86
86
  }
@@ -104,7 +104,7 @@ export class ContentFetching {
104
104
  try {
105
105
  const dsKey = bufferToRecordKey(this.datastorePrefix, key)
106
106
  this.log(`Storing corrected record for key ${dsKey.toString()}`)
107
- await this.components.datastore.put(dsKey, fixupRec.subarray())
107
+ await this.components.datastore.put(dsKey, fixupRec.subarray(), options)
108
108
  } catch (err: any) {
109
109
  this.log.error('Failed error correcting self', err)
110
110
  }
@@ -148,7 +148,7 @@ export class ContentFetching {
148
148
  // store the record locally
149
149
  const dsKey = bufferToRecordKey(this.datastorePrefix, key)
150
150
  this.log(`storing record for key ${dsKey.toString()}`)
151
- await this.components.datastore.put(dsKey, record.subarray())
151
+ await this.components.datastore.put(dsKey, record.subarray(), options)
152
152
 
153
153
  // put record to the closest peers
154
154
  yield * pipe(
@@ -265,7 +265,7 @@ export class ContentFetching {
265
265
  this.log('getMany values for %b', key)
266
266
 
267
267
  try {
268
- const localRec = await this.getLocal(key)
268
+ const localRec = await this.getLocal(key, options)
269
269
 
270
270
  yield valueEvent({
271
271
  value: localRec.value,
@@ -83,7 +83,7 @@ export class ContentRouting {
83
83
  const target = key.multihash.bytes
84
84
 
85
85
  // Add peer as provider
86
- await this.providers.addProvider(key, this.components.peerId)
86
+ await this.providers.addProvider(key, this.components.peerId, options)
87
87
 
88
88
  const msg: Partial<Message> = {
89
89
  type: MessageType.ADD_PROVIDER,
@@ -182,7 +182,7 @@ export class ContentRouting {
182
182
 
183
183
  this.log('findProviders %c', key)
184
184
 
185
- const provs = await this.providers.getProviders(key)
185
+ const provs = await this.providers.getProviders(key, options)
186
186
 
187
187
  // yield values if we have some, also slice because maybe we got lucky and already have too many?
188
188
  if (provs.length > 0) {
@@ -190,7 +190,7 @@ export class ContentRouting {
190
190
 
191
191
  for (const peerId of provs.slice(0, toFind)) {
192
192
  try {
193
- const peer = await this.components.peerStore.get(peerId)
193
+ const peer = await this.components.peerStore.get(peerId, options)
194
194
 
195
195
  providers.push({
196
196
  id: peerId,
package/src/errors.ts CHANGED
@@ -8,16 +8,6 @@ export class QueryError extends Error {
8
8
  }
9
9
  }
10
10
 
11
- /**
12
- * A query was aborted
13
- */
14
- export class QueryAbortedError extends Error {
15
- constructor (message = 'Query aborted') {
16
- super(message)
17
- this.name = 'QueryAbortedError'
18
- }
19
- }
20
-
21
11
  /**
22
12
  * An invalid record was received
23
13
  */
package/src/index.ts CHANGED
@@ -135,11 +135,12 @@
135
135
  import { KadDHT as KadDHTClass } from './kad-dht.js'
136
136
  import { MessageType } from './message/dht.js'
137
137
  import { removePrivateAddressesMapper, removePublicAddressesMapper, passthroughMapper } from './utils.js'
138
- import type { Libp2pEvents, ComponentLogger, TypedEventTarget, Metrics, PeerId, PeerInfo, PeerStore, RoutingOptions, PrivateKey } from '@libp2p/interface'
138
+ import type { Libp2pEvents, ComponentLogger, Metrics, PeerId, PeerInfo, PeerStore, RoutingOptions, PrivateKey, AbortOptions } from '@libp2p/interface'
139
139
  import type { AddressManager, ConnectionManager, Registrar } from '@libp2p/interface-internal'
140
140
  import type { Ping } from '@libp2p/ping'
141
141
  import type { AdaptiveTimeoutInit } from '@libp2p/utils/adaptive-timeout'
142
142
  import type { Datastore } from 'interface-datastore'
143
+ import type { TypedEventTarget } from 'main-event'
143
144
  import type { CID } from 'multiformats/cid'
144
145
  import type { ProgressEvent } from 'progress-events'
145
146
 
@@ -302,6 +303,10 @@ export interface PeerInfoMapper {
302
303
  (peer: PeerInfo): PeerInfo
303
304
  }
304
305
 
306
+ export interface SetModeOptions extends AbortOptions {
307
+ force?: boolean
308
+ }
309
+
305
310
  export interface KadDHT {
306
311
  /**
307
312
  * This is the maximum size of the k-buckets and how many peers are looked up
@@ -350,7 +355,7 @@ export interface KadDHT {
350
355
  * Provider records must be re-published every 24 hours - pass a previously
351
356
  * provided CID here to not re-publish a record for it any more
352
357
  */
353
- cancelReprovide(key: CID): Promise<void>
358
+ cancelReprovide(key: CID, options?: AbortOptions): Promise<void>
354
359
 
355
360
  /**
356
361
  * Store the passed value under the passed key on the DHT
@@ -366,12 +371,12 @@ export interface KadDHT {
366
371
  * If 'server' this node will respond to DHT queries, if 'client' this node
367
372
  * will not.
368
373
  */
369
- setMode(mode: 'client' | 'server'): Promise<void>
374
+ setMode(mode: 'client' | 'server', options?: SetModeOptions): Promise<void>
370
375
 
371
376
  /**
372
377
  * Force a routing table refresh
373
378
  */
374
- refreshRoutingTable(): Promise<void>
379
+ refreshRoutingTable(options?: AbortOptions): Promise<void>
375
380
  }
376
381
 
377
382
  export interface SingleKadDHT extends KadDHT {
@@ -388,7 +393,7 @@ export interface SelectFn { (key: Uint8Array, records: Uint8Array[]): number }
388
393
  * A validator function takes a DHT key and the value of the record for that key
389
394
  * and throws if the record is invalid
390
395
  */
391
- export interface ValidateFn { (key: Uint8Array, value: Uint8Array): Promise<void> }
396
+ export interface ValidateFn { (key: Uint8Array, value: Uint8Array, options?: AbortOptions): Promise<void> }
392
397
 
393
398
  /**
394
399
  * Selectors are a map of key prefixes to selector functions
@@ -680,6 +685,23 @@ export interface KadDHTInit {
680
685
  * Dynamic network timeout settings for sending messages to peers
681
686
  */
682
687
  networkDialTimeout?: Omit<AdaptiveTimeoutInit, 'metricsName' | 'metrics'>
688
+
689
+ /**
690
+ * When a peer that supports the KAD-DHT protocol connects we try to add it to
691
+ * the routing table. This setting is how long we will try to do that for in
692
+ * ms.
693
+ *
694
+ * @default 10_000
695
+ */
696
+ onPeerConnectTimeout?: number
697
+
698
+ /**
699
+ * When acting as a DHT server, all incoming RPC requests must complete within
700
+ * this timeout in ms otherwise the stream will be closed.
701
+ *
702
+ * @default 10_000
703
+ */
704
+ incomingMessageTimeout?: number
683
705
  }
684
706
 
685
707
  export interface KadDHTComponents {
package/src/kad-dht.ts CHANGED
@@ -1,8 +1,8 @@
1
- import { NotFoundError, TypedEventEmitter, contentRoutingSymbol, peerDiscoverySymbol, peerRoutingSymbol, serviceCapabilities, serviceDependencies, start, stop } from '@libp2p/interface'
1
+ import { NotFoundError, contentRoutingSymbol, peerDiscoverySymbol, peerRoutingSymbol, serviceCapabilities, serviceDependencies, start, stop } from '@libp2p/interface'
2
2
  import drain from 'it-drain'
3
- import createMortice from 'mortice'
3
+ import { setMaxListeners, TypedEventEmitter } from 'main-event'
4
4
  import pDefer from 'p-defer'
5
- import { ALPHA, PROTOCOL } from './constants.js'
5
+ import { ALPHA, ON_PEER_CONNECT_TIMEOUT, PROTOCOL } from './constants.js'
6
6
  import { ContentFetching } from './content-fetching/index.js'
7
7
  import { ContentRouting as KADDHTContentRouting } from './content-routing/index.js'
8
8
  import { Network } from './network.js'
@@ -22,8 +22,9 @@ import {
22
22
  removePrivateAddressesMapper,
23
23
  timeOperationGenerator
24
24
  } from './utils.js'
25
- import type { KadDHTComponents, KadDHTInit, Validators, Selectors, KadDHT as KadDHTInterface, QueryEvent, PeerInfoMapper } from './index.js'
25
+ import type { KadDHTComponents, KadDHTInit, Validators, Selectors, KadDHT as KadDHTInterface, QueryEvent, PeerInfoMapper, SetModeOptions } from './index.js'
26
26
  import type { ContentRouting, CounterGroup, Logger, MetricGroup, PeerDiscovery, PeerDiscoveryEvents, PeerId, PeerInfo, PeerRouting, RoutingOptions, Startable } from '@libp2p/interface'
27
+ import type { AbortOptions } from 'it-pushable'
27
28
  import type { CID } from 'multiformats/cid'
28
29
 
29
30
  /**
@@ -142,6 +143,7 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
142
143
  private readonly dhtPeerRouting: DHTPeerRouting
143
144
  private readonly peerInfoMapper: PeerInfoMapper
144
145
  private readonly reprovider: Reprovider
146
+ private readonly onPeerConnectTimeout: number
145
147
 
146
148
  /**
147
149
  * Create a new KadDHT
@@ -171,14 +173,12 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
171
173
  this.maxInboundStreams = init.maxInboundStreams ?? DEFAULT_MAX_INBOUND_STREAMS
172
174
  this.maxOutboundStreams = init.maxOutboundStreams ?? DEFAULT_MAX_OUTBOUND_STREAMS
173
175
  this.peerInfoMapper = init.peerInfoMapper ?? removePrivateAddressesMapper
174
-
175
- const providerLock = createMortice()
176
+ this.onPeerConnectTimeout = init.onPeerConnectTimeout ?? ON_PEER_CONNECT_TIMEOUT
176
177
 
177
178
  this.providers = new Providers(components, {
178
179
  ...init.providers,
179
180
  logPrefix,
180
- datastorePrefix,
181
- lock: providerLock
181
+ datastorePrefix
182
182
  })
183
183
 
184
184
  this.validators = {
@@ -289,7 +289,6 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
289
289
  metricsPrefix,
290
290
  datastorePrefix,
291
291
  contentRouting: this.contentRouting,
292
- lock: providerLock,
293
292
  operationMetrics
294
293
  })
295
294
 
@@ -366,7 +365,8 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
366
365
  readonly [serviceCapabilities]: string[] = [
367
366
  '@libp2p/content-routing',
368
367
  '@libp2p/peer-routing',
369
- '@libp2p/peer-discovery'
368
+ '@libp2p/peer-discovery',
369
+ '@libp2p/kad-dht'
370
370
  ]
371
371
 
372
372
  readonly [serviceDependencies]: string[] = [
@@ -396,8 +396,13 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
396
396
  return
397
397
  }
398
398
 
399
+ const signal = AbortSignal.timeout(this.onPeerConnectTimeout)
400
+ setMaxListeners(Infinity, signal)
401
+
399
402
  try {
400
- await this.routingTable.add(peerData.id)
403
+ await this.routingTable.add(peerData.id, {
404
+ signal
405
+ })
401
406
  } catch (err: any) {
402
407
  this.log.error('could not add %p to routing table', peerData.id, err)
403
408
  }
@@ -420,16 +425,16 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
420
425
  /**
421
426
  * If 'server' this node will respond to DHT queries, if 'client' this node will not
422
427
  */
423
- async setMode (mode: 'client' | 'server', force = false): Promise<void> {
424
- if (mode === this.getMode() && !force) {
428
+ async setMode (mode: 'client' | 'server', options?: SetModeOptions): Promise<void> {
429
+ if (mode === this.getMode() && options?.force !== true) {
425
430
  this.log('already in %s mode', mode)
426
431
  return
427
432
  }
428
433
 
429
- await this.components.registrar.unhandle(this.protocol)
434
+ await this.components.registrar.unhandle(this.protocol, options)
430
435
 
431
436
  // check again after async work
432
- if (mode === this.getMode() && !force) {
437
+ if (mode === this.getMode() && options?.force !== true) {
433
438
  this.log('already in %s mode', mode)
434
439
  return
435
440
  }
@@ -441,6 +446,7 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
441
446
  this.log('enabling server mode while in %s mode', this.getMode())
442
447
  this.clientMode = false
443
448
  await this.components.registrar.handle(this.protocol, this.rpc.onIncomingStream.bind(this.rpc), {
449
+ signal: options?.signal,
444
450
  maxInboundStreams: this.maxInboundStreams,
445
451
  maxOutboundStreams: this.maxOutboundStreams
446
452
  })
@@ -458,7 +464,9 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
458
464
  this.running = true
459
465
 
460
466
  // Only respond to queries when not in client mode
461
- await this.setMode(this.clientMode ? 'client' : 'server', true)
467
+ await this.setMode(this.clientMode ? 'client' : 'server', {
468
+ force: true
469
+ })
462
470
 
463
471
  await start(
464
472
  this.routingTable,
@@ -520,8 +528,8 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
520
528
  * Provider records must be re-published every 24 hours - pass a previously
521
529
  * provided CID here to not re-publish a record for it any more
522
530
  */
523
- async cancelReprovide (key: CID): Promise<void> {
524
- await this.providers.removeProvider(key, this.components.peerId)
531
+ async cancelReprovide (key: CID, options?: AbortOptions): Promise<void> {
532
+ await this.providers.removeProvider(key, this.components.peerId, options)
525
533
  }
526
534
 
527
535
  /**
@@ -547,7 +555,7 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
547
555
  yield * this.peerRouting.getClosestPeers(key, options)
548
556
  }
549
557
 
550
- async refreshRoutingTable (): Promise<void> {
551
- this.routingTableRefresh.refreshTable(true)
558
+ async refreshRoutingTable (options?: AbortOptions): Promise<void> {
559
+ this.routingTableRefresh.refreshTable(true, options)
552
560
  }
553
561
  }
package/src/network.ts CHANGED
@@ -1,7 +1,8 @@
1
- import { InvalidParametersError, TypedEventEmitter } from '@libp2p/interface'
1
+ import { InvalidParametersError } from '@libp2p/interface'
2
2
  import { Libp2pRecord } from '@libp2p/record'
3
3
  import { AdaptiveTimeout } from '@libp2p/utils/adaptive-timeout'
4
4
  import { pbStream } from 'it-protobuf-stream'
5
+ import { TypedEventEmitter } from 'main-event'
5
6
  import { Message } from './message/dht.js'
6
7
  import { fromPbPeerInfo } from './message/utils.js'
7
8
  import {
@@ -2,7 +2,7 @@ import { xor as uint8ArrayXor } from 'uint8arrays/xor'
2
2
  import { xorCompare as uint8ArrayXorCompare } from 'uint8arrays/xor-compare'
3
3
  import { convertPeerId } from './utils.js'
4
4
  import type { DisjointPath } from './index.js'
5
- import type { PeerId, PeerInfo } from '@libp2p/interface'
5
+ import type { AbortOptions, PeerId, PeerInfo } from '@libp2p/interface'
6
6
 
7
7
  interface PeerDistance {
8
8
  peer: PeerInfo
@@ -49,8 +49,8 @@ export class PeerDistanceList {
49
49
  /**
50
50
  * Add a peerId to the list.
51
51
  */
52
- async add (peer: PeerInfo, path: DisjointPath = { index: -1, queued: 0, running: 0, total: 0 }): Promise<void> {
53
- const dhtKey = await convertPeerId(peer.id)
52
+ async add (peer: PeerInfo, path: DisjointPath = { index: -1, queued: 0, running: 0, total: 0 }, options?: AbortOptions): Promise<void> {
53
+ const dhtKey = await convertPeerId(peer.id, options)
54
54
 
55
55
  this.addWithKadId(peer, dhtKey, path)
56
56
  }
@@ -100,12 +100,12 @@ export class PeerDistanceList {
100
100
  * Indicates whether any of the peerIds passed as a parameter are closer
101
101
  * to the origin key than the furthest peerId in the PeerDistanceList.
102
102
  */
103
- async isCloser (peerId: PeerId): Promise<boolean> {
103
+ async isCloser (peerId: PeerId, options?: AbortOptions): Promise<boolean> {
104
104
  if (this.length === 0) {
105
105
  return true
106
106
  }
107
107
 
108
- const dhtKey = await convertPeerId(peerId)
108
+ const dhtKey = await convertPeerId(peerId, options)
109
109
  const dhtKeyXor = uint8ArrayXor(dhtKey, this.originDhtKey)
110
110
  const furthestDistance = this.peerDistances[this.peerDistances.length - 1].distance
111
111
 
@@ -116,13 +116,13 @@ export class PeerDistanceList {
116
116
  * Indicates whether any of the peerIds passed as a parameter are closer
117
117
  * to the origin key than the furthest peerId in the PeerDistanceList.
118
118
  */
119
- async anyCloser (peerIds: PeerId[]): Promise<boolean> {
119
+ async anyCloser (peerIds: PeerId[], options?: AbortOptions): Promise<boolean> {
120
120
  if (peerIds.length === 0) {
121
121
  return false
122
122
  }
123
123
 
124
124
  return Promise.any(
125
- peerIds.map(async peerId => this.isCloser(peerId))
125
+ peerIds.map(async peerId => this.isCloser(peerId, options))
126
126
  )
127
127
  }
128
128
  }
@@ -3,8 +3,6 @@ import { InvalidPublicKeyError, NotFoundError } from '@libp2p/interface'
3
3
  import { peerIdFromPublicKey, peerIdFromMultihash } from '@libp2p/peer-id'
4
4
  import { Libp2pRecord } from '@libp2p/record'
5
5
  import * as Digest from 'multiformats/hashes/digest'
6
- import { xor as uint8ArrayXor } from 'uint8arrays/xor'
7
- import { xorCompare as uint8ArrayXorCompare } from 'uint8arrays/xor-compare'
8
6
  import { QueryError, InvalidRecordError } from '../errors.js'
9
7
  import { MessageType } from '../message/dht.js'
10
8
  import { PeerDistanceList } from '../peer-distance-list.js'
@@ -14,15 +12,17 @@ import {
14
12
  valueEvent
15
13
  } from '../query/events.js'
16
14
  import { verifyRecord } from '../record/validators.js'
17
- import { convertBuffer, convertPeerId, keyForPublicKey } from '../utils.js'
15
+ import { convertBuffer, keyForPublicKey } from '../utils.js'
18
16
  import type { DHTRecord, FinalPeerEvent, QueryEvent, Validators } from '../index.js'
19
17
  import type { Message } from '../message/dht.js'
20
18
  import type { Network, SendMessageOptions } from '../network.js'
21
19
  import type { QueryManager, QueryOptions } from '../query/manager.js'
22
20
  import type { QueryFunc } from '../query/types.js'
23
21
  import type { RoutingTable } from '../routing-table/index.js'
22
+ import type { GetClosestPeersOptions } from '../routing-table/k-bucket.ts'
24
23
  import type { ComponentLogger, Logger, Metrics, PeerId, PeerInfo, PeerStore, RoutingOptions } from '@libp2p/interface'
25
24
  import type { ConnectionManager } from '@libp2p/interface-internal'
25
+ import type { AbortOptions } from 'it-pushable'
26
26
 
27
27
  export interface PeerRoutingComponents {
28
28
  peerId: PeerId
@@ -68,15 +68,15 @@ export class PeerRouting {
68
68
  * Look if we are connected to a peer with the given id.
69
69
  * Returns its id and addresses, if found, otherwise `undefined`.
70
70
  */
71
- async findPeerLocal (peer: PeerId): Promise<PeerInfo | undefined> {
71
+ async findPeerLocal (peer: PeerId, options?: AbortOptions): Promise<PeerInfo | undefined> {
72
72
  let peerData
73
- const p = await this.routingTable.find(peer)
73
+ const p = await this.routingTable.find(peer, options)
74
74
 
75
75
  if (p != null) {
76
76
  this.log('findPeerLocal found %p in routing table', peer)
77
77
 
78
78
  try {
79
- peerData = await this.components.peerStore.get(p)
79
+ peerData = await this.components.peerStore.get(p, options)
80
80
  } catch (err: any) {
81
81
  if (err.name !== 'NotFoundError') {
82
82
  throw err
@@ -86,7 +86,7 @@ export class PeerRouting {
86
86
 
87
87
  if (peerData == null) {
88
88
  try {
89
- peerData = await this.components.peerStore.get(peer)
89
+ peerData = await this.components.peerStore.get(peer, options)
90
90
  } catch (err: any) {
91
91
  if (err.name !== 'NotFoundError') {
92
92
  throw err
@@ -168,7 +168,7 @@ export class PeerRouting {
168
168
 
169
169
  if (options.useCache !== false) {
170
170
  // Try to find locally
171
- const pi = await this.findPeerLocal(id)
171
+ const pi = await this.findPeerLocal(id, options)
172
172
 
173
173
  // already got it
174
174
  if (pi != null) {
@@ -240,12 +240,12 @@ export class PeerRouting {
240
240
  */
241
241
  async * getClosestPeers (key: Uint8Array, options: QueryOptions = {}): AsyncGenerator<QueryEvent> {
242
242
  this.log('getClosestPeers to %b', key)
243
- const kadId = await convertBuffer(key)
243
+ const kadId = await convertBuffer(key, options)
244
244
  const peers = new PeerDistanceList(kadId, this.routingTable.kBucketSize)
245
245
  const self = this
246
246
 
247
247
  const getCloserPeersQuery: QueryFunc = async function * ({ peer, path, peerKadId, signal }) {
248
- self.log('getClosestPeers asking %p', peer)
248
+ self.log('getClosestPeers asking %p', peer.id)
249
249
  const request: Partial<Message> = {
250
250
  type: MessageType.FIND_NODE,
251
251
  key
@@ -268,7 +268,7 @@ export class PeerRouting {
268
268
  for (let { peer, path } of peers.peers) {
269
269
  try {
270
270
  if (peer.multiaddrs.length === 0) {
271
- peer = await self.components.peerStore.getInfo(peer.id)
271
+ peer = await self.components.peerStore.getInfo(peer.id, options)
272
272
  }
273
273
 
274
274
  if (peer.multiaddrs.length === 0) {
@@ -277,7 +277,7 @@ export class PeerRouting {
277
277
 
278
278
  yield finalPeerEvent({
279
279
  from: this.components.peerId,
280
- peer: await self.components.peerStore.getInfo(peer.id),
280
+ peer: await self.components.peerStore.getInfo(peer.id, options),
281
281
  path: {
282
282
  index: path.index,
283
283
  queued: 0,
@@ -303,7 +303,7 @@ export class PeerRouting {
303
303
  if (event.record != null) {
304
304
  // We have a record
305
305
  try {
306
- await this._verifyRecordOnline(event.record)
306
+ await this._verifyRecordOnline(event.record, options)
307
307
  } catch (err: any) {
308
308
  const errMsg = 'invalid record received, discarded'
309
309
  this.log(errMsg)
@@ -326,19 +326,18 @@ export class PeerRouting {
326
326
  * Verify a record, fetching missing public keys from the network.
327
327
  * Throws an error if the record is invalid.
328
328
  */
329
- async _verifyRecordOnline (record: DHTRecord): Promise<void> {
329
+ async _verifyRecordOnline (record: DHTRecord, options?: AbortOptions): Promise<void> {
330
330
  if (record.timeReceived == null) {
331
331
  throw new InvalidRecordError('invalid record received')
332
332
  }
333
333
 
334
- await verifyRecord(this.validators, new Libp2pRecord(record.key, record.value, record.timeReceived))
334
+ await verifyRecord(this.validators, new Libp2pRecord(record.key, record.value, record.timeReceived), options)
335
335
  }
336
336
 
337
337
  /**
338
- * Get the peers in our routing table that are closer than the passed PeerId
339
- * to the passed key
338
+ * Get the peers in our routing table that are closest to the passed key
340
339
  */
341
- async getCloserPeersOffline (key: Uint8Array, closerThan: PeerId): Promise<PeerInfo[]> {
340
+ async getClosestPeersOffline (key: Uint8Array, options?: GetClosestPeersOptions): Promise<PeerInfo[]> {
342
341
  const output: PeerInfo[] = []
343
342
 
344
343
  // try getting the peer directly
@@ -346,7 +345,7 @@ export class PeerRouting {
346
345
  const multihash = Digest.decode(key)
347
346
  const targetPeerId = peerIdFromMultihash(multihash)
348
347
 
349
- const peer = await this.components.peerStore.get(targetPeerId)
348
+ const peer = await this.components.peerStore.get(targetPeerId, options)
350
349
 
351
350
  output.push({
352
351
  id: peer.id,
@@ -354,22 +353,12 @@ export class PeerRouting {
354
353
  })
355
354
  } catch {}
356
355
 
357
- const keyKadId = await convertBuffer(key)
358
- const ids = this.routingTable.closestPeers(keyKadId)
359
- const closerThanKadId = await convertPeerId(closerThan)
360
- const requesterXor = uint8ArrayXor(closerThanKadId, keyKadId)
356
+ const keyKadId = await convertBuffer(key, options)
357
+ const ids = this.routingTable.closestPeers(keyKadId, options)
361
358
 
362
359
  for (const peerId of ids) {
363
- const peerKadId = await convertPeerId(peerId)
364
- const peerXor = uint8ArrayXor(peerKadId, keyKadId)
365
-
366
- // only include if peer is closer than requester
367
- if (uint8ArrayXorCompare(peerXor, requesterXor) !== -1) {
368
- continue
369
- }
370
-
371
360
  try {
372
- output.push(await this.components.peerStore.getInfo(peerId))
361
+ output.push(await this.components.peerStore.getInfo(peerId, options))
373
362
  } catch (err: any) {
374
363
  if (err.name !== 'NotFoundError') {
375
364
  throw err
@@ -378,9 +367,9 @@ export class PeerRouting {
378
367
  }
379
368
 
380
369
  if (output.length > 0) {
381
- this.log('getCloserPeersOffline found %d peer(s) closer to %b than %p', output.length, key, closerThan)
370
+ this.log('getClosestPeersOffline returning the %d closest peer(s) %b we know', output.length, key)
382
371
  } else {
383
- this.log('getCloserPeersOffline could not find peer closer to %b than %p with %d peers in the routing table', key, closerThan, this.routingTable.size)
372
+ this.log('getClosestPeersOffline could not any peers close to %b with %d peers in the routing table', key, this.routingTable.size)
384
373
  }
385
374
 
386
375
  return output