@libp2p/kad-dht 15.1.1 → 15.1.2-3528df829
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 +1 -1
- package/dist/index.min.js.map +4 -4
- package/dist/src/constants.d.ts +2 -0
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +4 -0
- package/dist/src/constants.js.map +1 -1
- package/dist/src/content-fetching/index.d.ts +2 -2
- package/dist/src/content-fetching/index.d.ts.map +1 -1
- package/dist/src/content-fetching/index.js +6 -6
- package/dist/src/content-fetching/index.js.map +1 -1
- package/dist/src/content-routing/index.js +3 -3
- package/dist/src/content-routing/index.js.map +1 -1
- package/dist/src/errors.d.ts +0 -6
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +0 -9
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +16 -5
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/kad-dht.d.ts +6 -4
- package/dist/src/kad-dht.d.ts.map +1 -1
- package/dist/src/kad-dht.js +23 -13
- package/dist/src/kad-dht.js.map +1 -1
- package/dist/src/peer-distance-list.d.ts +4 -4
- package/dist/src/peer-distance-list.d.ts.map +1 -1
- package/dist/src/peer-distance-list.js +6 -6
- package/dist/src/peer-distance-list.js.map +1 -1
- package/dist/src/peer-routing/index.d.ts +4 -3
- package/dist/src/peer-routing/index.d.ts.map +1 -1
- package/dist/src/peer-routing/index.js +17 -17
- package/dist/src/peer-routing/index.js.map +1 -1
- package/dist/src/providers.d.ts.map +1 -1
- package/dist/src/providers.js +6 -6
- package/dist/src/providers.js.map +1 -1
- package/dist/src/query/manager.d.ts.map +1 -1
- package/dist/src/query/manager.js +3 -1
- package/dist/src/query/manager.js.map +1 -1
- package/dist/src/query/query-path.d.ts.map +1 -1
- package/dist/src/query/query-path.js +11 -5
- package/dist/src/query/query-path.js.map +1 -1
- package/dist/src/query-self.d.ts.map +1 -1
- package/dist/src/query-self.js +1 -0
- package/dist/src/query-self.js.map +1 -1
- package/dist/src/record/validators.d.ts +2 -1
- package/dist/src/record/validators.d.ts.map +1 -1
- package/dist/src/record/validators.js +3 -3
- package/dist/src/record/validators.js.map +1 -1
- package/dist/src/reprovider.d.ts.map +1 -1
- package/dist/src/reprovider.js +11 -7
- package/dist/src/reprovider.js.map +1 -1
- package/dist/src/routing-table/index.d.ts +2 -2
- package/dist/src/routing-table/index.d.ts.map +1 -1
- package/dist/src/routing-table/index.js +14 -13
- package/dist/src/routing-table/index.js.map +1 -1
- package/dist/src/routing-table/k-bucket.d.ts +12 -7
- package/dist/src/routing-table/k-bucket.d.ts.map +1 -1
- package/dist/src/routing-table/k-bucket.js +20 -14
- package/dist/src/routing-table/k-bucket.js.map +1 -1
- package/dist/src/routing-table/refresh.d.ts +5 -5
- package/dist/src/routing-table/refresh.d.ts.map +1 -1
- package/dist/src/routing-table/refresh.js +20 -14
- package/dist/src/routing-table/refresh.js.map +1 -1
- package/dist/src/utils.d.ts +3 -3
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +4 -3
- package/dist/src/utils.js.map +1 -1
- package/package.json +15 -15
- package/src/constants.ts +6 -0
- package/src/content-fetching/index.ts +7 -7
- package/src/content-routing/index.ts +3 -3
- package/src/errors.ts +0 -10
- package/src/index.ts +18 -5
- package/src/kad-dht.ts +26 -14
- package/src/peer-distance-list.ts +7 -7
- package/src/peer-routing/index.ts +18 -17
- package/src/providers.ts +10 -6
- package/src/query/manager.ts +3 -1
- package/src/query/query-path.ts +11 -5
- package/src/query-self.ts +2 -0
- package/src/record/validators.ts +4 -3
- package/src/reprovider.ts +11 -7
- package/src/routing-table/index.ts +14 -13
- package/src/routing-table/k-bucket.ts +30 -18
- package/src/routing-table/refresh.ts +20 -15
- package/src/utils.ts +5 -4
- package/dist/typedoc-urls.json +0 -63
|
@@ -23,6 +23,7 @@ import type { QueryFunc } from '../query/types.js'
|
|
|
23
23
|
import type { RoutingTable } from '../routing-table/index.js'
|
|
24
24
|
import type { ComponentLogger, Logger, Metrics, PeerId, PeerInfo, PeerStore, RoutingOptions } from '@libp2p/interface'
|
|
25
25
|
import type { ConnectionManager } from '@libp2p/interface-internal'
|
|
26
|
+
import type { AbortOptions } from 'it-pushable'
|
|
26
27
|
|
|
27
28
|
export interface PeerRoutingComponents {
|
|
28
29
|
peerId: PeerId
|
|
@@ -68,15 +69,15 @@ export class PeerRouting {
|
|
|
68
69
|
* Look if we are connected to a peer with the given id.
|
|
69
70
|
* Returns its id and addresses, if found, otherwise `undefined`.
|
|
70
71
|
*/
|
|
71
|
-
async findPeerLocal (peer: PeerId): Promise<PeerInfo | undefined> {
|
|
72
|
+
async findPeerLocal (peer: PeerId, options?: AbortOptions): Promise<PeerInfo | undefined> {
|
|
72
73
|
let peerData
|
|
73
|
-
const p = await this.routingTable.find(peer)
|
|
74
|
+
const p = await this.routingTable.find(peer, options)
|
|
74
75
|
|
|
75
76
|
if (p != null) {
|
|
76
77
|
this.log('findPeerLocal found %p in routing table', peer)
|
|
77
78
|
|
|
78
79
|
try {
|
|
79
|
-
peerData = await this.components.peerStore.get(p)
|
|
80
|
+
peerData = await this.components.peerStore.get(p, options)
|
|
80
81
|
} catch (err: any) {
|
|
81
82
|
if (err.name !== 'NotFoundError') {
|
|
82
83
|
throw err
|
|
@@ -86,7 +87,7 @@ export class PeerRouting {
|
|
|
86
87
|
|
|
87
88
|
if (peerData == null) {
|
|
88
89
|
try {
|
|
89
|
-
peerData = await this.components.peerStore.get(peer)
|
|
90
|
+
peerData = await this.components.peerStore.get(peer, options)
|
|
90
91
|
} catch (err: any) {
|
|
91
92
|
if (err.name !== 'NotFoundError') {
|
|
92
93
|
throw err
|
|
@@ -168,7 +169,7 @@ export class PeerRouting {
|
|
|
168
169
|
|
|
169
170
|
if (options.useCache !== false) {
|
|
170
171
|
// Try to find locally
|
|
171
|
-
const pi = await this.findPeerLocal(id)
|
|
172
|
+
const pi = await this.findPeerLocal(id, options)
|
|
172
173
|
|
|
173
174
|
// already got it
|
|
174
175
|
if (pi != null) {
|
|
@@ -240,7 +241,7 @@ export class PeerRouting {
|
|
|
240
241
|
*/
|
|
241
242
|
async * getClosestPeers (key: Uint8Array, options: QueryOptions = {}): AsyncGenerator<QueryEvent> {
|
|
242
243
|
this.log('getClosestPeers to %b', key)
|
|
243
|
-
const kadId = await convertBuffer(key)
|
|
244
|
+
const kadId = await convertBuffer(key, options)
|
|
244
245
|
const peers = new PeerDistanceList(kadId, this.routingTable.kBucketSize)
|
|
245
246
|
const self = this
|
|
246
247
|
|
|
@@ -268,7 +269,7 @@ export class PeerRouting {
|
|
|
268
269
|
for (let { peer, path } of peers.peers) {
|
|
269
270
|
try {
|
|
270
271
|
if (peer.multiaddrs.length === 0) {
|
|
271
|
-
peer = await self.components.peerStore.getInfo(peer.id)
|
|
272
|
+
peer = await self.components.peerStore.getInfo(peer.id, options)
|
|
272
273
|
}
|
|
273
274
|
|
|
274
275
|
if (peer.multiaddrs.length === 0) {
|
|
@@ -277,7 +278,7 @@ export class PeerRouting {
|
|
|
277
278
|
|
|
278
279
|
yield finalPeerEvent({
|
|
279
280
|
from: this.components.peerId,
|
|
280
|
-
peer: await self.components.peerStore.getInfo(peer.id),
|
|
281
|
+
peer: await self.components.peerStore.getInfo(peer.id, options),
|
|
281
282
|
path: {
|
|
282
283
|
index: path.index,
|
|
283
284
|
queued: 0,
|
|
@@ -303,7 +304,7 @@ export class PeerRouting {
|
|
|
303
304
|
if (event.record != null) {
|
|
304
305
|
// We have a record
|
|
305
306
|
try {
|
|
306
|
-
await this._verifyRecordOnline(event.record)
|
|
307
|
+
await this._verifyRecordOnline(event.record, options)
|
|
307
308
|
} catch (err: any) {
|
|
308
309
|
const errMsg = 'invalid record received, discarded'
|
|
309
310
|
this.log(errMsg)
|
|
@@ -326,19 +327,19 @@ export class PeerRouting {
|
|
|
326
327
|
* Verify a record, fetching missing public keys from the network.
|
|
327
328
|
* Throws an error if the record is invalid.
|
|
328
329
|
*/
|
|
329
|
-
async _verifyRecordOnline (record: DHTRecord): Promise<void> {
|
|
330
|
+
async _verifyRecordOnline (record: DHTRecord, options?: AbortOptions): Promise<void> {
|
|
330
331
|
if (record.timeReceived == null) {
|
|
331
332
|
throw new InvalidRecordError('invalid record received')
|
|
332
333
|
}
|
|
333
334
|
|
|
334
|
-
await verifyRecord(this.validators, new Libp2pRecord(record.key, record.value, record.timeReceived))
|
|
335
|
+
await verifyRecord(this.validators, new Libp2pRecord(record.key, record.value, record.timeReceived), options)
|
|
335
336
|
}
|
|
336
337
|
|
|
337
338
|
/**
|
|
338
339
|
* Get the peers in our routing table that are closer than the passed PeerId
|
|
339
340
|
* to the passed key
|
|
340
341
|
*/
|
|
341
|
-
async getCloserPeersOffline (key: Uint8Array, closerThan: PeerId): Promise<PeerInfo[]> {
|
|
342
|
+
async getCloserPeersOffline (key: Uint8Array, closerThan: PeerId, options?: AbortOptions): Promise<PeerInfo[]> {
|
|
342
343
|
const output: PeerInfo[] = []
|
|
343
344
|
|
|
344
345
|
// try getting the peer directly
|
|
@@ -346,7 +347,7 @@ export class PeerRouting {
|
|
|
346
347
|
const multihash = Digest.decode(key)
|
|
347
348
|
const targetPeerId = peerIdFromMultihash(multihash)
|
|
348
349
|
|
|
349
|
-
const peer = await this.components.peerStore.get(targetPeerId)
|
|
350
|
+
const peer = await this.components.peerStore.get(targetPeerId, options)
|
|
350
351
|
|
|
351
352
|
output.push({
|
|
352
353
|
id: peer.id,
|
|
@@ -354,13 +355,13 @@ export class PeerRouting {
|
|
|
354
355
|
})
|
|
355
356
|
} catch {}
|
|
356
357
|
|
|
357
|
-
const keyKadId = await convertBuffer(key)
|
|
358
|
+
const keyKadId = await convertBuffer(key, options)
|
|
358
359
|
const ids = this.routingTable.closestPeers(keyKadId)
|
|
359
|
-
const closerThanKadId = await convertPeerId(closerThan)
|
|
360
|
+
const closerThanKadId = await convertPeerId(closerThan, options)
|
|
360
361
|
const requesterXor = uint8ArrayXor(closerThanKadId, keyKadId)
|
|
361
362
|
|
|
362
363
|
for (const peerId of ids) {
|
|
363
|
-
const peerKadId = await convertPeerId(peerId)
|
|
364
|
+
const peerKadId = await convertPeerId(peerId, options)
|
|
364
365
|
const peerXor = uint8ArrayXor(peerKadId, keyKadId)
|
|
365
366
|
|
|
366
367
|
// only include if peer is closer than requester
|
|
@@ -369,7 +370,7 @@ export class PeerRouting {
|
|
|
369
370
|
}
|
|
370
371
|
|
|
371
372
|
try {
|
|
372
|
-
output.push(await this.components.peerStore.getInfo(peerId))
|
|
373
|
+
output.push(await this.components.peerStore.getInfo(peerId, options))
|
|
373
374
|
} catch (err: any) {
|
|
374
375
|
if (err.name !== 'NotFoundError') {
|
|
375
376
|
throw err
|
package/src/providers.ts
CHANGED
|
@@ -18,6 +18,10 @@ export interface ProvidersComponents {
|
|
|
18
18
|
metrics?: Metrics
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
interface WriteProviderEntryOptions extends AbortOptions {
|
|
22
|
+
time?: Date
|
|
23
|
+
}
|
|
24
|
+
|
|
21
25
|
/**
|
|
22
26
|
* Provides a mechanism to add and remove provider records from the datastore
|
|
23
27
|
*/
|
|
@@ -38,11 +42,11 @@ export class Providers {
|
|
|
38
42
|
* Add a new provider for the given CID
|
|
39
43
|
*/
|
|
40
44
|
async addProvider (cid: CID, provider: PeerId, options?: AbortOptions): Promise<void> {
|
|
41
|
-
const release = await this.lock.readLock()
|
|
45
|
+
const release = await this.lock.readLock(options)
|
|
42
46
|
|
|
43
47
|
try {
|
|
44
48
|
this.log.trace('%p provides %s', provider, cid)
|
|
45
|
-
await this.writeProviderEntry(cid, provider)
|
|
49
|
+
await this.writeProviderEntry(cid, provider, options)
|
|
46
50
|
} finally {
|
|
47
51
|
release()
|
|
48
52
|
}
|
|
@@ -52,7 +56,7 @@ export class Providers {
|
|
|
52
56
|
* Remove a provider for the given CID
|
|
53
57
|
*/
|
|
54
58
|
async removeProvider (cid: CID, provider: PeerId, options?: AbortOptions): Promise<void> {
|
|
55
|
-
const release = await this.lock.writeLock()
|
|
59
|
+
const release = await this.lock.writeLock(options)
|
|
56
60
|
|
|
57
61
|
try {
|
|
58
62
|
const key = toProviderKey(this.datastorePrefix, cid, provider)
|
|
@@ -67,7 +71,7 @@ export class Providers {
|
|
|
67
71
|
* Get a list of providers for the given CID
|
|
68
72
|
*/
|
|
69
73
|
async getProviders (cid: CID, options?: AbortOptions): Promise<PeerId[]> {
|
|
70
|
-
const release = await this.lock.readLock()
|
|
74
|
+
const release = await this.lock.readLock(options)
|
|
71
75
|
|
|
72
76
|
try {
|
|
73
77
|
this.log.trace('get providers for %c', cid)
|
|
@@ -83,9 +87,9 @@ export class Providers {
|
|
|
83
87
|
/**
|
|
84
88
|
* Write a provider into the given store
|
|
85
89
|
*/
|
|
86
|
-
private async writeProviderEntry (cid: CID, peerId: PeerId,
|
|
90
|
+
private async writeProviderEntry (cid: CID, peerId: PeerId, options?: WriteProviderEntryOptions): Promise<void> {
|
|
87
91
|
const key = toProviderKey(this.datastorePrefix, cid, peerId)
|
|
88
|
-
const buffer = varint.encode(time
|
|
92
|
+
const buffer = varint.encode(options?.time?.getTime() ?? Date.now())
|
|
89
93
|
|
|
90
94
|
await this.datastore.put(key, buffer, options)
|
|
91
95
|
}
|
package/src/query/manager.ts
CHANGED
|
@@ -165,7 +165,9 @@ export class QueryManager implements Startable {
|
|
|
165
165
|
|
|
166
166
|
log('query:start')
|
|
167
167
|
|
|
168
|
-
const id = await convertBuffer(key
|
|
168
|
+
const id = await convertBuffer(key, {
|
|
169
|
+
signal
|
|
170
|
+
})
|
|
169
171
|
const peers = this.routingTable.closestPeers(id, this.routingTable.kBucketSize)
|
|
170
172
|
|
|
171
173
|
// split peers into d buckets evenly(ish)
|
package/src/query/query-path.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
+
import { AbortError } from '@libp2p/interface'
|
|
1
2
|
import { Queue } from '@libp2p/utils/queue'
|
|
2
3
|
import { pushable } from 'it-pushable'
|
|
3
4
|
import { xor as uint8ArrayXor } from 'uint8arrays/xor'
|
|
4
5
|
import { xorCompare as uint8ArrayXorCompare } from 'uint8arrays/xor-compare'
|
|
5
|
-
import { QueryAbortedError } from '../errors.js'
|
|
6
6
|
import { convertPeerId, convertBuffer } from '../utils.js'
|
|
7
7
|
import { pathEndedEvent, queryErrorEvent } from './events.js'
|
|
8
8
|
import type { QueryEvent } from '../index.js'
|
|
@@ -106,11 +106,13 @@ export async function * queryPath (options: QueryPathOptions): AsyncGenerator<Qu
|
|
|
106
106
|
|
|
107
107
|
signal.addEventListener('abort', () => {
|
|
108
108
|
queue.abort()
|
|
109
|
-
events.end(new
|
|
109
|
+
events.end(new AbortError())
|
|
110
110
|
})
|
|
111
111
|
|
|
112
112
|
// perform lookups on kadId, not the actual value
|
|
113
|
-
const kadId = await convertBuffer(key
|
|
113
|
+
const kadId = await convertBuffer(key, {
|
|
114
|
+
signal
|
|
115
|
+
})
|
|
114
116
|
|
|
115
117
|
/**
|
|
116
118
|
* Adds the passed peer to the query queue if it's not us and no other path
|
|
@@ -159,7 +161,9 @@ export async function * queryPath (options: QueryPathOptions): AsyncGenerator<Qu
|
|
|
159
161
|
continue
|
|
160
162
|
}
|
|
161
163
|
|
|
162
|
-
const closerPeerKadId = await convertPeerId(closerPeer.id
|
|
164
|
+
const closerPeerKadId = await convertPeerId(closerPeer.id, {
|
|
165
|
+
signal
|
|
166
|
+
})
|
|
163
167
|
const closerPeerXor = uint8ArrayXor(closerPeerKadId, kadId)
|
|
164
168
|
|
|
165
169
|
// only continue query if closer peer is actually closer
|
|
@@ -206,7 +210,9 @@ export async function * queryPath (options: QueryPathOptions): AsyncGenerator<Qu
|
|
|
206
210
|
// begin the query with the starting peers
|
|
207
211
|
await Promise.all(
|
|
208
212
|
startingPeers.map(async startingPeer => {
|
|
209
|
-
queryPeer({ id: startingPeer, multiaddrs: [] }, await convertPeerId(startingPeer
|
|
213
|
+
queryPeer({ id: startingPeer, multiaddrs: [] }, await convertPeerId(startingPeer, {
|
|
214
|
+
signal
|
|
215
|
+
}))
|
|
210
216
|
})
|
|
211
217
|
)
|
|
212
218
|
|
package/src/query-self.ts
CHANGED
package/src/record/validators.ts
CHANGED
|
@@ -4,13 +4,14 @@ import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
|
|
|
4
4
|
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
|
5
5
|
import type { Validators } from '../index.js'
|
|
6
6
|
import type { Libp2pRecord } from '@libp2p/record'
|
|
7
|
+
import type { AbortOptions } from 'it-pushable'
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* Checks a record and ensures it is still valid.
|
|
10
11
|
* It runs the needed validators.
|
|
11
12
|
* If verification fails the returned Promise will reject with the error.
|
|
12
13
|
*/
|
|
13
|
-
export async function verifyRecord (validators: Validators, record: Libp2pRecord): Promise<void> {
|
|
14
|
+
export async function verifyRecord (validators: Validators, record: Libp2pRecord, options?: AbortOptions): Promise<void> {
|
|
14
15
|
const key = record.key
|
|
15
16
|
const keyString = uint8ArrayToString(key)
|
|
16
17
|
const parts = keyString.split('/')
|
|
@@ -26,7 +27,7 @@ export async function verifyRecord (validators: Validators, record: Libp2pRecord
|
|
|
26
27
|
throw new InvalidParametersError(`No validator available for key type "${parts[1]}"`)
|
|
27
28
|
}
|
|
28
29
|
|
|
29
|
-
await validator(key, record.value)
|
|
30
|
+
await validator(key, record.value, options)
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
/**
|
|
@@ -38,7 +39,7 @@ export async function verifyRecord (validators: Validators, record: Libp2pRecord
|
|
|
38
39
|
* @param {Uint8Array} key - A valid key is of the form `'/pk/<keymultihash>'`
|
|
39
40
|
* @param {Uint8Array} publicKey - The public key to validate against (protobuf encoded).
|
|
40
41
|
*/
|
|
41
|
-
const validatePublicKeyRecord = async (key: Uint8Array, publicKey: Uint8Array): Promise<void> => {
|
|
42
|
+
const validatePublicKeyRecord = async (key: Uint8Array, publicKey: Uint8Array, options?: AbortOptions): Promise<void> => {
|
|
42
43
|
if (!(key instanceof Uint8Array)) {
|
|
43
44
|
throw new InvalidParametersError('"key" must be a Uint8Array')
|
|
44
45
|
}
|
package/src/reprovider.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { TypedEventEmitter, setMaxListeners } from '@libp2p/interface'
|
|
|
2
2
|
import { AdaptiveTimeout } from '@libp2p/utils/adaptive-timeout'
|
|
3
3
|
import { Queue } from '@libp2p/utils/queue'
|
|
4
4
|
import drain from 'it-drain'
|
|
5
|
-
import { PROVIDERS_VALIDITY, REPROVIDE_CONCURRENCY, REPROVIDE_INTERVAL, REPROVIDE_MAX_QUEUE_SIZE, REPROVIDE_THRESHOLD } from './constants.js'
|
|
5
|
+
import { PROVIDERS_VALIDITY, REPROVIDE_CONCURRENCY, REPROVIDE_INTERVAL, REPROVIDE_MAX_QUEUE_SIZE, REPROVIDE_THRESHOLD, REPROVIDE_TIMEOUT } from './constants.js'
|
|
6
6
|
import { parseProviderKey, readProviderTime, timeOperationMethod } from './utils.js'
|
|
7
7
|
import type { ContentRouting } from './content-routing/index.js'
|
|
8
8
|
import type { OperationMetrics } from './kad-dht.js'
|
|
@@ -103,7 +103,9 @@ export class Reprovider extends TypedEventEmitter<ReprovideEvents> {
|
|
|
103
103
|
setMaxListeners(Infinity, this.shutdownController.signal)
|
|
104
104
|
|
|
105
105
|
this.timeout = setTimeout(() => {
|
|
106
|
-
this.cleanUp(
|
|
106
|
+
this.cleanUp({
|
|
107
|
+
signal: AbortSignal.timeout(REPROVIDE_TIMEOUT)
|
|
108
|
+
}).catch(err => {
|
|
107
109
|
this.log.error('error running reprovide/cleanup - %e', err)
|
|
108
110
|
})
|
|
109
111
|
}, this.interval)
|
|
@@ -120,8 +122,8 @@ export class Reprovider extends TypedEventEmitter<ReprovideEvents> {
|
|
|
120
122
|
* Check all provider records. Delete them if they have expired, reprovide
|
|
121
123
|
* them if the provider is us and the expiry is within the reprovide window.
|
|
122
124
|
*/
|
|
123
|
-
private async cleanUp (): Promise<void> {
|
|
124
|
-
const release = await this.lock.writeLock()
|
|
125
|
+
private async cleanUp (options?: AbortOptions): Promise<void> {
|
|
126
|
+
const release = await this.lock.writeLock(options)
|
|
125
127
|
|
|
126
128
|
try {
|
|
127
129
|
this.safeDispatchEvent('reprovide:start')
|
|
@@ -165,7 +167,9 @@ export class Reprovider extends TypedEventEmitter<ReprovideEvents> {
|
|
|
165
167
|
|
|
166
168
|
if (this.running) {
|
|
167
169
|
this.timeout = setTimeout(() => {
|
|
168
|
-
this.cleanUp(
|
|
170
|
+
this.cleanUp({
|
|
171
|
+
signal: AbortSignal.timeout(REPROVIDE_TIMEOUT)
|
|
172
|
+
}).catch(err => {
|
|
169
173
|
this.log.error('error running re-provide - %e', err)
|
|
170
174
|
})
|
|
171
175
|
}, this.interval)
|
|
@@ -173,13 +177,13 @@ export class Reprovider extends TypedEventEmitter<ReprovideEvents> {
|
|
|
173
177
|
}
|
|
174
178
|
}
|
|
175
179
|
|
|
176
|
-
private async queueReprovide (cid: CID): Promise<void> {
|
|
180
|
+
private async queueReprovide (cid: CID, options?: AbortOptions): Promise<void> {
|
|
177
181
|
if (!this.running) {
|
|
178
182
|
return
|
|
179
183
|
}
|
|
180
184
|
|
|
181
185
|
this.log.trace('waiting for queue capacity before adding %c to re-provide queue', cid)
|
|
182
|
-
await this.reprovideQueue.onSizeLessThan(this.maxQueueSize)
|
|
186
|
+
await this.reprovideQueue.onSizeLessThan(this.maxQueueSize, options)
|
|
183
187
|
|
|
184
188
|
const existingJob = this.reprovideQueue.queue.find(job => job.options.cid.equals(cid))
|
|
185
189
|
|
|
@@ -139,7 +139,7 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
139
139
|
metricName: `${init.metricsPrefix}_routing_table_ping_new_contact_time_milliseconds`
|
|
140
140
|
})
|
|
141
141
|
|
|
142
|
-
this.kb = new KBucket({
|
|
142
|
+
this.kb = new KBucket(components, {
|
|
143
143
|
kBucketSize: init.kBucketSize,
|
|
144
144
|
prefixLength: init.prefixLength,
|
|
145
145
|
splitThreshold: init.splitThreshold,
|
|
@@ -148,7 +148,8 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
148
148
|
ping: this.pingOldContacts,
|
|
149
149
|
verify: this.verifyNewContact,
|
|
150
150
|
onAdd: this.peerAdded,
|
|
151
|
-
onRemove: this.peerRemoved
|
|
151
|
+
onRemove: this.peerRemoved,
|
|
152
|
+
metricsPrefix: init.metricsPrefix
|
|
152
153
|
})
|
|
153
154
|
|
|
154
155
|
this.closestPeerTagger = new ClosestPeers(this.components, {
|
|
@@ -184,7 +185,7 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
184
185
|
|
|
185
186
|
this.running = true
|
|
186
187
|
|
|
187
|
-
await start(this.closestPeerTagger)
|
|
188
|
+
await start(this.closestPeerTagger, this.kb)
|
|
188
189
|
await this.kb.addSelfPeer(this.components.peerId)
|
|
189
190
|
}
|
|
190
191
|
|
|
@@ -232,12 +233,12 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
232
233
|
|
|
233
234
|
async stop (): Promise<void> {
|
|
234
235
|
this.running = false
|
|
235
|
-
await stop(this.closestPeerTagger)
|
|
236
|
+
await stop(this.closestPeerTagger, this.kb)
|
|
236
237
|
this.pingOldContactQueue.abort()
|
|
237
238
|
this.pingNewContactQueue.abort()
|
|
238
239
|
}
|
|
239
240
|
|
|
240
|
-
private async peerAdded (peer: Peer, bucket: LeafBucket): Promise<void> {
|
|
241
|
+
private async peerAdded (peer: Peer, bucket: LeafBucket, options?: AbortOptions): Promise<void> {
|
|
241
242
|
if (!this.components.peerId.equals(peer.peerId)) {
|
|
242
243
|
await this.components.peerStore.merge(peer.peerId, {
|
|
243
244
|
tags: {
|
|
@@ -245,7 +246,7 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
245
246
|
value: this.peerTagValue
|
|
246
247
|
}
|
|
247
248
|
}
|
|
248
|
-
})
|
|
249
|
+
}, options)
|
|
249
250
|
}
|
|
250
251
|
|
|
251
252
|
this.updateMetrics()
|
|
@@ -253,13 +254,13 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
253
254
|
this.safeDispatchEvent('peer:add', { detail: peer.peerId })
|
|
254
255
|
}
|
|
255
256
|
|
|
256
|
-
private async peerRemoved (peer: Peer, bucket: LeafBucket): Promise<void> {
|
|
257
|
+
private async peerRemoved (peer: Peer, bucket: LeafBucket, options?: AbortOptions): Promise<void> {
|
|
257
258
|
if (!this.components.peerId.equals(peer.peerId)) {
|
|
258
259
|
await this.components.peerStore.merge(peer.peerId, {
|
|
259
260
|
tags: {
|
|
260
261
|
[this.peerTagName]: undefined
|
|
261
262
|
}
|
|
262
|
-
})
|
|
263
|
+
}, options)
|
|
263
264
|
}
|
|
264
265
|
|
|
265
266
|
this.updateMetrics()
|
|
@@ -408,8 +409,8 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
408
409
|
/**
|
|
409
410
|
* Find a specific peer by id
|
|
410
411
|
*/
|
|
411
|
-
async find (peer: PeerId): Promise<PeerId | undefined> {
|
|
412
|
-
const kadId = await utils.convertPeerId(peer)
|
|
412
|
+
async find (peer: PeerId, options?: AbortOptions): Promise<PeerId | undefined> {
|
|
413
|
+
const kadId = await utils.convertPeerId(peer, options)
|
|
413
414
|
return this.kb.get(kadId)?.peerId
|
|
414
415
|
}
|
|
415
416
|
|
|
@@ -451,14 +452,14 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
451
452
|
/**
|
|
452
453
|
* Remove a given peer from the table
|
|
453
454
|
*/
|
|
454
|
-
async remove (peer: PeerId): Promise<void> {
|
|
455
|
+
async remove (peer: PeerId, options?: AbortOptions): Promise<void> {
|
|
455
456
|
if (this.kb == null) {
|
|
456
457
|
throw new Error('RoutingTable is not started')
|
|
457
458
|
}
|
|
458
459
|
|
|
459
|
-
const kadId = await utils.convertPeerId(peer)
|
|
460
|
+
const kadId = await utils.convertPeerId(peer, options)
|
|
460
461
|
|
|
461
|
-
await this.kb.remove(kadId)
|
|
462
|
+
await this.kb.remove(kadId, options)
|
|
462
463
|
}
|
|
463
464
|
|
|
464
465
|
private updateMetrics (): void {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PeerMap } from '@libp2p/peer-collections'
|
|
1
|
+
import { PeerMap, trackedPeerMap } from '@libp2p/peer-collections'
|
|
2
2
|
import map from 'it-map'
|
|
3
3
|
import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
|
|
4
4
|
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
|
@@ -6,7 +6,7 @@ import { xor as uint8ArrayXor } from 'uint8arrays/xor'
|
|
|
6
6
|
import { PeerDistanceList } from '../peer-distance-list.js'
|
|
7
7
|
import { convertPeerId } from '../utils.js'
|
|
8
8
|
import { KBUCKET_SIZE, LAST_PING_THRESHOLD, PING_OLD_CONTACT_COUNT, PREFIX_LENGTH } from './index.js'
|
|
9
|
-
import type { PeerId, AbortOptions } from '@libp2p/interface'
|
|
9
|
+
import type { PeerId, AbortOptions, Metrics } from '@libp2p/interface'
|
|
10
10
|
|
|
11
11
|
export interface PingFunction {
|
|
12
12
|
/**
|
|
@@ -28,21 +28,25 @@ export interface OnAddCallback {
|
|
|
28
28
|
/**
|
|
29
29
|
* Invoked when a new peer is added to the routing tables
|
|
30
30
|
*/
|
|
31
|
-
(peer: Peer, bucket: LeafBucket): Promise<void>
|
|
31
|
+
(peer: Peer, bucket: LeafBucket, options?: AbortOptions): Promise<void>
|
|
32
32
|
}
|
|
33
33
|
|
|
34
34
|
export interface OnRemoveCallback {
|
|
35
35
|
/**
|
|
36
36
|
* Invoked when a peer is evicted from the routing tables
|
|
37
37
|
*/
|
|
38
|
-
(peer: Peer, bucket: LeafBucket): Promise<void>
|
|
38
|
+
(peer: Peer, bucket: LeafBucket, options?: AbortOptions): Promise<void>
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
export interface OnMoveCallback {
|
|
42
42
|
/**
|
|
43
43
|
* Invoked when a peer is moved between buckets in the routing tables
|
|
44
44
|
*/
|
|
45
|
-
(peer: Peer, oldBucket: LeafBucket, newBucket: LeafBucket): Promise<void>
|
|
45
|
+
(peer: Peer, oldBucket: LeafBucket, newBucket: LeafBucket, options?: AbortOptions): Promise<void>
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export interface KBucketComponents {
|
|
49
|
+
metrics?: Metrics
|
|
46
50
|
}
|
|
47
51
|
|
|
48
52
|
export interface KBucketOptions {
|
|
@@ -97,6 +101,7 @@ export interface KBucketOptions {
|
|
|
97
101
|
verify: VerifyFunction
|
|
98
102
|
onAdd?: OnAddCallback
|
|
99
103
|
onRemove?: OnRemoveCallback
|
|
104
|
+
metricsPrefix?: string
|
|
100
105
|
}
|
|
101
106
|
|
|
102
107
|
export interface Peer {
|
|
@@ -143,7 +148,7 @@ export class KBucket {
|
|
|
143
148
|
private readonly onMove?: OnMoveCallback
|
|
144
149
|
private readonly addingPeerMap: PeerMap<Promise<void>>
|
|
145
150
|
|
|
146
|
-
constructor (options: KBucketOptions) {
|
|
151
|
+
constructor (components: KBucketComponents, options: KBucketOptions) {
|
|
147
152
|
this.prefixLength = options.prefixLength ?? PREFIX_LENGTH
|
|
148
153
|
this.kBucketSize = options.kBucketSize ?? KBUCKET_SIZE
|
|
149
154
|
this.splitThreshold = options.splitThreshold ?? this.kBucketSize
|
|
@@ -153,7 +158,10 @@ export class KBucket {
|
|
|
153
158
|
this.verify = options.verify
|
|
154
159
|
this.onAdd = options.onAdd
|
|
155
160
|
this.onRemove = options.onRemove
|
|
156
|
-
this.addingPeerMap =
|
|
161
|
+
this.addingPeerMap = trackedPeerMap({
|
|
162
|
+
name: `${options.metricsPrefix}_adding_peer_map`,
|
|
163
|
+
metrics: components.metrics
|
|
164
|
+
})
|
|
157
165
|
|
|
158
166
|
this.root = {
|
|
159
167
|
prefix: '',
|
|
@@ -162,10 +170,14 @@ export class KBucket {
|
|
|
162
170
|
}
|
|
163
171
|
}
|
|
164
172
|
|
|
165
|
-
|
|
173
|
+
stop (): void {
|
|
174
|
+
this.addingPeerMap.clear()
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
async addSelfPeer (peerId: PeerId, options?: AbortOptions): Promise<void> {
|
|
166
178
|
this.localPeer = {
|
|
167
179
|
peerId,
|
|
168
|
-
kadId: await convertPeerId(peerId),
|
|
180
|
+
kadId: await convertPeerId(peerId, options),
|
|
169
181
|
lastPing: Date.now()
|
|
170
182
|
}
|
|
171
183
|
}
|
|
@@ -176,7 +188,7 @@ export class KBucket {
|
|
|
176
188
|
async add (peerId: PeerId, options?: AbortOptions): Promise<void> {
|
|
177
189
|
const peer = {
|
|
178
190
|
peerId,
|
|
179
|
-
kadId: await convertPeerId(peerId),
|
|
191
|
+
kadId: await convertPeerId(peerId, options),
|
|
180
192
|
lastPing: 0
|
|
181
193
|
}
|
|
182
194
|
|
|
@@ -206,7 +218,7 @@ export class KBucket {
|
|
|
206
218
|
// are there too many peers in the bucket and can we make the trie deeper?
|
|
207
219
|
if (bucket.peers.length === this.splitThreshold && bucket.depth < this.prefixLength) {
|
|
208
220
|
// split the bucket
|
|
209
|
-
await this._split(bucket)
|
|
221
|
+
await this._split(bucket, options)
|
|
210
222
|
|
|
211
223
|
// try again
|
|
212
224
|
await this._add(peer, options)
|
|
@@ -219,7 +231,7 @@ export class KBucket {
|
|
|
219
231
|
// we've ping this peer previously, just add them to the bucket
|
|
220
232
|
if (!needsPing(peer, this.lastPingThreshold)) {
|
|
221
233
|
bucket.peers.push(peer)
|
|
222
|
-
await this.onAdd?.(peer, bucket)
|
|
234
|
+
await this.onAdd?.(peer, bucket, options)
|
|
223
235
|
return
|
|
224
236
|
}
|
|
225
237
|
|
|
@@ -274,7 +286,7 @@ export class KBucket {
|
|
|
274
286
|
|
|
275
287
|
for await (const toEvict of this.ping(toPing, options)) {
|
|
276
288
|
evicted = true
|
|
277
|
-
await this.remove(toEvict.kadId)
|
|
289
|
+
await this.remove(toEvict.kadId, options)
|
|
278
290
|
}
|
|
279
291
|
|
|
280
292
|
// did not evict any peers, cannot add new contact
|
|
@@ -351,14 +363,14 @@ export class KBucket {
|
|
|
351
363
|
*
|
|
352
364
|
* @param {Uint8Array} kadId - The ID of the contact to remove
|
|
353
365
|
*/
|
|
354
|
-
async remove (kadId: Uint8Array): Promise<void> {
|
|
366
|
+
async remove (kadId: Uint8Array, options?: AbortOptions): Promise<void> {
|
|
355
367
|
const bucket = this._determineBucket(kadId)
|
|
356
368
|
const index = this._indexOf(bucket, kadId)
|
|
357
369
|
|
|
358
370
|
if (index > -1) {
|
|
359
371
|
const peer = bucket.peers.splice(index, 1)[0]
|
|
360
372
|
|
|
361
|
-
await this.onRemove?.(peer, bucket)
|
|
373
|
+
await this.onRemove?.(peer, bucket, options)
|
|
362
374
|
}
|
|
363
375
|
}
|
|
364
376
|
|
|
@@ -439,7 +451,7 @@ export class KBucket {
|
|
|
439
451
|
*
|
|
440
452
|
* @param {any} bucket - bucket for splitting
|
|
441
453
|
*/
|
|
442
|
-
private async _split (bucket: LeafBucket): Promise<void> {
|
|
454
|
+
private async _split (bucket: LeafBucket, options?: AbortOptions): Promise<void> {
|
|
443
455
|
// create child buckets
|
|
444
456
|
const left: LeafBucket = {
|
|
445
457
|
prefix: '0',
|
|
@@ -458,10 +470,10 @@ export class KBucket {
|
|
|
458
470
|
|
|
459
471
|
if (bitString[bucket.depth] === '0') {
|
|
460
472
|
left.peers.push(peer)
|
|
461
|
-
await this.onMove?.(peer, bucket, left)
|
|
473
|
+
await this.onMove?.(peer, bucket, left, options)
|
|
462
474
|
} else {
|
|
463
475
|
right.peers.push(peer)
|
|
464
|
-
await this.onMove?.(peer, bucket, right)
|
|
476
|
+
await this.onMove?.(peer, bucket, right, options)
|
|
465
477
|
}
|
|
466
478
|
}
|
|
467
479
|
|