@libp2p/kad-dht 13.1.1 → 13.1.2-27b2fa6b6
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/dist/index.min.js +2 -2
- package/dist/src/index.d.ts +28 -6
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/kad-dht.d.ts.map +1 -1
- package/dist/src/kad-dht.js +25 -11
- package/dist/src/kad-dht.js.map +1 -1
- package/dist/src/network.d.ts +2 -1
- package/dist/src/network.d.ts.map +1 -1
- package/dist/src/network.js +10 -3
- package/dist/src/network.js.map +1 -1
- package/dist/src/peer-distance-list.d.ts.map +1 -0
- package/dist/src/{peer-list/peer-distance-list.js → peer-distance-list.js} +1 -1
- package/dist/src/peer-distance-list.js.map +1 -0
- package/dist/src/peer-routing/index.js +1 -1
- package/dist/src/peer-routing/index.js.map +1 -1
- package/dist/src/query/manager.d.ts +1 -2
- package/dist/src/query/manager.d.ts.map +1 -1
- package/dist/src/query/manager.js +11 -16
- package/dist/src/query/manager.js.map +1 -1
- package/dist/src/query-self.d.ts.map +1 -1
- package/dist/src/query-self.js +13 -6
- package/dist/src/query-self.js.map +1 -1
- package/dist/src/routing-table/closest-peers.d.ts +43 -0
- package/dist/src/routing-table/closest-peers.d.ts.map +1 -0
- package/dist/src/routing-table/closest-peers.js +86 -0
- package/dist/src/routing-table/closest-peers.js.map +1 -0
- package/dist/src/routing-table/index.d.ts +55 -32
- package/dist/src/routing-table/index.d.ts.map +1 -1
- package/dist/src/routing-table/index.js +261 -158
- package/dist/src/routing-table/index.js.map +1 -1
- package/dist/src/routing-table/k-bucket.d.ts +65 -21
- package/dist/src/routing-table/k-bucket.d.ts.map +1 -1
- package/dist/src/routing-table/k-bucket.js +122 -66
- package/dist/src/routing-table/k-bucket.js.map +1 -1
- package/dist/src/routing-table/refresh.d.ts.map +1 -1
- package/dist/src/routing-table/refresh.js +4 -1
- package/dist/src/routing-table/refresh.js.map +1 -1
- package/dist/src/rpc/index.d.ts.map +1 -1
- package/dist/src/rpc/index.js +3 -7
- package/dist/src/rpc/index.js.map +1 -1
- package/package.json +11 -12
- package/src/index.ts +32 -6
- package/src/kad-dht.ts +29 -13
- package/src/network.ts +18 -5
- package/src/{peer-list/peer-distance-list.ts → peer-distance-list.ts} +1 -1
- package/src/peer-routing/index.ts +1 -1
- package/src/query/manager.ts +16 -21
- package/src/query-self.ts +14 -6
- package/src/routing-table/closest-peers.ts +113 -0
- package/src/routing-table/index.ts +302 -189
- package/src/routing-table/k-bucket.ts +194 -81
- package/src/routing-table/refresh.ts +5 -1
- package/src/rpc/index.ts +4 -7
- package/dist/src/peer-list/index.d.ts +0 -29
- package/dist/src/peer-list/index.d.ts.map +0 -1
- package/dist/src/peer-list/index.js +0 -45
- package/dist/src/peer-list/index.js.map +0 -1
- package/dist/src/peer-list/peer-distance-list.d.ts.map +0 -1
- package/dist/src/peer-list/peer-distance-list.js.map +0 -1
- package/dist/typedoc-urls.json +0 -56
- package/src/peer-list/index.ts +0 -54
- /package/dist/src/{peer-list/peer-distance-list.d.ts → peer-distance-list.d.ts} +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@libp2p/kad-dht",
|
|
3
|
-
"version": "13.1.
|
|
3
|
+
"version": "13.1.2-27b2fa6b6",
|
|
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",
|
|
@@ -57,13 +57,13 @@
|
|
|
57
57
|
"doc-check": "aegir doc-check"
|
|
58
58
|
},
|
|
59
59
|
"dependencies": {
|
|
60
|
-
"@libp2p/crypto": "
|
|
61
|
-
"@libp2p/interface": "
|
|
62
|
-
"@libp2p/interface-internal": "
|
|
63
|
-
"@libp2p/peer-collections": "
|
|
64
|
-
"@libp2p/peer-id": "
|
|
65
|
-
"@libp2p/record": "
|
|
66
|
-
"@libp2p/utils": "
|
|
60
|
+
"@libp2p/crypto": "5.0.4-27b2fa6b6",
|
|
61
|
+
"@libp2p/interface": "2.1.2-27b2fa6b6",
|
|
62
|
+
"@libp2p/interface-internal": "2.0.6-27b2fa6b6",
|
|
63
|
+
"@libp2p/peer-collections": "6.0.6-27b2fa6b6",
|
|
64
|
+
"@libp2p/peer-id": "5.0.4-27b2fa6b6",
|
|
65
|
+
"@libp2p/record": "4.0.4-27b2fa6b6",
|
|
66
|
+
"@libp2p/utils": "6.0.6-27b2fa6b6",
|
|
67
67
|
"@multiformats/multiaddr": "^12.2.3",
|
|
68
68
|
"any-signal": "^4.1.1",
|
|
69
69
|
"hashlru": "^2.3.0",
|
|
@@ -89,9 +89,9 @@
|
|
|
89
89
|
"uint8arrays": "^5.1.0"
|
|
90
90
|
},
|
|
91
91
|
"devDependencies": {
|
|
92
|
-
"@libp2p/interface-compliance-tests": "
|
|
93
|
-
"@libp2p/logger": "
|
|
94
|
-
"@libp2p/peer-store": "
|
|
92
|
+
"@libp2p/interface-compliance-tests": "6.1.4-27b2fa6b6",
|
|
93
|
+
"@libp2p/logger": "5.1.0-27b2fa6b6",
|
|
94
|
+
"@libp2p/peer-store": "11.0.6-27b2fa6b6",
|
|
95
95
|
"@types/lodash.random": "^3.2.9",
|
|
96
96
|
"@types/lodash.range": "^3.2.9",
|
|
97
97
|
"@types/sinon": "^17.0.3",
|
|
@@ -109,7 +109,6 @@
|
|
|
109
109
|
"lodash.random": "^3.2.0",
|
|
110
110
|
"lodash.range": "^3.2.0",
|
|
111
111
|
"p-retry": "^6.2.0",
|
|
112
|
-
"p-wait-for": "^5.0.2",
|
|
113
112
|
"protons": "^7.5.0",
|
|
114
113
|
"sinon": "^18.0.0",
|
|
115
114
|
"sinon-ts": "^2.0.0",
|
package/src/index.ts
CHANGED
|
@@ -397,12 +397,10 @@ export interface KadDHTInit {
|
|
|
397
397
|
logPrefix?: string
|
|
398
398
|
|
|
399
399
|
/**
|
|
400
|
-
*
|
|
401
|
-
* should be evicted from the routing table or not.
|
|
402
|
-
*
|
|
403
|
-
* @default 10000
|
|
400
|
+
* Settings for how long to wait in ms when pinging DHT peers to decide if
|
|
401
|
+
* they should be evicted from the routing table or not.
|
|
404
402
|
*/
|
|
405
|
-
|
|
403
|
+
pingOldContactTimeout?: Omit<AdaptiveTimeoutInit, 'metricsName' | 'metrics'>
|
|
406
404
|
|
|
407
405
|
/**
|
|
408
406
|
* How many peers to ping in parallel when deciding if they should
|
|
@@ -410,7 +408,35 @@ export interface KadDHTInit {
|
|
|
410
408
|
*
|
|
411
409
|
* @default 10
|
|
412
410
|
*/
|
|
413
|
-
|
|
411
|
+
pingOldContactConcurrency?: number
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* How long the queue to ping peers is allowed to grow
|
|
415
|
+
*
|
|
416
|
+
* @default 100
|
|
417
|
+
*/
|
|
418
|
+
pingOldContactMaxQueueSize?: number
|
|
419
|
+
|
|
420
|
+
/**
|
|
421
|
+
* Settings for how long to wait in ms when pinging DHT peers to decide if
|
|
422
|
+
* they should be added to the routing table or not.
|
|
423
|
+
*/
|
|
424
|
+
pingNewContactTimeout?: Omit<AdaptiveTimeoutInit, 'metricsName' | 'metrics'>
|
|
425
|
+
|
|
426
|
+
/**
|
|
427
|
+
* How many peers to ping in parallel when deciding if they should be added to
|
|
428
|
+
* the routing table or not
|
|
429
|
+
*
|
|
430
|
+
* @default 10
|
|
431
|
+
*/
|
|
432
|
+
pingNewContactConcurrency?: number
|
|
433
|
+
|
|
434
|
+
/**
|
|
435
|
+
* How long the queue to ping peers is allowed to grow
|
|
436
|
+
*
|
|
437
|
+
* @default 100
|
|
438
|
+
*/
|
|
439
|
+
pingNewContactMaxQueueSize?: number
|
|
414
440
|
|
|
415
441
|
/**
|
|
416
442
|
* How many parallel incoming streams to allow on the DHT protocol per
|
package/src/kad-dht.ts
CHANGED
|
@@ -138,8 +138,6 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
|
138
138
|
querySelfInterval,
|
|
139
139
|
protocol,
|
|
140
140
|
logPrefix,
|
|
141
|
-
pingTimeout,
|
|
142
|
-
pingConcurrency,
|
|
143
141
|
maxInboundStreams,
|
|
144
142
|
maxOutboundStreams,
|
|
145
143
|
providers: providersInit
|
|
@@ -156,13 +154,6 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
|
156
154
|
this.maxInboundStreams = maxInboundStreams ?? DEFAULT_MAX_INBOUND_STREAMS
|
|
157
155
|
this.maxOutboundStreams = maxOutboundStreams ?? DEFAULT_MAX_OUTBOUND_STREAMS
|
|
158
156
|
this.peerInfoMapper = init.peerInfoMapper ?? removePrivateAddressesMapper
|
|
159
|
-
this.routingTable = new RoutingTable(components, {
|
|
160
|
-
kBucketSize,
|
|
161
|
-
pingTimeout,
|
|
162
|
-
pingConcurrency,
|
|
163
|
-
protocol: this.protocol,
|
|
164
|
-
logPrefix: loggingPrefix
|
|
165
|
-
})
|
|
166
157
|
|
|
167
158
|
this.providers = new Providers(components, providersInit ?? {})
|
|
168
159
|
|
|
@@ -179,6 +170,21 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
|
179
170
|
logPrefix: loggingPrefix
|
|
180
171
|
})
|
|
181
172
|
|
|
173
|
+
this.routingTable = new RoutingTable(components, {
|
|
174
|
+
kBucketSize,
|
|
175
|
+
pingOldContactTimeout: init.pingOldContactTimeout,
|
|
176
|
+
pingOldContactConcurrency: init.pingOldContactConcurrency,
|
|
177
|
+
pingOldContactMaxQueueSize: init.pingOldContactMaxQueueSize,
|
|
178
|
+
pingNewContactTimeout: init.pingNewContactTimeout,
|
|
179
|
+
pingNewContactConcurrency: init.pingNewContactConcurrency,
|
|
180
|
+
pingNewContactMaxQueueSize: init.pingNewContactMaxQueueSize,
|
|
181
|
+
protocol: this.protocol,
|
|
182
|
+
logPrefix: loggingPrefix,
|
|
183
|
+
prefixLength: init.prefixLength,
|
|
184
|
+
splitThreshold: init.kBucketSplitThreshold,
|
|
185
|
+
network: this.network
|
|
186
|
+
})
|
|
187
|
+
|
|
182
188
|
// all queries should wait for the initial query-self query to run so we have
|
|
183
189
|
// some peers and don't force consumers to use arbitrary timeouts
|
|
184
190
|
const initialQuerySelfHasRun = pDefer<any>()
|
|
@@ -374,11 +380,17 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
|
374
380
|
|
|
375
381
|
await this.components.registrar.unhandle(this.protocol)
|
|
376
382
|
|
|
383
|
+
// check again after async work
|
|
384
|
+
if (mode === this.getMode() && !force) {
|
|
385
|
+
this.log('already in %s mode', mode)
|
|
386
|
+
return
|
|
387
|
+
}
|
|
388
|
+
|
|
377
389
|
if (mode === 'client') {
|
|
378
|
-
this.log('enabling client mode')
|
|
390
|
+
this.log('enabling client mode while in %s mode', this.getMode())
|
|
379
391
|
this.clientMode = true
|
|
380
392
|
} else {
|
|
381
|
-
this.log('enabling server mode')
|
|
393
|
+
this.log('enabling server mode while in %s mode', this.getMode())
|
|
382
394
|
this.clientMode = false
|
|
383
395
|
await this.components.registrar.handle(this.protocol, this.rpc.onIncomingStream.bind(this.rpc), {
|
|
384
396
|
maxInboundStreams: this.maxInboundStreams,
|
|
@@ -397,14 +409,18 @@ export class KadDHT extends TypedEventEmitter<PeerDiscoveryEvents> implements Ka
|
|
|
397
409
|
await this.setMode(this.clientMode ? 'client' : 'server', true)
|
|
398
410
|
|
|
399
411
|
await start(
|
|
400
|
-
this.
|
|
412
|
+
this.routingTable,
|
|
401
413
|
this.providers,
|
|
402
414
|
this.queryManager,
|
|
403
415
|
this.network,
|
|
404
|
-
this.routingTable,
|
|
405
416
|
this.topologyListener,
|
|
406
417
|
this.routingTableRefresh
|
|
407
418
|
)
|
|
419
|
+
|
|
420
|
+
// Query self after other components are configured
|
|
421
|
+
await start(
|
|
422
|
+
this.querySelf
|
|
423
|
+
)
|
|
408
424
|
}
|
|
409
425
|
|
|
410
426
|
/**
|
package/src/network.ts
CHANGED
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
queryErrorEvent
|
|
12
12
|
} from './query/events.js'
|
|
13
13
|
import type { KadDHTComponents, QueryEvent } from './index.js'
|
|
14
|
-
import type { AbortOptions, Logger, Stream, PeerId, PeerInfo, Startable, RoutingOptions } from '@libp2p/interface'
|
|
14
|
+
import type { AbortOptions, Logger, Stream, PeerId, PeerInfo, Startable, RoutingOptions, CounterGroup } from '@libp2p/interface'
|
|
15
15
|
|
|
16
16
|
export interface NetworkInit {
|
|
17
17
|
protocol: string
|
|
@@ -32,6 +32,10 @@ export class Network extends TypedEventEmitter<NetworkEvents> implements Startab
|
|
|
32
32
|
private running: boolean
|
|
33
33
|
private readonly components: KadDHTComponents
|
|
34
34
|
private readonly timeout: AdaptiveTimeout
|
|
35
|
+
private readonly metrics: {
|
|
36
|
+
operations?: CounterGroup
|
|
37
|
+
errors?: CounterGroup
|
|
38
|
+
}
|
|
35
39
|
|
|
36
40
|
/**
|
|
37
41
|
* Create a new network
|
|
@@ -49,6 +53,10 @@ export class Network extends TypedEventEmitter<NetworkEvents> implements Startab
|
|
|
49
53
|
metrics: components.metrics,
|
|
50
54
|
metricName: `${init.logPrefix.replaceAll(':', '_')}_network_message_send_times_milliseconds`
|
|
51
55
|
})
|
|
56
|
+
this.metrics = {
|
|
57
|
+
operations: components.metrics?.registerCounterGroup(`${init.logPrefix.replaceAll(':', '_')}_outbound_rpc_requests_total`),
|
|
58
|
+
errors: components.metrics?.registerCounterGroup(`${init.logPrefix.replaceAll(':', '_')}_outbound_rpc_errors_total`)
|
|
59
|
+
}
|
|
52
60
|
}
|
|
53
61
|
|
|
54
62
|
/**
|
|
@@ -77,7 +85,7 @@ export class Network extends TypedEventEmitter<NetworkEvents> implements Startab
|
|
|
77
85
|
}
|
|
78
86
|
|
|
79
87
|
/**
|
|
80
|
-
* Send a request and
|
|
88
|
+
* Send a request and read a response
|
|
81
89
|
*/
|
|
82
90
|
async * sendRequest (to: PeerId, msg: Partial<Message>, options: RoutingOptions = {}): AsyncGenerator<QueryEvent> {
|
|
83
91
|
if (!this.running) {
|
|
@@ -103,6 +111,8 @@ export class Network extends TypedEventEmitter<NetworkEvents> implements Startab
|
|
|
103
111
|
}
|
|
104
112
|
|
|
105
113
|
try {
|
|
114
|
+
this.metrics.operations?.increment({ [type]: true })
|
|
115
|
+
|
|
106
116
|
const connection = await this.components.connectionManager.openConnection(to, options)
|
|
107
117
|
stream = await connection.newStream(this.protocol, options)
|
|
108
118
|
const response = await this._writeReadMessage(stream, msg, options)
|
|
@@ -121,6 +131,8 @@ export class Network extends TypedEventEmitter<NetworkEvents> implements Startab
|
|
|
121
131
|
record: response.record == null ? undefined : Libp2pRecord.deserialize(response.record)
|
|
122
132
|
}, options)
|
|
123
133
|
} catch (err: any) {
|
|
134
|
+
this.metrics.errors?.increment({ [type]: true })
|
|
135
|
+
|
|
124
136
|
stream?.abort(err)
|
|
125
137
|
|
|
126
138
|
// only log if the incoming signal was not aborted - this means we were
|
|
@@ -162,6 +174,8 @@ export class Network extends TypedEventEmitter<NetworkEvents> implements Startab
|
|
|
162
174
|
}
|
|
163
175
|
|
|
164
176
|
try {
|
|
177
|
+
this.metrics.operations?.increment({ [type]: true })
|
|
178
|
+
|
|
165
179
|
const connection = await this.components.connectionManager.openConnection(to, options)
|
|
166
180
|
stream = await connection.newStream(this.protocol, options)
|
|
167
181
|
|
|
@@ -175,6 +189,8 @@ export class Network extends TypedEventEmitter<NetworkEvents> implements Startab
|
|
|
175
189
|
|
|
176
190
|
yield peerResponseEvent({ from: to, messageType: type }, options)
|
|
177
191
|
} catch (err: any) {
|
|
192
|
+
this.metrics.errors?.increment({ [type]: true })
|
|
193
|
+
|
|
178
194
|
stream?.abort(err)
|
|
179
195
|
yield queryErrorEvent({ from: to, error: err }, options)
|
|
180
196
|
} finally {
|
|
@@ -188,7 +204,6 @@ export class Network extends TypedEventEmitter<NetworkEvents> implements Startab
|
|
|
188
204
|
async _writeMessage (stream: Stream, msg: Partial<Message>, options: AbortOptions): Promise<void> {
|
|
189
205
|
const pb = pbStream(stream)
|
|
190
206
|
await pb.write(msg, Message, options)
|
|
191
|
-
await pb.unwrap().close(options)
|
|
192
207
|
}
|
|
193
208
|
|
|
194
209
|
/**
|
|
@@ -203,8 +218,6 @@ export class Network extends TypedEventEmitter<NetworkEvents> implements Startab
|
|
|
203
218
|
|
|
204
219
|
const message = await pb.read(Message, options)
|
|
205
220
|
|
|
206
|
-
await pb.unwrap().close(options)
|
|
207
|
-
|
|
208
221
|
// tell any listeners about new peers we've seen
|
|
209
222
|
message.closer.forEach(peerData => {
|
|
210
223
|
this.safeDispatchEvent<PeerInfo>('peer', {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { xor as uint8ArrayXor } from 'uint8arrays/xor'
|
|
2
2
|
import { xorCompare as uint8ArrayXorCompare } from 'uint8arrays/xor-compare'
|
|
3
|
-
import { convertPeerId } from '
|
|
3
|
+
import { convertPeerId } from './utils.js'
|
|
4
4
|
import type { PeerId, PeerInfo } from '@libp2p/interface'
|
|
5
5
|
|
|
6
6
|
interface PeerDistance {
|
|
@@ -5,7 +5,7 @@ import { Libp2pRecord } from '@libp2p/record'
|
|
|
5
5
|
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
|
6
6
|
import { QueryError, InvalidRecordError } from '../errors.js'
|
|
7
7
|
import { MessageType } from '../message/dht.js'
|
|
8
|
-
import { PeerDistanceList } from '../peer-
|
|
8
|
+
import { PeerDistanceList } from '../peer-distance-list.js'
|
|
9
9
|
import {
|
|
10
10
|
queryErrorEvent,
|
|
11
11
|
finalPeerEvent,
|
package/src/query/manager.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { queryPath } from './query-path.js'
|
|
|
12
12
|
import type { QueryFunc } from './types.js'
|
|
13
13
|
import type { QueryEvent } from '../index.js'
|
|
14
14
|
import type { RoutingTable } from '../routing-table/index.js'
|
|
15
|
-
import type { ComponentLogger, Metric, Metrics, PeerId, RoutingOptions, Startable } from '@libp2p/interface'
|
|
15
|
+
import type { ComponentLogger, Counter, Metric, Metrics, PeerId, RoutingOptions, Startable } from '@libp2p/interface'
|
|
16
16
|
import type { ConnectionManager } from '@libp2p/interface-internal'
|
|
17
17
|
import type { DeferredPromise } from 'p-defer'
|
|
18
18
|
|
|
@@ -52,16 +52,16 @@ export class QueryManager implements Startable {
|
|
|
52
52
|
private readonly alpha: number
|
|
53
53
|
private shutDownController: AbortController
|
|
54
54
|
private running: boolean
|
|
55
|
-
private queries: number
|
|
56
55
|
private readonly logger: ComponentLogger
|
|
57
56
|
private readonly peerId: PeerId
|
|
58
57
|
private readonly connectionManager: ConnectionManager
|
|
59
58
|
private readonly routingTable: RoutingTable
|
|
60
59
|
private initialQuerySelfHasRun?: DeferredPromise<void>
|
|
61
60
|
private readonly logPrefix: string
|
|
62
|
-
private readonly metrics
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
private readonly metrics: {
|
|
62
|
+
queries?: Counter
|
|
63
|
+
errors?: Counter
|
|
64
|
+
queryTime?: Metric
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
constructor (components: QueryManagerComponents, init: QueryManagerInit) {
|
|
@@ -71,18 +71,16 @@ export class QueryManager implements Startable {
|
|
|
71
71
|
this.disjointPaths = disjointPaths ?? K
|
|
72
72
|
this.running = false
|
|
73
73
|
this.alpha = alpha ?? ALPHA
|
|
74
|
-
this.queries = 0
|
|
75
74
|
this.initialQuerySelfHasRun = init.initialQuerySelfHasRun
|
|
76
75
|
this.routingTable = init.routingTable
|
|
77
76
|
this.logger = components.logger
|
|
78
77
|
this.peerId = components.peerId
|
|
79
78
|
this.connectionManager = components.connectionManager
|
|
80
79
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}
|
|
80
|
+
this.metrics = {
|
|
81
|
+
queries: components.metrics?.registerCounter(`${logPrefix.replaceAll(':', '_')}_queries_total`),
|
|
82
|
+
errors: components.metrics?.registerCounter(`${logPrefix.replaceAll(':', '_')}_query_errors_total`),
|
|
83
|
+
queryTime: components.metrics?.registerMetric(`${logPrefix.replaceAll(':', '_')}_query_time_seconds`)
|
|
86
84
|
}
|
|
87
85
|
|
|
88
86
|
// allow us to stop queries on shut down
|
|
@@ -121,7 +119,7 @@ export class QueryManager implements Startable {
|
|
|
121
119
|
throw new Error('QueryManager not started')
|
|
122
120
|
}
|
|
123
121
|
|
|
124
|
-
const stopQueryTimer = this.metrics?.
|
|
122
|
+
const stopQueryTimer = this.metrics.queryTime?.timer()
|
|
125
123
|
|
|
126
124
|
if (options.signal == null) {
|
|
127
125
|
// don't let queries run forever
|
|
@@ -167,8 +165,7 @@ export class QueryManager implements Startable {
|
|
|
167
165
|
}
|
|
168
166
|
|
|
169
167
|
log('query:start')
|
|
170
|
-
this.queries
|
|
171
|
-
this.metrics?.runningQueries.update(this.queries)
|
|
168
|
+
this.metrics?.queries?.increment()
|
|
172
169
|
|
|
173
170
|
const id = await convertBuffer(key)
|
|
174
171
|
const peers = this.routingTable.closestPeers(id)
|
|
@@ -223,6 +220,10 @@ export class QueryManager implements Startable {
|
|
|
223
220
|
|
|
224
221
|
queryFinished = true
|
|
225
222
|
} catch (err: any) {
|
|
223
|
+
if (!queryFinished) {
|
|
224
|
+
this.metrics?.errors?.increment()
|
|
225
|
+
}
|
|
226
|
+
|
|
226
227
|
if (!this.running && err.name === 'QueryAbortedError') {
|
|
227
228
|
// ignore query aborted errors that were thrown during query manager shutdown
|
|
228
229
|
} else {
|
|
@@ -236,13 +237,7 @@ export class QueryManager implements Startable {
|
|
|
236
237
|
|
|
237
238
|
signal.clear()
|
|
238
239
|
|
|
239
|
-
|
|
240
|
-
this.metrics?.runningQueries.update(this.queries)
|
|
241
|
-
|
|
242
|
-
if (stopQueryTimer != null) {
|
|
243
|
-
stopQueryTimer()
|
|
244
|
-
}
|
|
245
|
-
|
|
240
|
+
stopQueryTimer?.()
|
|
246
241
|
log('query:done in %dms', Date.now() - startTime)
|
|
247
242
|
}
|
|
248
243
|
}
|
package/src/query-self.ts
CHANGED
|
@@ -106,19 +106,27 @@ export class QuerySelf implements Startable {
|
|
|
106
106
|
|
|
107
107
|
if (this.started) {
|
|
108
108
|
this.controller = new AbortController()
|
|
109
|
-
const
|
|
110
|
-
const signal = anySignal([this.controller.signal, timeoutSignal])
|
|
109
|
+
const signals = [this.controller.signal]
|
|
111
110
|
|
|
112
|
-
//
|
|
113
|
-
|
|
111
|
+
// add a shorter timeout if we've already run our initial self query
|
|
112
|
+
if (this.initialQuerySelfHasRun == null) {
|
|
113
|
+
const timeoutSignal = AbortSignal.timeout(this.queryTimeout)
|
|
114
|
+
setMaxListeners(Infinity, timeoutSignal)
|
|
115
|
+
signals.push(timeoutSignal)
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const signal = anySignal(signals)
|
|
119
|
+
setMaxListeners(Infinity, signal, this.controller.signal)
|
|
114
120
|
|
|
115
121
|
try {
|
|
116
122
|
if (this.routingTable.size === 0) {
|
|
117
123
|
this.log('routing table was empty, waiting for some peers before running query')
|
|
118
|
-
// wait to discover at least one DHT peer
|
|
124
|
+
// wait to discover at least one DHT peer that isn't us
|
|
119
125
|
await pEvent(this.routingTable, 'peer:add', {
|
|
120
|
-
signal
|
|
126
|
+
signal,
|
|
127
|
+
filter: (event) => !this.peerId.equals(event.detail)
|
|
121
128
|
})
|
|
129
|
+
this.log('routing table has peers, continuing with query')
|
|
122
130
|
}
|
|
123
131
|
|
|
124
132
|
this.log('run self-query, look for %d peers timing out after %dms', this.count, this.queryTimeout)
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { KEEP_ALIVE } from '@libp2p/interface'
|
|
2
|
+
import { PeerSet } from '@libp2p/peer-collections'
|
|
3
|
+
import { PeerDistanceList } from '../peer-distance-list.js'
|
|
4
|
+
import { convertPeerId } from '../utils.js'
|
|
5
|
+
import type { RoutingTable } from './index.js'
|
|
6
|
+
import type { ComponentLogger, Logger, Metrics, PeerId, PeerStore, Startable } from '@libp2p/interface'
|
|
7
|
+
|
|
8
|
+
export const PEER_SET_SIZE = 20
|
|
9
|
+
export const REFRESH_INTERVAL = 5000
|
|
10
|
+
export const KAD_CLOSE_TAG_NAME = 'kad-close'
|
|
11
|
+
export const KAD_CLOSE_TAG_VALUE = 50
|
|
12
|
+
|
|
13
|
+
export interface ClosestPeersInit {
|
|
14
|
+
logPrefix: string
|
|
15
|
+
routingTable: RoutingTable
|
|
16
|
+
peerSetSize?: number
|
|
17
|
+
refreshInterval?: number
|
|
18
|
+
closeTagName?: string
|
|
19
|
+
closeTagValue?: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface ClosestPeersComponents {
|
|
23
|
+
peerId: PeerId
|
|
24
|
+
peerStore: PeerStore
|
|
25
|
+
metrics?: Metrics
|
|
26
|
+
logger: ComponentLogger
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Contains a list of the kad-closest peers encountered on the network.
|
|
31
|
+
*
|
|
32
|
+
* Once every few seconds, if the list has changed, it tags the closest peers.
|
|
33
|
+
*/
|
|
34
|
+
export class ClosestPeers implements Startable {
|
|
35
|
+
private readonly routingTable: RoutingTable
|
|
36
|
+
private readonly components: ClosestPeersComponents
|
|
37
|
+
private closestPeers: PeerSet
|
|
38
|
+
private newPeers?: PeerDistanceList
|
|
39
|
+
private readonly refreshInterval: number
|
|
40
|
+
private readonly peerSetSize: number
|
|
41
|
+
private timeout?: ReturnType<typeof setTimeout>
|
|
42
|
+
private readonly closeTagName: string
|
|
43
|
+
private readonly closeTagValue: number
|
|
44
|
+
private readonly log: Logger
|
|
45
|
+
|
|
46
|
+
constructor (components: ClosestPeersComponents, init: ClosestPeersInit) {
|
|
47
|
+
this.components = components
|
|
48
|
+
this.log = components.logger.forComponent(`${init.logPrefix}:routing-table`)
|
|
49
|
+
this.routingTable = init.routingTable
|
|
50
|
+
this.refreshInterval = init.refreshInterval ?? REFRESH_INTERVAL
|
|
51
|
+
this.peerSetSize = init.peerSetSize ?? PEER_SET_SIZE
|
|
52
|
+
this.closeTagName = init.closeTagName ?? KAD_CLOSE_TAG_NAME
|
|
53
|
+
this.closeTagValue = init.closeTagValue ?? KAD_CLOSE_TAG_VALUE
|
|
54
|
+
|
|
55
|
+
this.closestPeers = new PeerSet()
|
|
56
|
+
this.onPeerPing = this.onPeerPing.bind(this)
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async start (): Promise<void> {
|
|
60
|
+
const targetKadId = await convertPeerId(this.components.peerId)
|
|
61
|
+
this.newPeers = new PeerDistanceList(targetKadId, this.peerSetSize)
|
|
62
|
+
this.routingTable.addEventListener('peer:ping', this.onPeerPing)
|
|
63
|
+
|
|
64
|
+
this.timeout = setInterval(() => {
|
|
65
|
+
this.updatePeerTags()
|
|
66
|
+
.catch(err => {
|
|
67
|
+
this.log.error('error updating peer tags - %e', err)
|
|
68
|
+
})
|
|
69
|
+
}, this.refreshInterval)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
stop (): void {
|
|
73
|
+
this.routingTable.removeEventListener('peer:ping', this.onPeerPing)
|
|
74
|
+
clearTimeout(this.timeout)
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
onPeerPing (event: CustomEvent<PeerId>): void {
|
|
78
|
+
this.newPeers?.add({ id: event.detail, multiaddrs: [] })
|
|
79
|
+
.catch(err => {
|
|
80
|
+
this.log.error('error adding peer to distance list - %e', err)
|
|
81
|
+
})
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async updatePeerTags (): Promise<void> {
|
|
85
|
+
const newClosest = new PeerSet(this.newPeers?.peers.map(peer => peer.id))
|
|
86
|
+
const added = newClosest.difference(this.closestPeers)
|
|
87
|
+
const removed = this.closestPeers.difference(newClosest)
|
|
88
|
+
this.closestPeers = newClosest
|
|
89
|
+
|
|
90
|
+
await Promise.all([
|
|
91
|
+
...[...added].map(async peerId => {
|
|
92
|
+
await this.components.peerStore.merge(peerId, {
|
|
93
|
+
tags: {
|
|
94
|
+
[this.closeTagName]: {
|
|
95
|
+
value: this.closeTagValue
|
|
96
|
+
},
|
|
97
|
+
[KEEP_ALIVE]: {
|
|
98
|
+
value: 1
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
})
|
|
102
|
+
}),
|
|
103
|
+
...[...removed].map(async peerId => {
|
|
104
|
+
await this.components.peerStore.merge(peerId, {
|
|
105
|
+
tags: {
|
|
106
|
+
[this.closeTagName]: undefined,
|
|
107
|
+
[KEEP_ALIVE]: undefined
|
|
108
|
+
}
|
|
109
|
+
})
|
|
110
|
+
})
|
|
111
|
+
])
|
|
112
|
+
}
|
|
113
|
+
}
|