@libp2p/kad-dht 12.0.15 → 12.0.16-1cd5aae11
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 +4 -4
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +1 -1
- package/dist/src/constants.js.map +1 -1
- package/dist/src/content-routing/index.d.ts.map +1 -1
- package/dist/src/content-routing/index.js +3 -2
- package/dist/src/content-routing/index.js.map +1 -1
- package/dist/src/index.d.ts +34 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/network.d.ts +3 -0
- package/dist/src/network.d.ts.map +1 -1
- package/dist/src/network.js +33 -8
- package/dist/src/network.js.map +1 -1
- package/dist/src/peer-list/peer-distance-list.d.ts +13 -4
- package/dist/src/peer-list/peer-distance-list.d.ts.map +1 -1
- package/dist/src/peer-list/peer-distance-list.js +29 -21
- package/dist/src/peer-list/peer-distance-list.js.map +1 -1
- package/dist/src/peer-routing/index.d.ts +5 -5
- package/dist/src/peer-routing/index.d.ts.map +1 -1
- package/dist/src/peer-routing/index.js +15 -24
- package/dist/src/peer-routing/index.js.map +1 -1
- package/dist/src/query/manager.d.ts +3 -0
- package/dist/src/query/manager.d.ts.map +1 -1
- package/dist/src/query/manager.js +14 -5
- package/dist/src/query/manager.js.map +1 -1
- package/dist/src/query/query-path.d.ts +6 -6
- package/dist/src/query/query-path.d.ts.map +1 -1
- package/dist/src/query/query-path.js +32 -20
- package/dist/src/query/query-path.js.map +1 -1
- package/dist/src/routing-table/index.d.ts +11 -5
- package/dist/src/routing-table/index.d.ts.map +1 -1
- package/dist/src/routing-table/index.js +84 -42
- package/dist/src/routing-table/index.js.map +1 -1
- package/dist/src/routing-table/k-bucket.d.ts +80 -115
- package/dist/src/routing-table/k-bucket.d.ts.map +1 -1
- package/dist/src/routing-table/k-bucket.js +165 -311
- 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 +9 -4
- package/dist/src/routing-table/refresh.js.map +1 -1
- package/package.json +14 -16
- package/src/constants.ts +1 -1
- package/src/content-routing/index.ts +3 -2
- package/src/index.ts +37 -1
- package/src/network.ts +38 -9
- package/src/peer-list/peer-distance-list.ts +36 -25
- package/src/peer-routing/index.ts +19 -28
- package/src/query/manager.ts +18 -5
- package/src/query/query-path.ts +46 -30
- package/src/routing-table/index.ts +100 -46
- package/src/routing-table/k-bucket.ts +214 -359
- package/src/routing-table/refresh.ts +10 -4
- package/dist/src/query/utils.d.ts +0 -6
- package/dist/src/query/utils.d.ts.map +0 -1
- package/dist/src/query/utils.js +0 -53
- package/dist/src/query/utils.js.map +0 -1
- package/dist/typedoc-urls.json +0 -55
- package/src/query/utils.ts +0 -64
package/src/query/query-path.ts
CHANGED
|
@@ -1,19 +1,16 @@
|
|
|
1
|
-
import { setMaxListeners } from '@libp2p/interface'
|
|
1
|
+
import { CodeError, setMaxListeners } from '@libp2p/interface'
|
|
2
|
+
import { Queue } from '@libp2p/utils/queue'
|
|
2
3
|
import { anySignal } from 'any-signal'
|
|
3
|
-
import
|
|
4
|
-
import {
|
|
5
|
-
import { xor } from 'uint8arrays/xor'
|
|
4
|
+
import { xor as uint8ArrayXor } from 'uint8arrays/xor'
|
|
5
|
+
import { xorCompare as uint8ArrayXorCompare } from 'uint8arrays/xor-compare'
|
|
6
6
|
import { convertPeerId, convertBuffer } from '../utils.js'
|
|
7
7
|
import { queryErrorEvent } from './events.js'
|
|
8
|
-
import { queueToGenerator } from './utils.js'
|
|
9
|
-
import type { CleanUpEvents } from './manager.js'
|
|
10
8
|
import type { QueryEvent } from '../index.js'
|
|
11
9
|
import type { QueryFunc } from '../query/types.js'
|
|
12
|
-
import type { Logger,
|
|
10
|
+
import type { Logger, PeerId, RoutingOptions, AbortOptions } from '@libp2p/interface'
|
|
11
|
+
import type { ConnectionManager } from '@libp2p/interface-internal'
|
|
13
12
|
import type { PeerSet } from '@libp2p/peer-collections'
|
|
14
13
|
|
|
15
|
-
const MAX_XOR = BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF')
|
|
16
|
-
|
|
17
14
|
export interface QueryPathOptions extends RoutingOptions {
|
|
18
15
|
/**
|
|
19
16
|
* What are we trying to find
|
|
@@ -55,11 +52,6 @@ export interface QueryPathOptions extends RoutingOptions {
|
|
|
55
52
|
*/
|
|
56
53
|
numPaths: number
|
|
57
54
|
|
|
58
|
-
/**
|
|
59
|
-
* will emit a 'cleanup' event if the caller exits the for..await of early
|
|
60
|
-
*/
|
|
61
|
-
cleanUp: TypedEventTarget<CleanUpEvents>
|
|
62
|
-
|
|
63
55
|
/**
|
|
64
56
|
* A timeout for queryFunc in ms
|
|
65
57
|
*/
|
|
@@ -74,6 +66,15 @@ export interface QueryPathOptions extends RoutingOptions {
|
|
|
74
66
|
* Set of peers seen by this and other paths
|
|
75
67
|
*/
|
|
76
68
|
peersSeen: PeerSet
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* The libp2p connection manager
|
|
72
|
+
*/
|
|
73
|
+
connectionManager: ConnectionManager
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
interface QueryQueueOptions extends AbortOptions {
|
|
77
|
+
distance: Uint8Array
|
|
77
78
|
}
|
|
78
79
|
|
|
79
80
|
/**
|
|
@@ -81,11 +82,12 @@ export interface QueryPathOptions extends RoutingOptions {
|
|
|
81
82
|
* every peer encountered that we have not seen before
|
|
82
83
|
*/
|
|
83
84
|
export async function * queryPath (options: QueryPathOptions): AsyncGenerator<QueryEvent, void, undefined> {
|
|
84
|
-
const { key, startingPeer, ourPeerId, signal, query, alpha, pathIndex, numPaths,
|
|
85
|
+
const { key, startingPeer, ourPeerId, signal, query, alpha, pathIndex, numPaths, queryFuncTimeout, log, peersSeen, connectionManager } = options
|
|
85
86
|
// Only ALPHA node/value lookups are allowed at any given time for each process
|
|
86
87
|
// https://github.com/libp2p/specs/tree/master/kad-dht#alpha-concurrency-parameter-%CE%B1
|
|
87
|
-
const queue = new Queue({
|
|
88
|
-
concurrency: alpha
|
|
88
|
+
const queue = new Queue<QueryEvent | undefined, QueryQueueOptions>({
|
|
89
|
+
concurrency: alpha,
|
|
90
|
+
sort: (a, b) => uint8ArrayXorCompare(a.options.distance, b.options.distance)
|
|
89
91
|
})
|
|
90
92
|
|
|
91
93
|
// perform lookups on kadId, not the actual value
|
|
@@ -102,7 +104,7 @@ export async function * queryPath (options: QueryPathOptions): AsyncGenerator<Qu
|
|
|
102
104
|
|
|
103
105
|
peersSeen.add(peer)
|
|
104
106
|
|
|
105
|
-
const peerXor =
|
|
107
|
+
const peerXor = uint8ArrayXor(peerKadId, kadId)
|
|
106
108
|
|
|
107
109
|
queue.add(async () => {
|
|
108
110
|
const signals = [signal]
|
|
@@ -141,11 +143,16 @@ export async function * queryPath (options: QueryPathOptions): AsyncGenerator<Qu
|
|
|
141
143
|
continue
|
|
142
144
|
}
|
|
143
145
|
|
|
146
|
+
if (!(await connectionManager.isDialable(closerPeer.multiaddrs))) { // eslint-disable-line max-depth
|
|
147
|
+
log('not querying undialable peer')
|
|
148
|
+
continue
|
|
149
|
+
}
|
|
150
|
+
|
|
144
151
|
const closerPeerKadId = await convertPeerId(closerPeer.id)
|
|
145
|
-
const closerPeerXor =
|
|
152
|
+
const closerPeerXor = uint8ArrayXor(closerPeerKadId, kadId)
|
|
146
153
|
|
|
147
154
|
// only continue query if closer peer is actually closer
|
|
148
|
-
if (closerPeerXor
|
|
155
|
+
if (uint8ArrayXorCompare(closerPeerXor, peerXor) !== -1) { // eslint-disable-line max-depth
|
|
149
156
|
log('skipping %p as they are not closer to %b than %p', closerPeer.id, key, peer)
|
|
150
157
|
continue
|
|
151
158
|
}
|
|
@@ -154,7 +161,10 @@ export async function * queryPath (options: QueryPathOptions): AsyncGenerator<Qu
|
|
|
154
161
|
queryPeer(closerPeer.id, closerPeerKadId)
|
|
155
162
|
}
|
|
156
163
|
}
|
|
157
|
-
|
|
164
|
+
|
|
165
|
+
queue.safeDispatchEvent('completed', {
|
|
166
|
+
detail: event
|
|
167
|
+
})
|
|
158
168
|
}
|
|
159
169
|
} catch (err: any) {
|
|
160
170
|
if (!signal.aborted) {
|
|
@@ -167,13 +177,7 @@ export async function * queryPath (options: QueryPathOptions): AsyncGenerator<Qu
|
|
|
167
177
|
compoundSignal.clear()
|
|
168
178
|
}
|
|
169
179
|
}, {
|
|
170
|
-
|
|
171
|
-
// subtract it from MAX_XOR because higher priority values execute sooner
|
|
172
|
-
|
|
173
|
-
// @ts-expect-error this is supposed to be a Number but it's ok to use BigInts
|
|
174
|
-
// as long as all priorities are BigInts since we won't mix BigInts and Number
|
|
175
|
-
// values in arithmetic operations
|
|
176
|
-
priority: MAX_XOR - peerXor
|
|
180
|
+
distance: peerXor
|
|
177
181
|
}).catch(err => {
|
|
178
182
|
log.error(err)
|
|
179
183
|
})
|
|
@@ -182,6 +186,18 @@ export async function * queryPath (options: QueryPathOptions): AsyncGenerator<Qu
|
|
|
182
186
|
// begin the query with the starting peer
|
|
183
187
|
queryPeer(startingPeer, await convertPeerId(startingPeer))
|
|
184
188
|
|
|
185
|
-
|
|
186
|
-
|
|
189
|
+
try {
|
|
190
|
+
// yield results as they come in
|
|
191
|
+
for await (const event of queue.toGenerator({ signal })) {
|
|
192
|
+
if (event != null) {
|
|
193
|
+
yield event
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
} catch (err) {
|
|
197
|
+
if (signal.aborted) {
|
|
198
|
+
throw new CodeError('Query aborted', 'ERR_QUERY_ABORTED')
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
throw err
|
|
202
|
+
}
|
|
187
203
|
}
|
|
@@ -4,19 +4,22 @@ import { PeerQueue } from '@libp2p/utils/peer-queue'
|
|
|
4
4
|
import { pbStream } from 'it-protobuf-stream'
|
|
5
5
|
import { Message, MessageType } from '../message/dht.js'
|
|
6
6
|
import * as utils from '../utils.js'
|
|
7
|
-
import { KBucket, type PingEventDetails } from './k-bucket.js'
|
|
7
|
+
import { KBucket, isLeafBucket, type Bucket, type PingEventDetails } from './k-bucket.js'
|
|
8
8
|
import type { ComponentLogger, Logger, Metric, Metrics, PeerId, PeerStore, Startable, Stream } from '@libp2p/interface'
|
|
9
9
|
import type { ConnectionManager } from '@libp2p/interface-internal'
|
|
10
10
|
|
|
11
11
|
export const KAD_CLOSE_TAG_NAME = 'kad-close'
|
|
12
12
|
export const KAD_CLOSE_TAG_VALUE = 50
|
|
13
13
|
export const KBUCKET_SIZE = 20
|
|
14
|
+
export const PREFIX_LENGTH = 32
|
|
14
15
|
export const PING_TIMEOUT = 10000
|
|
15
16
|
export const PING_CONCURRENCY = 10
|
|
16
17
|
|
|
17
18
|
export interface RoutingTableInit {
|
|
18
19
|
logPrefix: string
|
|
19
20
|
protocol: string
|
|
21
|
+
prefixLength?: number
|
|
22
|
+
splitThreshold?: number
|
|
20
23
|
kBucketSize?: number
|
|
21
24
|
pingTimeout?: number
|
|
22
25
|
pingConcurrency?: number
|
|
@@ -48,6 +51,8 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
48
51
|
|
|
49
52
|
private readonly log: Logger
|
|
50
53
|
private readonly components: RoutingTableComponents
|
|
54
|
+
private readonly prefixLength: number
|
|
55
|
+
private readonly splitThreshold: number
|
|
51
56
|
private readonly pingTimeout: number
|
|
52
57
|
private readonly pingConcurrency: number
|
|
53
58
|
private running: boolean
|
|
@@ -56,26 +61,29 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
56
61
|
private readonly tagValue: number
|
|
57
62
|
private readonly metrics?: {
|
|
58
63
|
routingTableSize: Metric
|
|
64
|
+
routingTableKadBucketTotal: Metric
|
|
65
|
+
routingTableKadBucketAverageOccupancy: Metric
|
|
66
|
+
routingTableKadBucketMaxDepth: Metric
|
|
59
67
|
}
|
|
60
68
|
|
|
61
69
|
constructor (components: RoutingTableComponents, init: RoutingTableInit) {
|
|
62
70
|
super()
|
|
63
71
|
|
|
64
|
-
const { kBucketSize, pingTimeout, logPrefix, pingConcurrency, protocol, tagName, tagValue } = init
|
|
65
|
-
|
|
66
72
|
this.components = components
|
|
67
|
-
this.log = components.logger.forComponent(`${logPrefix}:routing-table`)
|
|
68
|
-
this.kBucketSize = kBucketSize ?? KBUCKET_SIZE
|
|
69
|
-
this.pingTimeout = pingTimeout ?? PING_TIMEOUT
|
|
70
|
-
this.pingConcurrency = pingConcurrency ?? PING_CONCURRENCY
|
|
73
|
+
this.log = components.logger.forComponent(`${init.logPrefix}:routing-table`)
|
|
74
|
+
this.kBucketSize = init.kBucketSize ?? KBUCKET_SIZE
|
|
75
|
+
this.pingTimeout = init.pingTimeout ?? PING_TIMEOUT
|
|
76
|
+
this.pingConcurrency = init.pingConcurrency ?? PING_CONCURRENCY
|
|
71
77
|
this.running = false
|
|
72
|
-
this.protocol = protocol
|
|
73
|
-
this.tagName = tagName ?? KAD_CLOSE_TAG_NAME
|
|
74
|
-
this.tagValue = tagValue ?? KAD_CLOSE_TAG_VALUE
|
|
78
|
+
this.protocol = init.protocol
|
|
79
|
+
this.tagName = init.tagName ?? KAD_CLOSE_TAG_NAME
|
|
80
|
+
this.tagValue = init.tagValue ?? KAD_CLOSE_TAG_VALUE
|
|
81
|
+
this.prefixLength = init.prefixLength ?? PREFIX_LENGTH
|
|
82
|
+
this.splitThreshold = init.splitThreshold ?? KBUCKET_SIZE
|
|
75
83
|
|
|
76
84
|
this.pingQueue = new PeerQueue({
|
|
77
85
|
concurrency: this.pingConcurrency,
|
|
78
|
-
metricName: `${logPrefix.replaceAll(':', '_')}_ping_queue`,
|
|
86
|
+
metricName: `${init.logPrefix.replaceAll(':', '_')}_ping_queue`,
|
|
79
87
|
metrics: this.components.metrics
|
|
80
88
|
})
|
|
81
89
|
this.pingQueue.addEventListener('error', evt => {
|
|
@@ -84,7 +92,10 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
84
92
|
|
|
85
93
|
if (this.components.metrics != null) {
|
|
86
94
|
this.metrics = {
|
|
87
|
-
routingTableSize: this.components.metrics.registerMetric(`${logPrefix.replaceAll(':', '_')}_routing_table_size`)
|
|
95
|
+
routingTableSize: this.components.metrics.registerMetric(`${init.logPrefix.replaceAll(':', '_')}_routing_table_size`),
|
|
96
|
+
routingTableKadBucketTotal: this.components.metrics.registerMetric(`${init.logPrefix.replaceAll(':', '_')}_routing_table_kad_bucket_total`),
|
|
97
|
+
routingTableKadBucketAverageOccupancy: this.components.metrics.registerMetric(`${init.logPrefix.replaceAll(':', '_')}_routing_table_kad_bucket_average_occupancy`),
|
|
98
|
+
routingTableKadBucketMaxDepth: this.components.metrics.registerMetric(`${init.logPrefix.replaceAll(':', '_')}_routing_table_kad_bucket_max_depth`)
|
|
88
99
|
}
|
|
89
100
|
}
|
|
90
101
|
}
|
|
@@ -97,8 +108,13 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
97
108
|
this.running = true
|
|
98
109
|
|
|
99
110
|
const kBuck = new KBucket({
|
|
100
|
-
|
|
101
|
-
|
|
111
|
+
localPeer: {
|
|
112
|
+
kadId: await utils.convertPeerId(this.components.peerId),
|
|
113
|
+
peerId: this.components.peerId
|
|
114
|
+
},
|
|
115
|
+
kBucketSize: this.kBucketSize,
|
|
116
|
+
prefixLength: this.prefixLength,
|
|
117
|
+
splitThreshold: this.splitThreshold,
|
|
102
118
|
numberOfNodesToPing: 1
|
|
103
119
|
})
|
|
104
120
|
this.kb = kBuck
|
|
@@ -110,6 +126,20 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
110
126
|
})
|
|
111
127
|
})
|
|
112
128
|
|
|
129
|
+
let peerStorePeers = 0
|
|
130
|
+
|
|
131
|
+
// add existing peers from the peer store to routing table
|
|
132
|
+
for (const peer of await this.components.peerStore.all()) {
|
|
133
|
+
if (peer.protocols.includes(this.protocol)) {
|
|
134
|
+
const id = await utils.convertPeerId(peer.id)
|
|
135
|
+
|
|
136
|
+
this.kb.add({ kadId: id, peerId: peer.id })
|
|
137
|
+
peerStorePeers++
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
this.log('added %d peer store peers to the routing table', peerStorePeers)
|
|
142
|
+
|
|
113
143
|
// tag kad-close peers
|
|
114
144
|
this._tagPeers(kBuck)
|
|
115
145
|
}
|
|
@@ -130,7 +160,7 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
130
160
|
|
|
131
161
|
const updatePeerTags = utils.debounce(() => {
|
|
132
162
|
const newClosest = new PeerSet(
|
|
133
|
-
kBuck.closest(kBuck.
|
|
163
|
+
kBuck.closest(kBuck.localPeer.kadId, KBUCKET_SIZE)
|
|
134
164
|
)
|
|
135
165
|
const addedPeers = newClosest.difference(kClosest)
|
|
136
166
|
const removedPeers = kClosest.difference(newClosest)
|
|
@@ -165,12 +195,12 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
165
195
|
kBuck.addEventListener('added', (evt) => {
|
|
166
196
|
updatePeerTags()
|
|
167
197
|
|
|
168
|
-
this.safeDispatchEvent('peer:add', { detail: evt.detail.
|
|
198
|
+
this.safeDispatchEvent('peer:add', { detail: evt.detail.peerId })
|
|
169
199
|
})
|
|
170
200
|
kBuck.addEventListener('removed', (evt) => {
|
|
171
201
|
updatePeerTags()
|
|
172
202
|
|
|
173
|
-
this.safeDispatchEvent('peer:remove', { detail: evt.detail.
|
|
203
|
+
this.safeDispatchEvent('peer:remove', { detail: evt.detail.peerId })
|
|
174
204
|
})
|
|
175
205
|
}
|
|
176
206
|
|
|
@@ -197,7 +227,7 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
197
227
|
const results = await Promise.all(
|
|
198
228
|
oldContacts.map(async oldContact => {
|
|
199
229
|
// if a previous ping wants us to ping this contact, re-use the result
|
|
200
|
-
const pingJob = this.pingQueue.find(oldContact.
|
|
230
|
+
const pingJob = this.pingQueue.find(oldContact.peerId)
|
|
201
231
|
|
|
202
232
|
if (pingJob != null) {
|
|
203
233
|
return pingJob.join()
|
|
@@ -211,8 +241,8 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
211
241
|
signal: AbortSignal.timeout(this.pingTimeout)
|
|
212
242
|
}
|
|
213
243
|
|
|
214
|
-
this.log('pinging old contact %p', oldContact.
|
|
215
|
-
const connection = await this.components.connectionManager.openConnection(oldContact.
|
|
244
|
+
this.log('pinging old contact %p', oldContact.peerId)
|
|
245
|
+
const connection = await this.components.connectionManager.openConnection(oldContact.peerId, options)
|
|
216
246
|
stream = await connection.newStream(this.protocol, options)
|
|
217
247
|
|
|
218
248
|
const pb = pbStream(stream)
|
|
@@ -232,9 +262,9 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
232
262
|
if (this.running && this.kb != null) {
|
|
233
263
|
// only evict peers if we are still running, otherwise we evict
|
|
234
264
|
// when dialing is cancelled due to shutdown in progress
|
|
235
|
-
this.log.error('could not ping peer %p', oldContact.
|
|
236
|
-
this.log('evicting old contact after ping failed %p', oldContact.
|
|
237
|
-
this.kb.remove(oldContact.
|
|
265
|
+
this.log.error('could not ping peer %p', oldContact.peerId, err)
|
|
266
|
+
this.log('evicting old contact after ping failed %p', oldContact.peerId)
|
|
267
|
+
this.kb.remove(oldContact.kadId)
|
|
238
268
|
}
|
|
239
269
|
|
|
240
270
|
stream?.abort(err)
|
|
@@ -244,7 +274,7 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
244
274
|
this.metrics?.routingTableSize.update(this.size)
|
|
245
275
|
}
|
|
246
276
|
}, {
|
|
247
|
-
peerId: oldContact.
|
|
277
|
+
peerId: oldContact.peerId
|
|
248
278
|
})
|
|
249
279
|
})
|
|
250
280
|
)
|
|
@@ -254,7 +284,7 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
254
284
|
.length
|
|
255
285
|
|
|
256
286
|
if (this.running && responded < oldContacts.length && this.kb != null) {
|
|
257
|
-
this.log('adding new contact %p', newContact.
|
|
287
|
+
this.log('adding new contact %p', newContact.peerId)
|
|
258
288
|
this.kb.add(newContact)
|
|
259
289
|
}
|
|
260
290
|
}
|
|
@@ -277,20 +307,14 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
277
307
|
*/
|
|
278
308
|
async find (peer: PeerId): Promise<PeerId | undefined> {
|
|
279
309
|
const key = await utils.convertPeerId(peer)
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
if (closest != null && peer.equals(closest)) {
|
|
283
|
-
return closest
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
return undefined
|
|
310
|
+
return this.kb?.get(key)?.peerId
|
|
287
311
|
}
|
|
288
312
|
|
|
289
313
|
/**
|
|
290
|
-
* Retrieve the closest peers to the given
|
|
314
|
+
* Retrieve the closest peers to the given kadId
|
|
291
315
|
*/
|
|
292
|
-
closestPeer (
|
|
293
|
-
const res = this.closestPeers(
|
|
316
|
+
closestPeer (kadId: Uint8Array): PeerId | undefined {
|
|
317
|
+
const res = this.closestPeers(kadId, 1)
|
|
294
318
|
|
|
295
319
|
if (res.length > 0) {
|
|
296
320
|
return res[0]
|
|
@@ -300,33 +324,31 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
300
324
|
}
|
|
301
325
|
|
|
302
326
|
/**
|
|
303
|
-
* Retrieve the `count`-closest peers to the given
|
|
327
|
+
* Retrieve the `count`-closest peers to the given kadId
|
|
304
328
|
*/
|
|
305
|
-
closestPeers (
|
|
329
|
+
closestPeers (kadId: Uint8Array, count = this.kBucketSize): PeerId[] {
|
|
306
330
|
if (this.kb == null) {
|
|
307
331
|
return []
|
|
308
332
|
}
|
|
309
333
|
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
return closest.map(p => p.peer)
|
|
334
|
+
return [...this.kb.closest(kadId, count)]
|
|
313
335
|
}
|
|
314
336
|
|
|
315
337
|
/**
|
|
316
338
|
* Add or update the routing table with the given peer
|
|
317
339
|
*/
|
|
318
|
-
async add (
|
|
340
|
+
async add (peerId: PeerId): Promise<void> {
|
|
319
341
|
if (this.kb == null) {
|
|
320
342
|
throw new Error('RoutingTable is not started')
|
|
321
343
|
}
|
|
322
344
|
|
|
323
|
-
const
|
|
345
|
+
const kadId = await utils.convertPeerId(peerId)
|
|
324
346
|
|
|
325
|
-
this.kb.add({
|
|
347
|
+
this.kb.add({ kadId, peerId })
|
|
326
348
|
|
|
327
|
-
this.log('added %p with kad id %b',
|
|
349
|
+
this.log('added %p with kad id %b', peerId, kadId)
|
|
328
350
|
|
|
329
|
-
this.
|
|
351
|
+
this.updateMetrics()
|
|
330
352
|
}
|
|
331
353
|
|
|
332
354
|
/**
|
|
@@ -341,6 +363,38 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
341
363
|
|
|
342
364
|
this.kb.remove(id)
|
|
343
365
|
|
|
344
|
-
this.
|
|
366
|
+
this.updateMetrics()
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
private updateMetrics (): void {
|
|
370
|
+
if (this.metrics == null || this.kb == null) {
|
|
371
|
+
return
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
let size = 0
|
|
375
|
+
let buckets = 0
|
|
376
|
+
let maxDepth = 0
|
|
377
|
+
|
|
378
|
+
function count (bucket: Bucket): void {
|
|
379
|
+
if (isLeafBucket(bucket)) {
|
|
380
|
+
if (bucket.depth > maxDepth) {
|
|
381
|
+
maxDepth = bucket.depth
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
buckets++
|
|
385
|
+
size += bucket.peers.length
|
|
386
|
+
return
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
count(bucket.left)
|
|
390
|
+
count(bucket.right)
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
count(this.kb.root)
|
|
394
|
+
|
|
395
|
+
this.metrics.routingTableSize.update(size)
|
|
396
|
+
this.metrics.routingTableKadBucketTotal.update(buckets)
|
|
397
|
+
this.metrics.routingTableKadBucketAverageOccupancy.update(Math.round(size / buckets))
|
|
398
|
+
this.metrics.routingTableKadBucketMaxDepth.update(maxDepth)
|
|
345
399
|
}
|
|
346
400
|
}
|