@libp2p/kad-dht 15.0.1 → 15.0.2-185b23eac
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 -15
- package/dist/index.min.js.map +7 -0
- package/dist/src/content-fetching/index.d.ts +4 -4
- package/dist/src/content-fetching/index.d.ts.map +1 -1
- package/dist/src/content-fetching/index.js +14 -7
- package/dist/src/content-fetching/index.js.map +1 -1
- package/dist/src/content-routing/index.d.ts.map +1 -1
- package/dist/src/content-routing/index.js +8 -4
- package/dist/src/content-routing/index.js.map +1 -1
- package/dist/src/index.d.ts +9 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/kad-dht.js +2 -2
- package/dist/src/kad-dht.js.map +1 -1
- package/dist/src/network.d.ts +10 -2
- package/dist/src/network.d.ts.map +1 -1
- package/dist/src/network.js +10 -11
- package/dist/src/network.js.map +1 -1
- package/dist/src/peer-distance-list.d.ts +9 -3
- package/dist/src/peer-distance-list.d.ts.map +1 -1
- package/dist/src/peer-distance-list.js +6 -5
- package/dist/src/peer-distance-list.js.map +1 -1
- package/dist/src/peer-routing/index.d.ts +3 -3
- package/dist/src/peer-routing/index.d.ts.map +1 -1
- package/dist/src/peer-routing/index.js +33 -15
- package/dist/src/peer-routing/index.js.map +1 -1
- package/dist/src/providers.d.ts +4 -4
- package/dist/src/providers.d.ts.map +1 -1
- package/dist/src/providers.js +8 -8
- package/dist/src/providers.js.map +1 -1
- package/dist/src/query/events.d.ts +8 -7
- package/dist/src/query/events.d.ts.map +1 -1
- package/dist/src/query/events.js +0 -9
- package/dist/src/query/events.js.map +1 -1
- package/dist/src/query/manager.d.ts +2 -0
- package/dist/src/query/manager.d.ts.map +1 -1
- package/dist/src/query/manager.js +23 -8
- package/dist/src/query/manager.js.map +1 -1
- package/dist/src/query/query-path.d.ts +3 -3
- package/dist/src/query/query-path.d.ts.map +1 -1
- package/dist/src/query/query-path.js +8 -16
- package/dist/src/query/query-path.js.map +1 -1
- package/dist/src/query/types.d.ts +1 -1
- package/dist/src/query/types.d.ts.map +1 -1
- package/dist/src/query-self.d.ts +2 -3
- package/dist/src/query-self.d.ts.map +1 -1
- package/dist/src/query-self.js +11 -14
- package/dist/src/query-self.js.map +1 -1
- package/dist/src/routing-table/closest-peers.js +1 -1
- package/dist/src/routing-table/closest-peers.js.map +1 -1
- package/dist/src/routing-table/k-bucket.js +1 -1
- package/dist/src/routing-table/k-bucket.js.map +1 -1
- package/package.json +12 -12
- package/src/content-fetching/index.ts +15 -8
- package/src/content-routing/index.ts +8 -4
- package/src/index.ts +9 -2
- package/src/kad-dht.ts +2 -2
- package/src/network.ts +18 -11
- package/src/peer-distance-list.ts +9 -7
- package/src/peer-routing/index.ts +34 -16
- package/src/providers.ts +9 -9
- package/src/query/events.ts +8 -19
- package/src/query/manager.ts +26 -8
- package/src/query/query-path.ts +11 -19
- package/src/query/types.ts +1 -1
- package/src/query-self.ts +15 -17
- package/src/routing-table/closest-peers.ts +1 -1
- package/src/routing-table/k-bucket.ts +1 -1
- package/dist/typedoc-urls.json +0 -59
|
@@ -6,6 +6,7 @@ import type { PeerId, PeerInfo } from '@libp2p/interface'
|
|
|
6
6
|
interface PeerDistance {
|
|
7
7
|
peer: PeerInfo
|
|
8
8
|
distance: Uint8Array
|
|
9
|
+
path: number
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
/**
|
|
@@ -40,30 +41,31 @@ export class PeerDistanceList {
|
|
|
40
41
|
/**
|
|
41
42
|
* The peers in the list, in order of distance from the origin key
|
|
42
43
|
*/
|
|
43
|
-
get peers ():
|
|
44
|
-
return this.peerDistances
|
|
44
|
+
get peers (): PeerDistance[] {
|
|
45
|
+
return [...this.peerDistances]
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
/**
|
|
48
49
|
* Add a peerId to the list.
|
|
49
50
|
*/
|
|
50
|
-
async add (peer: PeerInfo): Promise<void> {
|
|
51
|
+
async add (peer: PeerInfo, path: number = -1): Promise<void> {
|
|
51
52
|
const dhtKey = await convertPeerId(peer.id)
|
|
52
53
|
|
|
53
|
-
this.addWithKadId(peer, dhtKey)
|
|
54
|
+
this.addWithKadId(peer, dhtKey, path)
|
|
54
55
|
}
|
|
55
56
|
|
|
56
57
|
/**
|
|
57
58
|
* Add a peerId to the list.
|
|
58
59
|
*/
|
|
59
|
-
addWithKadId (peer: PeerInfo, kadId: Uint8Array): void {
|
|
60
|
+
addWithKadId (peer: PeerInfo, kadId: Uint8Array, path: number = -1): void {
|
|
60
61
|
if (this.peerDistances.find(pd => pd.peer.id.equals(peer.id)) != null) {
|
|
61
62
|
return
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
const el = {
|
|
65
|
+
const el: PeerDistance = {
|
|
65
66
|
peer,
|
|
66
|
-
distance: uint8ArrayXor(this.originDhtKey, kadId)
|
|
67
|
+
distance: uint8ArrayXor(this.originDhtKey, kadId),
|
|
68
|
+
path
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
let added = false
|
|
@@ -18,7 +18,7 @@ import { verifyRecord } from '../record/validators.js'
|
|
|
18
18
|
import { convertBuffer, convertPeerId, keyForPublicKey } from '../utils.js'
|
|
19
19
|
import type { DHTRecord, FinalPeerEvent, QueryEvent, Validators } from '../index.js'
|
|
20
20
|
import type { Message } from '../message/dht.js'
|
|
21
|
-
import type { Network } from '../network.js'
|
|
21
|
+
import type { Network, SendMessageOptions } from '../network.js'
|
|
22
22
|
import type { QueryManager, QueryOptions } from '../query/manager.js'
|
|
23
23
|
import type { QueryFunc } from '../query/types.js'
|
|
24
24
|
import type { RoutingTable } from '../routing-table/index.js'
|
|
@@ -110,7 +110,7 @@ export class PeerRouting {
|
|
|
110
110
|
/**
|
|
111
111
|
* Get a value via rpc call for the given parameters
|
|
112
112
|
*/
|
|
113
|
-
async * _getValueSingle (peer: PeerId, key: Uint8Array, options:
|
|
113
|
+
async * _getValueSingle (peer: PeerId, key: Uint8Array, options: SendMessageOptions): AsyncGenerator<QueryEvent> {
|
|
114
114
|
const msg: Partial<Message> = {
|
|
115
115
|
type: MessageType.GET_VALUE,
|
|
116
116
|
key
|
|
@@ -125,7 +125,10 @@ export class PeerRouting {
|
|
|
125
125
|
async * getPublicKeyFromNode (peer: PeerId, options: RoutingOptions = {}): AsyncGenerator<QueryEvent> {
|
|
126
126
|
const pkKey = keyForPublicKey(peer)
|
|
127
127
|
|
|
128
|
-
for await (const event of this._getValueSingle(peer, pkKey,
|
|
128
|
+
for await (const event of this._getValueSingle(peer, pkKey, {
|
|
129
|
+
...options,
|
|
130
|
+
path: -1
|
|
131
|
+
})) {
|
|
129
132
|
yield event
|
|
130
133
|
|
|
131
134
|
if (event.name === 'PEER_RESPONSE' && event.record != null) {
|
|
@@ -166,7 +169,8 @@ export class PeerRouting {
|
|
|
166
169
|
this.log('found local')
|
|
167
170
|
yield finalPeerEvent({
|
|
168
171
|
from: this.peerId,
|
|
169
|
-
peer: pi
|
|
172
|
+
peer: pi,
|
|
173
|
+
path: -1
|
|
170
174
|
}, options)
|
|
171
175
|
return
|
|
172
176
|
}
|
|
@@ -177,7 +181,7 @@ export class PeerRouting {
|
|
|
177
181
|
if (options.useNetwork !== false) {
|
|
178
182
|
const self = this // eslint-disable-line @typescript-eslint/no-this-alias
|
|
179
183
|
|
|
180
|
-
const findPeerQuery: QueryFunc = async function * ({ peer, signal }) {
|
|
184
|
+
const findPeerQuery: QueryFunc = async function * ({ peer, signal, path }) {
|
|
181
185
|
const request: Partial<Message> = {
|
|
182
186
|
type: MessageType.FIND_NODE,
|
|
183
187
|
key: id.toMultihash().bytes
|
|
@@ -185,7 +189,8 @@ export class PeerRouting {
|
|
|
185
189
|
|
|
186
190
|
for await (const event of self.network.sendRequest(peer, request, {
|
|
187
191
|
...options,
|
|
188
|
-
signal
|
|
192
|
+
signal,
|
|
193
|
+
path
|
|
189
194
|
})) {
|
|
190
195
|
yield event
|
|
191
196
|
|
|
@@ -194,7 +199,11 @@ export class PeerRouting {
|
|
|
194
199
|
|
|
195
200
|
// found the peer
|
|
196
201
|
if (match != null) {
|
|
197
|
-
yield finalPeerEvent({
|
|
202
|
+
yield finalPeerEvent({
|
|
203
|
+
from: event.from,
|
|
204
|
+
peer: match,
|
|
205
|
+
path: event.path
|
|
206
|
+
}, options)
|
|
198
207
|
}
|
|
199
208
|
}
|
|
200
209
|
}
|
|
@@ -210,7 +219,10 @@ export class PeerRouting {
|
|
|
210
219
|
}
|
|
211
220
|
|
|
212
221
|
if (!foundPeer) {
|
|
213
|
-
yield queryErrorEvent({
|
|
222
|
+
yield queryErrorEvent({
|
|
223
|
+
from: this.peerId,
|
|
224
|
+
error: new NotFoundError('Not found')
|
|
225
|
+
}, options)
|
|
214
226
|
}
|
|
215
227
|
}
|
|
216
228
|
|
|
@@ -225,9 +237,9 @@ export class PeerRouting {
|
|
|
225
237
|
const self = this // eslint-disable-line @typescript-eslint/no-this-alias
|
|
226
238
|
|
|
227
239
|
const peers = new PeerDistanceList(kadId, this.routingTable.kBucketSize)
|
|
228
|
-
await Promise.all(tablePeers.map(async peer => { await peers.add({ id: peer, multiaddrs: [] }) }))
|
|
240
|
+
await Promise.all(tablePeers.map(async peer => { await peers.add({ id: peer, multiaddrs: [] }, -1) }))
|
|
229
241
|
|
|
230
|
-
const getCloserPeersQuery: QueryFunc = async function * ({ peer, signal }) {
|
|
242
|
+
const getCloserPeersQuery: QueryFunc = async function * ({ peer, signal, path }) {
|
|
231
243
|
self.log('closerPeersSingle %s from %p', uint8ArrayToString(key, 'base32'), peer)
|
|
232
244
|
const request: Partial<Message> = {
|
|
233
245
|
type: MessageType.FIND_NODE,
|
|
@@ -236,14 +248,15 @@ export class PeerRouting {
|
|
|
236
248
|
|
|
237
249
|
yield * self.network.sendRequest(peer, request, {
|
|
238
250
|
...options,
|
|
239
|
-
signal
|
|
251
|
+
signal,
|
|
252
|
+
path
|
|
240
253
|
})
|
|
241
254
|
}
|
|
242
255
|
|
|
243
256
|
for await (const event of this.queryManager.run(key, getCloserPeersQuery, options)) {
|
|
244
257
|
if (event.name === 'PEER_RESPONSE') {
|
|
245
258
|
await Promise.all(event.closer.map(async peerData => {
|
|
246
|
-
await peers.add(peerData)
|
|
259
|
+
await peers.add(peerData, event.path)
|
|
247
260
|
}))
|
|
248
261
|
}
|
|
249
262
|
|
|
@@ -252,10 +265,11 @@ export class PeerRouting {
|
|
|
252
265
|
|
|
253
266
|
this.log('found %d peers close to %b', peers.length, key)
|
|
254
267
|
|
|
255
|
-
for (const peer of peers.peers) {
|
|
268
|
+
for (const { peer, path } of peers.peers) {
|
|
256
269
|
yield finalPeerEvent({
|
|
257
270
|
from: this.peerId,
|
|
258
|
-
peer
|
|
271
|
+
peer,
|
|
272
|
+
path
|
|
259
273
|
}, options)
|
|
260
274
|
}
|
|
261
275
|
}
|
|
@@ -266,7 +280,7 @@ export class PeerRouting {
|
|
|
266
280
|
*
|
|
267
281
|
* Note: The peerStore is updated with new addresses found for the given peer.
|
|
268
282
|
*/
|
|
269
|
-
async * getValueOrPeers (peer: PeerId, key: Uint8Array, options:
|
|
283
|
+
async * getValueOrPeers (peer: PeerId, key: Uint8Array, options: SendMessageOptions): AsyncGenerator<QueryEvent> {
|
|
270
284
|
for await (const event of this._getValueSingle(peer, key, options)) {
|
|
271
285
|
if (event.name === 'PEER_RESPONSE') {
|
|
272
286
|
if (event.record != null) {
|
|
@@ -277,7 +291,11 @@ export class PeerRouting {
|
|
|
277
291
|
const errMsg = 'invalid record received, discarded'
|
|
278
292
|
this.log(errMsg)
|
|
279
293
|
|
|
280
|
-
yield queryErrorEvent({
|
|
294
|
+
yield queryErrorEvent({
|
|
295
|
+
from: event.from,
|
|
296
|
+
error: new QueryError(errMsg),
|
|
297
|
+
path: options.path
|
|
298
|
+
}, options)
|
|
281
299
|
continue
|
|
282
300
|
}
|
|
283
301
|
}
|
package/src/providers.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { PeerMap } from '@libp2p/peer-collections'
|
|
2
2
|
import * as varint from 'uint8-varint'
|
|
3
3
|
import { parseProviderKey, readProviderTime, toProviderKey } from './utils.js'
|
|
4
|
-
import type { ComponentLogger, Logger, Metrics, PeerId } from '@libp2p/interface'
|
|
4
|
+
import type { AbortOptions, ComponentLogger, Logger, Metrics, PeerId } from '@libp2p/interface'
|
|
5
5
|
import type { Datastore } from 'interface-datastore'
|
|
6
6
|
import type { Mortice } from 'mortice'
|
|
7
7
|
import type { CID } from 'multiformats'
|
|
@@ -37,7 +37,7 @@ export class Providers {
|
|
|
37
37
|
/**
|
|
38
38
|
* Add a new provider for the given CID
|
|
39
39
|
*/
|
|
40
|
-
async addProvider (cid: CID, provider: PeerId): Promise<void> {
|
|
40
|
+
async addProvider (cid: CID, provider: PeerId, options?: AbortOptions): Promise<void> {
|
|
41
41
|
const release = await this.lock.readLock()
|
|
42
42
|
|
|
43
43
|
try {
|
|
@@ -51,7 +51,7 @@ export class Providers {
|
|
|
51
51
|
/**
|
|
52
52
|
* Remove a provider for the given CID
|
|
53
53
|
*/
|
|
54
|
-
async removeProvider (cid: CID, provider: PeerId): Promise<void> {
|
|
54
|
+
async removeProvider (cid: CID, provider: PeerId, options?: AbortOptions): Promise<void> {
|
|
55
55
|
const release = await this.lock.writeLock()
|
|
56
56
|
|
|
57
57
|
try {
|
|
@@ -66,12 +66,12 @@ export class Providers {
|
|
|
66
66
|
/**
|
|
67
67
|
* Get a list of providers for the given CID
|
|
68
68
|
*/
|
|
69
|
-
async getProviders (cid: CID): Promise<PeerId[]> {
|
|
69
|
+
async getProviders (cid: CID, options?: AbortOptions): Promise<PeerId[]> {
|
|
70
70
|
const release = await this.lock.readLock()
|
|
71
71
|
|
|
72
72
|
try {
|
|
73
73
|
this.log('get providers for %c', cid)
|
|
74
|
-
const provs = await this.loadProviders(cid)
|
|
74
|
+
const provs = await this.loadProviders(cid, options)
|
|
75
75
|
this.log('got %d providers for %c', provs.size, cid)
|
|
76
76
|
|
|
77
77
|
return [...provs.keys()]
|
|
@@ -83,21 +83,21 @@ export class Providers {
|
|
|
83
83
|
/**
|
|
84
84
|
* Write a provider into the given store
|
|
85
85
|
*/
|
|
86
|
-
private async writeProviderEntry (cid: CID, peerId: PeerId, time: Date = new Date()): Promise<void> {
|
|
86
|
+
private async writeProviderEntry (cid: CID, peerId: PeerId, time: Date = new Date(), options?: AbortOptions): Promise<void> {
|
|
87
87
|
const key = toProviderKey(this.datastorePrefix, cid, peerId)
|
|
88
88
|
const buffer = varint.encode(time.getTime())
|
|
89
89
|
|
|
90
|
-
await this.datastore.put(key, buffer)
|
|
90
|
+
await this.datastore.put(key, buffer, options)
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
/**
|
|
94
94
|
* Load providers for the given CID from the store
|
|
95
95
|
*/
|
|
96
|
-
private async loadProviders (cid: CID): Promise<PeerMap<Date>> {
|
|
96
|
+
private async loadProviders (cid: CID, options?: AbortOptions): Promise<PeerMap<Date>> {
|
|
97
97
|
const providers = new PeerMap<Date>()
|
|
98
98
|
const key = toProviderKey(this.datastorePrefix, cid)
|
|
99
99
|
|
|
100
|
-
for await (const entry of this.datastore.query({ prefix: key.toString() })) {
|
|
100
|
+
for await (const entry of this.datastore.query({ prefix: key.toString() }, options)) {
|
|
101
101
|
const { peerId } = parseProviderKey(entry.key)
|
|
102
102
|
providers.set(peerId, readProviderTime(entry.value))
|
|
103
103
|
}
|
package/src/query/events.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { MessageType, SendQueryEvent, PeerResponseEvent,
|
|
1
|
+
import type { MessageType, SendQueryEvent, PeerResponseEvent, AddPeerEvent, ValueEvent, ProviderEvent, QueryErrorEvent, FinalPeerEvent } from '../index.js'
|
|
2
2
|
import type { PeerId, PeerInfo } from '@libp2p/interface'
|
|
3
3
|
import type { Libp2pRecord } from '@libp2p/record'
|
|
4
4
|
import type { ProgressOptions } from 'progress-events'
|
|
@@ -6,6 +6,7 @@ import type { ProgressOptions } from 'progress-events'
|
|
|
6
6
|
export interface QueryEventFields {
|
|
7
7
|
to: PeerId
|
|
8
8
|
type: MessageType
|
|
9
|
+
path: number
|
|
9
10
|
}
|
|
10
11
|
|
|
11
12
|
export function sendQueryEvent (fields: QueryEventFields, options: ProgressOptions = {}): SendQueryEvent {
|
|
@@ -25,6 +26,7 @@ export function sendQueryEvent (fields: QueryEventFields, options: ProgressOptio
|
|
|
25
26
|
export interface PeerResponseEventFields {
|
|
26
27
|
from: PeerId
|
|
27
28
|
messageType: MessageType
|
|
29
|
+
path: number
|
|
28
30
|
closer?: PeerInfo[]
|
|
29
31
|
providers?: PeerInfo[]
|
|
30
32
|
record?: Libp2pRecord
|
|
@@ -48,6 +50,7 @@ export function peerResponseEvent (fields: PeerResponseEventFields, options: Pro
|
|
|
48
50
|
export interface FinalPeerEventFields {
|
|
49
51
|
from: PeerId
|
|
50
52
|
peer: PeerInfo
|
|
53
|
+
path: number
|
|
51
54
|
}
|
|
52
55
|
|
|
53
56
|
export function finalPeerEvent (fields: FinalPeerEventFields, options: ProgressOptions = {}): FinalPeerEvent {
|
|
@@ -65,6 +68,7 @@ export function finalPeerEvent (fields: FinalPeerEventFields, options: ProgressO
|
|
|
65
68
|
export interface ErrorEventFields {
|
|
66
69
|
from: PeerId
|
|
67
70
|
error: Error
|
|
71
|
+
path?: number
|
|
68
72
|
}
|
|
69
73
|
|
|
70
74
|
export function queryErrorEvent (fields: ErrorEventFields, options: ProgressOptions = {}): QueryErrorEvent {
|
|
@@ -113,11 +117,12 @@ export function valueEvent (fields: ValueEventFields, options: ProgressOptions =
|
|
|
113
117
|
return event
|
|
114
118
|
}
|
|
115
119
|
|
|
116
|
-
export interface
|
|
120
|
+
export interface AddPeerEventFields {
|
|
117
121
|
peer: PeerId
|
|
122
|
+
path: number
|
|
118
123
|
}
|
|
119
124
|
|
|
120
|
-
export function addPeerEvent (fields:
|
|
125
|
+
export function addPeerEvent (fields: AddPeerEventFields, options: ProgressOptions = {}): AddPeerEvent {
|
|
121
126
|
const event: AddPeerEvent = {
|
|
122
127
|
...fields,
|
|
123
128
|
name: 'ADD_PEER',
|
|
@@ -128,19 +133,3 @@ export function addPeerEvent (fields: PeerEventFields, options: ProgressOptions
|
|
|
128
133
|
|
|
129
134
|
return event
|
|
130
135
|
}
|
|
131
|
-
|
|
132
|
-
export interface DialPeerEventFields {
|
|
133
|
-
peer: PeerId
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
export function dialPeerEvent (fields: DialPeerEventFields, options: ProgressOptions = {}): DialPeerEvent {
|
|
137
|
-
const event: DialPeerEvent = {
|
|
138
|
-
...fields,
|
|
139
|
-
name: 'DIAL_PEER',
|
|
140
|
-
type: 7
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
options.onProgress?.(new CustomEvent('kad-dht:query:dial-peer', { detail: event }))
|
|
144
|
-
|
|
145
|
-
return event
|
|
146
|
-
}
|
package/src/query/manager.ts
CHANGED
|
@@ -2,6 +2,7 @@ import { setMaxListeners } from '@libp2p/interface'
|
|
|
2
2
|
import { PeerSet } from '@libp2p/peer-collections'
|
|
3
3
|
import { anySignal } from 'any-signal'
|
|
4
4
|
import merge from 'it-merge'
|
|
5
|
+
import { pEvent } from 'p-event'
|
|
5
6
|
import { raceSignal } from 'race-signal'
|
|
6
7
|
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
|
7
8
|
import {
|
|
@@ -26,6 +27,7 @@ export interface QueryManagerInit {
|
|
|
26
27
|
disjointPaths?: number
|
|
27
28
|
alpha?: number
|
|
28
29
|
initialQuerySelfHasRun: DeferredPromise<void>
|
|
30
|
+
allowQueryWithZeroPeers?: boolean
|
|
29
31
|
routingTable: RoutingTable
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -59,6 +61,7 @@ export class QueryManager implements Startable {
|
|
|
59
61
|
private readonly routingTable: RoutingTable
|
|
60
62
|
private initialQuerySelfHasRun?: DeferredPromise<void>
|
|
61
63
|
private readonly logPrefix: string
|
|
64
|
+
private readonly allowQueryWithZeroPeers: boolean
|
|
62
65
|
|
|
63
66
|
constructor (components: QueryManagerComponents, init: QueryManagerInit) {
|
|
64
67
|
this.logPrefix = init.logPrefix
|
|
@@ -69,6 +72,7 @@ export class QueryManager implements Startable {
|
|
|
69
72
|
this.logger = components.logger
|
|
70
73
|
this.peerId = components.peerId
|
|
71
74
|
this.connectionManager = components.connectionManager
|
|
75
|
+
this.allowQueryWithZeroPeers = init.allowQueryWithZeroPeers ?? false
|
|
72
76
|
|
|
73
77
|
// allow us to stop queries on shut down
|
|
74
78
|
this.shutDownController = new AbortController()
|
|
@@ -146,6 +150,16 @@ export class QueryManager implements Startable {
|
|
|
146
150
|
let queryFinished = false
|
|
147
151
|
|
|
148
152
|
try {
|
|
153
|
+
if (this.routingTable.size === 0 && !this.allowQueryWithZeroPeers) {
|
|
154
|
+
log('routing table was empty, waiting for some peers before running%s query', options.isSelfQuery === true ? ' self' : '')
|
|
155
|
+
// wait to discover at least one DHT peer that isn't us
|
|
156
|
+
await pEvent(this.routingTable, 'peer:add', {
|
|
157
|
+
signal,
|
|
158
|
+
filter: (event) => !this.peerId.equals(event.detail)
|
|
159
|
+
})
|
|
160
|
+
log('routing table has peers, continuing with%s query', options.isSelfQuery === true ? ' self' : '')
|
|
161
|
+
}
|
|
162
|
+
|
|
149
163
|
if (options.isSelfQuery !== true && this.initialQuerySelfHasRun != null) {
|
|
150
164
|
log('waiting for initial query-self query before continuing')
|
|
151
165
|
|
|
@@ -161,7 +175,7 @@ export class QueryManager implements Startable {
|
|
|
161
175
|
const peersToQuery = peers.slice(0, Math.min(this.disjointPaths, peers.length))
|
|
162
176
|
|
|
163
177
|
if (peers.length === 0) {
|
|
164
|
-
log.error('
|
|
178
|
+
log.error('running query with no peers')
|
|
165
179
|
return
|
|
166
180
|
}
|
|
167
181
|
|
|
@@ -177,7 +191,7 @@ export class QueryManager implements Startable {
|
|
|
177
191
|
ourPeerId: this.peerId,
|
|
178
192
|
signal,
|
|
179
193
|
query: queryFunc,
|
|
180
|
-
|
|
194
|
+
path: index,
|
|
181
195
|
numPaths: peersToQuery.length,
|
|
182
196
|
alpha: this.alpha,
|
|
183
197
|
queryFuncTimeout: options.queryFuncTimeout,
|
|
@@ -197,22 +211,26 @@ export class QueryManager implements Startable {
|
|
|
197
211
|
if (event.name === 'PEER_RESPONSE') {
|
|
198
212
|
for (const peer of [...event.closer, ...event.providers]) {
|
|
199
213
|
// eslint-disable-next-line max-depth
|
|
200
|
-
if (!(await this.connectionManager.isDialable(peer.multiaddrs
|
|
214
|
+
if (!(await this.connectionManager.isDialable(peer.multiaddrs, {
|
|
215
|
+
signal
|
|
216
|
+
}))) {
|
|
201
217
|
continue
|
|
202
218
|
}
|
|
203
219
|
|
|
204
|
-
await this.routingTable.add(peer.id
|
|
220
|
+
await this.routingTable.add(peer.id, {
|
|
221
|
+
signal
|
|
222
|
+
})
|
|
205
223
|
}
|
|
206
224
|
}
|
|
207
225
|
|
|
208
226
|
yield event
|
|
227
|
+
signal.throwIfAborted()
|
|
209
228
|
}
|
|
210
229
|
|
|
211
230
|
queryFinished = true
|
|
212
|
-
} catch (err
|
|
213
|
-
if (
|
|
214
|
-
// ignore
|
|
215
|
-
} else {
|
|
231
|
+
} catch (err) {
|
|
232
|
+
if (this.running) {
|
|
233
|
+
// ignore errors thrown during shut down
|
|
216
234
|
throw err
|
|
217
235
|
}
|
|
218
236
|
} finally {
|
package/src/query/query-path.ts
CHANGED
|
@@ -3,7 +3,6 @@ import { Queue } from '@libp2p/utils/queue'
|
|
|
3
3
|
import { anySignal } from 'any-signal'
|
|
4
4
|
import { xor as uint8ArrayXor } from 'uint8arrays/xor'
|
|
5
5
|
import { xorCompare as uint8ArrayXorCompare } from 'uint8arrays/xor-compare'
|
|
6
|
-
import { QueryAbortedError } from '../errors.js'
|
|
7
6
|
import { convertPeerId, convertBuffer } from '../utils.js'
|
|
8
7
|
import { queryErrorEvent } from './events.js'
|
|
9
8
|
import type { QueryEvent } from '../index.js'
|
|
@@ -44,12 +43,12 @@ export interface QueryPathOptions extends RoutingOptions {
|
|
|
44
43
|
alpha: number
|
|
45
44
|
|
|
46
45
|
/**
|
|
47
|
-
*
|
|
46
|
+
* The index within `k` this path represents
|
|
48
47
|
*/
|
|
49
|
-
|
|
48
|
+
path: number
|
|
50
49
|
|
|
51
50
|
/**
|
|
52
|
-
* How many
|
|
51
|
+
* How many disjoint paths are in this query
|
|
53
52
|
*/
|
|
54
53
|
numPaths: number
|
|
55
54
|
|
|
@@ -83,7 +82,7 @@ interface QueryQueueOptions extends AbortOptions {
|
|
|
83
82
|
* every peer encountered that we have not seen before
|
|
84
83
|
*/
|
|
85
84
|
export async function * queryPath (options: QueryPathOptions): AsyncGenerator<QueryEvent, void, undefined> {
|
|
86
|
-
const { key, startingPeer, ourPeerId, signal, query, alpha,
|
|
85
|
+
const { key, startingPeer, ourPeerId, signal, query, alpha, path, numPaths, queryFuncTimeout, log, peersSeen, connectionManager } = options
|
|
87
86
|
// Only ALPHA node/value lookups are allowed at any given time for each process
|
|
88
87
|
// https://github.com/libp2p/specs/tree/master/kad-dht#alpha-concurrency-parameter-%CE%B1
|
|
89
88
|
const queue = new Queue<QueryEvent | undefined, QueryQueueOptions>({
|
|
@@ -125,7 +124,7 @@ export async function * queryPath (options: QueryPathOptions): AsyncGenerator<Qu
|
|
|
125
124
|
key,
|
|
126
125
|
peer,
|
|
127
126
|
signal: compoundSignal,
|
|
128
|
-
|
|
127
|
+
path,
|
|
129
128
|
numPaths
|
|
130
129
|
})) {
|
|
131
130
|
if (compoundSignal.aborted) {
|
|
@@ -172,7 +171,8 @@ export async function * queryPath (options: QueryPathOptions): AsyncGenerator<Qu
|
|
|
172
171
|
if (!signal.aborted) {
|
|
173
172
|
return queryErrorEvent({
|
|
174
173
|
from: peer,
|
|
175
|
-
error: err
|
|
174
|
+
error: err,
|
|
175
|
+
path
|
|
176
176
|
}, options)
|
|
177
177
|
}
|
|
178
178
|
} finally {
|
|
@@ -188,18 +188,10 @@ export async function * queryPath (options: QueryPathOptions): AsyncGenerator<Qu
|
|
|
188
188
|
// begin the query with the starting peer
|
|
189
189
|
queryPeer(startingPeer, await convertPeerId(startingPeer))
|
|
190
190
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
yield event
|
|
196
|
-
}
|
|
191
|
+
// yield results as they come in
|
|
192
|
+
for await (const event of queue.toGenerator({ signal })) {
|
|
193
|
+
if (event != null) {
|
|
194
|
+
yield event
|
|
197
195
|
}
|
|
198
|
-
} catch (err) {
|
|
199
|
-
if (signal.aborted) {
|
|
200
|
-
throw new QueryAbortedError('Query aborted')
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
throw err
|
|
204
196
|
}
|
|
205
197
|
}
|
package/src/query/types.ts
CHANGED
|
@@ -9,7 +9,7 @@ export interface QueryContext {
|
|
|
9
9
|
// if this signal emits an 'abort' event, any long-lived processes or requests started as part of this query should be terminated
|
|
10
10
|
signal: AbortSignal
|
|
11
11
|
// which disjoint path we are following
|
|
12
|
-
|
|
12
|
+
path: number
|
|
13
13
|
// the total number of disjoint paths being executed
|
|
14
14
|
numPaths: number
|
|
15
15
|
}
|
package/src/query-self.ts
CHANGED
|
@@ -4,18 +4,16 @@ import length from 'it-length'
|
|
|
4
4
|
import { pipe } from 'it-pipe'
|
|
5
5
|
import take from 'it-take'
|
|
6
6
|
import pDefer from 'p-defer'
|
|
7
|
-
import { pEvent } from 'p-event'
|
|
8
7
|
import { QUERY_SELF_INTERVAL, QUERY_SELF_TIMEOUT, K, QUERY_SELF_INITIAL_INTERVAL } from './constants.js'
|
|
9
8
|
import { timeOperationMethod } from './utils.js'
|
|
10
9
|
import type { OperationMetrics } from './kad-dht.js'
|
|
11
10
|
import type { PeerRouting } from './peer-routing/index.js'
|
|
12
|
-
import type { RoutingTable } from './routing-table/index.js'
|
|
13
11
|
import type { ComponentLogger, Logger, Metrics, PeerId, Startable } from '@libp2p/interface'
|
|
14
12
|
import type { DeferredPromise } from 'p-defer'
|
|
13
|
+
|
|
15
14
|
export interface QuerySelfInit {
|
|
16
15
|
logPrefix: string
|
|
17
16
|
peerRouting: PeerRouting
|
|
18
|
-
routingTable: RoutingTable
|
|
19
17
|
count?: number
|
|
20
18
|
interval?: number
|
|
21
19
|
initialInterval?: number
|
|
@@ -28,6 +26,7 @@ export interface QuerySelfComponents {
|
|
|
28
26
|
peerId: PeerId
|
|
29
27
|
logger: ComponentLogger
|
|
30
28
|
metrics?: Metrics
|
|
29
|
+
events: EventTarget
|
|
31
30
|
}
|
|
32
31
|
|
|
33
32
|
/**
|
|
@@ -37,7 +36,7 @@ export class QuerySelf implements Startable {
|
|
|
37
36
|
private readonly log: Logger
|
|
38
37
|
private readonly peerId: PeerId
|
|
39
38
|
private readonly peerRouting: PeerRouting
|
|
40
|
-
private readonly
|
|
39
|
+
private readonly events: EventTarget
|
|
41
40
|
private readonly count: number
|
|
42
41
|
private readonly interval: number
|
|
43
42
|
private readonly initialInterval: number
|
|
@@ -51,9 +50,9 @@ export class QuerySelf implements Startable {
|
|
|
51
50
|
constructor (components: QuerySelfComponents, init: QuerySelfInit) {
|
|
52
51
|
this.peerId = components.peerId
|
|
53
52
|
this.log = components.logger.forComponent(`${init.logPrefix}:query-self`)
|
|
53
|
+
this.events = components.events
|
|
54
54
|
this.running = false
|
|
55
55
|
this.peerRouting = init.peerRouting
|
|
56
|
-
this.routingTable = init.routingTable
|
|
57
56
|
this.count = init.count ?? K
|
|
58
57
|
this.interval = init.interval ?? QUERY_SELF_INTERVAL
|
|
59
58
|
this.initialInterval = init.initialInterval ?? QUERY_SELF_INITIAL_INTERVAL
|
|
@@ -122,20 +121,10 @@ export class QuerySelf implements Startable {
|
|
|
122
121
|
setMaxListeners(Infinity, signal, this.controller.signal)
|
|
123
122
|
|
|
124
123
|
try {
|
|
125
|
-
if (this.routingTable.size === 0) {
|
|
126
|
-
this.log('routing table was empty, waiting for some peers before running query')
|
|
127
|
-
// wait to discover at least one DHT peer that isn't us
|
|
128
|
-
await pEvent(this.routingTable, 'peer:add', {
|
|
129
|
-
signal,
|
|
130
|
-
filter: (event) => !this.peerId.equals(event.detail)
|
|
131
|
-
})
|
|
132
|
-
this.log('routing table has peers, continuing with query')
|
|
133
|
-
}
|
|
134
|
-
|
|
135
124
|
this.log('run self-query, look for %d peers timing out after %dms', this.count, this.queryTimeout)
|
|
136
125
|
const start = Date.now()
|
|
137
126
|
|
|
138
|
-
const
|
|
127
|
+
const peers = await pipe(
|
|
139
128
|
this.peerRouting.getClosestPeers(this.peerId.toMultihash().bytes, {
|
|
140
129
|
signal,
|
|
141
130
|
isSelfQuery: true
|
|
@@ -144,7 +133,16 @@ export class QuerySelf implements Startable {
|
|
|
144
133
|
async (source) => length(source)
|
|
145
134
|
)
|
|
146
135
|
|
|
147
|
-
|
|
136
|
+
const duration = Date.now() - start
|
|
137
|
+
|
|
138
|
+
this.log('self-query found %d peers in %dms', peers, duration)
|
|
139
|
+
|
|
140
|
+
this.events.dispatchEvent(new CustomEvent('kad-dht:query:self', {
|
|
141
|
+
detail: {
|
|
142
|
+
peers,
|
|
143
|
+
duration
|
|
144
|
+
}
|
|
145
|
+
}))
|
|
148
146
|
} catch (err: any) {
|
|
149
147
|
this.log.error('self-query error', err)
|
|
150
148
|
} finally {
|
|
@@ -91,7 +91,7 @@ export class ClosestPeers implements Startable {
|
|
|
91
91
|
}
|
|
92
92
|
|
|
93
93
|
async updatePeerTags (): Promise<void> {
|
|
94
|
-
const newClosest = new PeerSet(this.newPeers?.peers.map(peer => peer.id))
|
|
94
|
+
const newClosest = new PeerSet(this.newPeers?.peers.map(({ peer }) => peer.id))
|
|
95
95
|
const added = newClosest.difference(this.closestPeers)
|
|
96
96
|
const removed = this.closestPeers.difference(newClosest)
|
|
97
97
|
this.closestPeers = newClosest
|