@libp2p/kad-dht 11.0.8 → 12.0.0-4e0135c7d
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/README.md +78 -0
- package/dist/index.min.js +23 -23
- package/dist/src/constants.d.ts +2 -4
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +7 -9
- package/dist/src/constants.js.map +1 -1
- package/dist/src/content-fetching/index.d.ts +7 -7
- package/dist/src/content-fetching/index.d.ts.map +1 -1
- package/dist/src/content-fetching/index.js +13 -7
- package/dist/src/content-fetching/index.js.map +1 -1
- package/dist/src/content-routing/index.d.ts +5 -4
- package/dist/src/content-routing/index.d.ts.map +1 -1
- package/dist/src/content-routing/index.js +23 -13
- package/dist/src/content-routing/index.js.map +1 -1
- package/dist/src/index.d.ts +142 -28
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +87 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/kad-dht.d.ts +20 -21
- package/dist/src/kad-dht.d.ts.map +1 -1
- package/dist/src/kad-dht.js +181 -35
- package/dist/src/kad-dht.js.map +1 -1
- package/dist/src/message/dht.d.ts +35 -35
- package/dist/src/message/dht.d.ts.map +1 -1
- package/dist/src/message/dht.js +150 -130
- package/dist/src/message/dht.js.map +1 -1
- package/dist/src/message/utils.d.ts +5 -0
- package/dist/src/message/utils.d.ts.map +1 -0
- package/dist/src/message/utils.js +20 -0
- package/dist/src/message/utils.js.map +1 -0
- package/dist/src/network.d.ts +8 -8
- package/dist/src/network.d.ts.map +1 -1
- package/dist/src/network.js +30 -18
- package/dist/src/network.js.map +1 -1
- package/dist/src/peer-routing/index.d.ts +6 -6
- package/dist/src/peer-routing/index.d.ts.map +1 -1
- package/dist/src/peer-routing/index.js +48 -35
- package/dist/src/peer-routing/index.js.map +1 -1
- package/dist/src/providers.d.ts +7 -0
- package/dist/src/providers.d.ts.map +1 -1
- package/dist/src/providers.js.map +1 -1
- package/dist/src/query/events.d.ts +13 -12
- package/dist/src/query/events.d.ts.map +1 -1
- package/dist/src/query/events.js +2 -2
- package/dist/src/query/events.js.map +1 -1
- package/dist/src/query/manager.d.ts +8 -5
- package/dist/src/query/manager.d.ts.map +1 -1
- package/dist/src/query/manager.js +6 -6
- 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-self.d.ts +1 -1
- package/dist/src/query-self.d.ts.map +1 -1
- package/dist/src/query-self.js +2 -2
- package/dist/src/query-self.js.map +1 -1
- package/dist/src/routing-table/index.d.ts +5 -6
- package/dist/src/routing-table/index.d.ts.map +1 -1
- package/dist/src/routing-table/index.js +72 -58
- package/dist/src/routing-table/index.js.map +1 -1
- package/dist/src/routing-table/refresh.d.ts +1 -1
- package/dist/src/routing-table/refresh.d.ts.map +1 -1
- package/dist/src/routing-table/refresh.js +2 -2
- package/dist/src/routing-table/refresh.js.map +1 -1
- package/dist/src/rpc/handlers/add-provider.d.ts +2 -1
- package/dist/src/rpc/handlers/add-provider.d.ts.map +1 -1
- package/dist/src/rpc/handlers/add-provider.js +8 -6
- package/dist/src/rpc/handlers/add-provider.js.map +1 -1
- package/dist/src/rpc/handlers/find-node.d.ts +5 -3
- package/dist/src/rpc/handlers/find-node.d.ts.map +1 -1
- package/dist/src/rpc/handlers/find-node.js +22 -14
- package/dist/src/rpc/handlers/find-node.js.map +1 -1
- package/dist/src/rpc/handlers/get-providers.d.ts +5 -3
- package/dist/src/rpc/handlers/get-providers.d.ts.map +1 -1
- package/dist/src/rpc/handlers/get-providers.js +29 -16
- package/dist/src/rpc/handlers/get-providers.js.map +1 -1
- package/dist/src/rpc/handlers/get-value.d.ts +2 -1
- package/dist/src/rpc/handlers/get-value.d.ts.map +1 -1
- package/dist/src/rpc/handlers/get-value.js +16 -7
- package/dist/src/rpc/handlers/get-value.js.map +1 -1
- package/dist/src/rpc/handlers/ping.d.ts +5 -2
- package/dist/src/rpc/handlers/ping.d.ts.map +1 -1
- package/dist/src/rpc/handlers/ping.js +2 -2
- package/dist/src/rpc/handlers/ping.js.map +1 -1
- package/dist/src/rpc/handlers/put-value.d.ts +2 -1
- package/dist/src/rpc/handlers/put-value.d.ts.map +1 -1
- package/dist/src/rpc/handlers/put-value.js +8 -7
- package/dist/src/rpc/handlers/put-value.js.map +1 -1
- package/dist/src/rpc/index.d.ts +4 -3
- package/dist/src/rpc/index.d.ts.map +1 -1
- package/dist/src/rpc/index.js +11 -11
- package/dist/src/rpc/index.js.map +1 -1
- package/dist/src/topology-listener.d.ts +1 -1
- package/dist/src/topology-listener.d.ts.map +1 -1
- package/dist/src/topology-listener.js +2 -2
- package/dist/src/topology-listener.js.map +1 -1
- package/dist/src/utils.d.ts +5 -2
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +32 -2
- package/dist/src/utils.js.map +1 -1
- package/package.json +13 -11
- package/src/constants.ts +7 -11
- package/src/content-fetching/index.ts +21 -14
- package/src/content-routing/index.ts +29 -18
- package/src/index.ts +148 -32
- package/src/kad-dht.ts +225 -56
- package/src/message/dht.proto +32 -32
- package/src/message/dht.ts +155 -138
- package/src/message/utils.ts +25 -0
- package/src/network.ts +41 -25
- package/src/peer-routing/index.ts +57 -42
- package/src/providers.ts +7 -0
- package/src/query/events.ts +14 -14
- package/src/query/manager.ts +14 -10
- package/src/query/query-path.ts +3 -3
- package/src/query-self.ts +3 -3
- package/src/routing-table/index.ts +86 -64
- package/src/routing-table/refresh.ts +4 -4
- package/src/rpc/handlers/add-provider.ts +10 -7
- package/src/rpc/handlers/find-node.ts +27 -18
- package/src/rpc/handlers/get-providers.ts +33 -20
- package/src/rpc/handlers/get-value.ts +18 -7
- package/src/rpc/handlers/ping.ts +7 -3
- package/src/rpc/handlers/put-value.ts +11 -9
- package/src/rpc/index.ts +14 -13
- package/src/topology-listener.ts +3 -3
- package/src/utils.ts +41 -2
- package/dist/src/dual-kad-dht.d.ts +0 -69
- package/dist/src/dual-kad-dht.d.ts.map +0 -1
- package/dist/src/dual-kad-dht.js +0 -304
- package/dist/src/dual-kad-dht.js.map +0 -1
- package/dist/src/message/index.d.ts +0 -35
- package/dist/src/message/index.d.ts.map +0 -1
- package/dist/src/message/index.js +0 -92
- package/dist/src/message/index.js.map +0 -1
- package/dist/typedoc-urls.json +0 -55
- package/src/dual-kad-dht.ts +0 -384
- package/src/message/index.ts +0 -117
|
@@ -2,7 +2,7 @@ import { keys } from '@libp2p/crypto'
|
|
|
2
2
|
import { CodeError } from '@libp2p/interface'
|
|
3
3
|
import { peerIdFromKeys } from '@libp2p/peer-id'
|
|
4
4
|
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
|
5
|
-
import {
|
|
5
|
+
import { MessageType } from '../message/dht.js'
|
|
6
6
|
import { PeerDistanceList } from '../peer-list/peer-distance-list.js'
|
|
7
7
|
import {
|
|
8
8
|
queryErrorEvent,
|
|
@@ -13,18 +13,19 @@ import { Libp2pRecord } from '../record/index.js'
|
|
|
13
13
|
import { verifyRecord } from '../record/validators.js'
|
|
14
14
|
import * as utils from '../utils.js'
|
|
15
15
|
import type { KadDHTComponents, DHTRecord, DialPeerEvent, FinalPeerEvent, QueryEvent, Validators } from '../index.js'
|
|
16
|
+
import type { Message } from '../message/dht.js'
|
|
16
17
|
import type { Network } from '../network.js'
|
|
17
18
|
import type { QueryManager, QueryOptions } from '../query/manager.js'
|
|
18
19
|
import type { QueryFunc } from '../query/types.js'
|
|
19
20
|
import type { RoutingTable } from '../routing-table/index.js'
|
|
20
|
-
import type {
|
|
21
|
+
import type { Logger, PeerId, PeerInfo, PeerStore, RoutingOptions } from '@libp2p/interface'
|
|
21
22
|
|
|
22
23
|
export interface PeerRoutingInit {
|
|
23
24
|
routingTable: RoutingTable
|
|
24
25
|
network: Network
|
|
25
26
|
validators: Validators
|
|
26
27
|
queryManager: QueryManager
|
|
27
|
-
|
|
28
|
+
logPrefix: string
|
|
28
29
|
}
|
|
29
30
|
|
|
30
31
|
export class PeerRouting {
|
|
@@ -37,7 +38,7 @@ export class PeerRouting {
|
|
|
37
38
|
private readonly peerId: PeerId
|
|
38
39
|
|
|
39
40
|
constructor (components: KadDHTComponents, init: PeerRoutingInit) {
|
|
40
|
-
const { routingTable, network, validators, queryManager,
|
|
41
|
+
const { routingTable, network, validators, queryManager, logPrefix } = init
|
|
41
42
|
|
|
42
43
|
this.routingTable = routingTable
|
|
43
44
|
this.network = network
|
|
@@ -45,7 +46,7 @@ export class PeerRouting {
|
|
|
45
46
|
this.queryManager = queryManager
|
|
46
47
|
this.peerStore = components.peerStore
|
|
47
48
|
this.peerId = components.peerId
|
|
48
|
-
this.log = components.logger.forComponent(
|
|
49
|
+
this.log = components.logger.forComponent(`${logPrefix}:peer-routing`)
|
|
49
50
|
}
|
|
50
51
|
|
|
51
52
|
/**
|
|
@@ -93,15 +94,19 @@ export class PeerRouting {
|
|
|
93
94
|
/**
|
|
94
95
|
* Get a value via rpc call for the given parameters
|
|
95
96
|
*/
|
|
96
|
-
async * _getValueSingle (peer: PeerId, key: Uint8Array, options:
|
|
97
|
-
const msg
|
|
97
|
+
async * _getValueSingle (peer: PeerId, key: Uint8Array, options: RoutingOptions = {}): AsyncGenerator<QueryEvent> {
|
|
98
|
+
const msg: Partial<Message> = {
|
|
99
|
+
type: MessageType.GET_VALUE,
|
|
100
|
+
key
|
|
101
|
+
}
|
|
102
|
+
|
|
98
103
|
yield * this.network.sendRequest(peer, msg, options)
|
|
99
104
|
}
|
|
100
105
|
|
|
101
106
|
/**
|
|
102
107
|
* Get the public key directly from a node
|
|
103
108
|
*/
|
|
104
|
-
async * getPublicKeyFromNode (peer: PeerId, options:
|
|
109
|
+
async * getPublicKeyFromNode (peer: PeerId, options: RoutingOptions = {}): AsyncGenerator<QueryEvent> {
|
|
105
110
|
const pkKey = utils.keyForPublicKey(peer)
|
|
106
111
|
|
|
107
112
|
for await (const event of this._getValueSingle(peer, pkKey, options)) {
|
|
@@ -129,52 +134,59 @@ export class PeerRouting {
|
|
|
129
134
|
/**
|
|
130
135
|
* Search for a peer with the given ID
|
|
131
136
|
*/
|
|
132
|
-
async * findPeer (id: PeerId, options:
|
|
137
|
+
async * findPeer (id: PeerId, options: RoutingOptions = {}): AsyncGenerator<FinalPeerEvent | QueryEvent> {
|
|
133
138
|
this.log('findPeer %p', id)
|
|
134
139
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
140
|
+
if (options.useCache !== false) {
|
|
141
|
+
// Try to find locally
|
|
142
|
+
const pi = await this.findPeerLocal(id)
|
|
143
|
+
|
|
144
|
+
// already got it
|
|
145
|
+
if (pi != null) {
|
|
146
|
+
this.log('found local')
|
|
147
|
+
yield finalPeerEvent({
|
|
148
|
+
from: this.peerId,
|
|
149
|
+
peer: pi
|
|
150
|
+
}, options)
|
|
151
|
+
return
|
|
152
|
+
}
|
|
146
153
|
}
|
|
147
154
|
|
|
148
|
-
|
|
155
|
+
let foundPeer = false
|
|
149
156
|
|
|
150
|
-
|
|
151
|
-
const
|
|
157
|
+
if (options.useNetwork !== false) {
|
|
158
|
+
const self = this // eslint-disable-line @typescript-eslint/no-this-alias
|
|
152
159
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
160
|
+
const findPeerQuery: QueryFunc = async function * ({ peer, signal }) {
|
|
161
|
+
const request: Partial<Message> = {
|
|
162
|
+
type: MessageType.FIND_NODE,
|
|
163
|
+
key: id.toBytes()
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
for await (const event of self.network.sendRequest(peer, request, {
|
|
167
|
+
...options,
|
|
168
|
+
signal
|
|
169
|
+
})) {
|
|
170
|
+
yield event
|
|
158
171
|
|
|
159
|
-
|
|
160
|
-
|
|
172
|
+
if (event.name === 'PEER_RESPONSE') {
|
|
173
|
+
const match = event.closer.find((p) => p.id.equals(id))
|
|
161
174
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
175
|
+
// found the peer
|
|
176
|
+
if (match != null) {
|
|
177
|
+
yield finalPeerEvent({ from: event.from, peer: match }, options)
|
|
178
|
+
}
|
|
165
179
|
}
|
|
166
180
|
}
|
|
167
181
|
}
|
|
168
|
-
}
|
|
169
182
|
|
|
170
|
-
|
|
183
|
+
for await (const event of this.queryManager.run(id.toBytes(), findPeerQuery, options)) {
|
|
184
|
+
if (event.name === 'FINAL_PEER') {
|
|
185
|
+
foundPeer = true
|
|
186
|
+
}
|
|
171
187
|
|
|
172
|
-
|
|
173
|
-
if (event.name === 'FINAL_PEER') {
|
|
174
|
-
foundPeer = true
|
|
188
|
+
yield event
|
|
175
189
|
}
|
|
176
|
-
|
|
177
|
-
yield event
|
|
178
190
|
}
|
|
179
191
|
|
|
180
192
|
if (!foundPeer) {
|
|
@@ -197,7 +209,10 @@ export class PeerRouting {
|
|
|
197
209
|
|
|
198
210
|
const getCloserPeersQuery: QueryFunc = async function * ({ peer, signal }) {
|
|
199
211
|
self.log('closerPeersSingle %s from %p', uint8ArrayToString(key, 'base32'), peer)
|
|
200
|
-
const request
|
|
212
|
+
const request: Partial<Message> = {
|
|
213
|
+
type: MessageType.FIND_NODE,
|
|
214
|
+
key
|
|
215
|
+
}
|
|
201
216
|
|
|
202
217
|
yield * self.network.sendRequest(peer, request, {
|
|
203
218
|
...options,
|
|
@@ -240,7 +255,7 @@ export class PeerRouting {
|
|
|
240
255
|
*
|
|
241
256
|
* Note: The peerStore is updated with new addresses found for the given peer.
|
|
242
257
|
*/
|
|
243
|
-
async * getValueOrPeers (peer: PeerId, key: Uint8Array, options:
|
|
258
|
+
async * getValueOrPeers (peer: PeerId, key: Uint8Array, options: RoutingOptions = {}): AsyncGenerator<DialPeerEvent | QueryEvent> {
|
|
244
259
|
for await (const event of this._getValueSingle(peer, key, options)) {
|
|
245
260
|
if (event.name === 'PEER_RESPONSE') {
|
|
246
261
|
if (event.record != null) {
|
package/src/providers.ts
CHANGED
|
@@ -15,13 +15,20 @@ import type { Datastore } from 'interface-datastore'
|
|
|
15
15
|
import type { CID } from 'multiformats'
|
|
16
16
|
|
|
17
17
|
export interface ProvidersInit {
|
|
18
|
+
/**
|
|
19
|
+
* @default 256
|
|
20
|
+
*/
|
|
18
21
|
cacheSize?: number
|
|
19
22
|
/**
|
|
20
23
|
* How often invalid records are cleaned. (in seconds)
|
|
24
|
+
*
|
|
25
|
+
* @default 5400
|
|
21
26
|
*/
|
|
22
27
|
cleanupInterval?: number
|
|
23
28
|
/**
|
|
24
29
|
* How long is a provider valid for. (in seconds)
|
|
30
|
+
*
|
|
31
|
+
* @default 86400
|
|
25
32
|
*/
|
|
26
33
|
provideValidity?: number
|
|
27
34
|
}
|
package/src/query/events.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { CustomEvent } from '@libp2p/interface'
|
|
2
|
-
import {
|
|
3
|
-
import type { SendQueryEvent, PeerResponseEvent, DialPeerEvent, AddPeerEvent, ValueEvent, ProviderEvent, QueryErrorEvent, FinalPeerEvent
|
|
4
|
-
import type { Message } from '../message/dht.js'
|
|
2
|
+
import { MessageType } from '../message/dht.js'
|
|
3
|
+
import type { SendQueryEvent, PeerResponseEvent, DialPeerEvent, AddPeerEvent, ValueEvent, ProviderEvent, QueryErrorEvent, FinalPeerEvent } from '../index.js'
|
|
5
4
|
import type { Libp2pRecord } from '../record/index.js'
|
|
6
5
|
import type { PeerId, PeerInfo } from '@libp2p/interface'
|
|
6
|
+
import type { ProgressOptions } from 'progress-events'
|
|
7
7
|
|
|
8
8
|
export interface QueryEventFields {
|
|
9
9
|
to: PeerId
|
|
10
|
-
type:
|
|
10
|
+
type: MessageType
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export function sendQueryEvent (fields: QueryEventFields, options:
|
|
13
|
+
export function sendQueryEvent (fields: QueryEventFields, options: ProgressOptions = {}): SendQueryEvent {
|
|
14
14
|
const event: SendQueryEvent = {
|
|
15
15
|
...fields,
|
|
16
16
|
name: 'SEND_QUERY',
|
|
17
17
|
type: 0,
|
|
18
18
|
messageName: fields.type,
|
|
19
|
-
messageType:
|
|
19
|
+
messageType: MessageType[fields.type]
|
|
20
20
|
}
|
|
21
21
|
|
|
22
22
|
options.onProgress?.(new CustomEvent('kad-dht:query:send-query', { detail: event }))
|
|
@@ -26,13 +26,13 @@ export function sendQueryEvent (fields: QueryEventFields, options: QueryOptions
|
|
|
26
26
|
|
|
27
27
|
export interface PeerResponseEventField {
|
|
28
28
|
from: PeerId
|
|
29
|
-
messageType:
|
|
29
|
+
messageType: MessageType
|
|
30
30
|
closer?: PeerInfo[]
|
|
31
31
|
providers?: PeerInfo[]
|
|
32
32
|
record?: Libp2pRecord
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export function peerResponseEvent (fields: PeerResponseEventField, options:
|
|
35
|
+
export function peerResponseEvent (fields: PeerResponseEventField, options: ProgressOptions = {}): PeerResponseEvent {
|
|
36
36
|
const event: PeerResponseEvent = {
|
|
37
37
|
...fields,
|
|
38
38
|
name: 'PEER_RESPONSE',
|
|
@@ -52,7 +52,7 @@ export interface FinalPeerEventFields {
|
|
|
52
52
|
peer: PeerInfo
|
|
53
53
|
}
|
|
54
54
|
|
|
55
|
-
export function finalPeerEvent (fields: FinalPeerEventFields, options:
|
|
55
|
+
export function finalPeerEvent (fields: FinalPeerEventFields, options: ProgressOptions = {}): FinalPeerEvent {
|
|
56
56
|
const event: FinalPeerEvent = {
|
|
57
57
|
...fields,
|
|
58
58
|
name: 'FINAL_PEER',
|
|
@@ -69,7 +69,7 @@ export interface ErrorEventFields {
|
|
|
69
69
|
error: Error
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
export function queryErrorEvent (fields: ErrorEventFields, options:
|
|
72
|
+
export function queryErrorEvent (fields: ErrorEventFields, options: ProgressOptions = {}): QueryErrorEvent {
|
|
73
73
|
const event: QueryErrorEvent = {
|
|
74
74
|
...fields,
|
|
75
75
|
name: 'QUERY_ERROR',
|
|
@@ -86,7 +86,7 @@ export interface ProviderEventFields {
|
|
|
86
86
|
providers: PeerInfo[]
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
-
export function providerEvent (fields: ProviderEventFields, options:
|
|
89
|
+
export function providerEvent (fields: ProviderEventFields, options: ProgressOptions = {}): ProviderEvent {
|
|
90
90
|
const event: ProviderEvent = {
|
|
91
91
|
...fields,
|
|
92
92
|
name: 'PROVIDER',
|
|
@@ -103,7 +103,7 @@ export interface ValueEventFields {
|
|
|
103
103
|
value: Uint8Array
|
|
104
104
|
}
|
|
105
105
|
|
|
106
|
-
export function valueEvent (fields: ValueEventFields, options:
|
|
106
|
+
export function valueEvent (fields: ValueEventFields, options: ProgressOptions = {}): ValueEvent {
|
|
107
107
|
const event: ValueEvent = {
|
|
108
108
|
...fields,
|
|
109
109
|
name: 'VALUE',
|
|
@@ -119,7 +119,7 @@ export interface PeerEventFields {
|
|
|
119
119
|
peer: PeerId
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
export function addPeerEvent (fields: PeerEventFields, options:
|
|
122
|
+
export function addPeerEvent (fields: PeerEventFields, options: ProgressOptions = {}): AddPeerEvent {
|
|
123
123
|
const event: AddPeerEvent = {
|
|
124
124
|
...fields,
|
|
125
125
|
name: 'ADD_PEER',
|
|
@@ -135,7 +135,7 @@ export interface DialPeerEventFields {
|
|
|
135
135
|
peer: PeerId
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
-
export function dialPeerEvent (fields: DialPeerEventFields, options:
|
|
138
|
+
export function dialPeerEvent (fields: DialPeerEventFields, options: ProgressOptions = {}): DialPeerEvent {
|
|
139
139
|
const event: DialPeerEvent = {
|
|
140
140
|
...fields,
|
|
141
141
|
name: 'DIAL_PEER',
|
package/src/query/manager.ts
CHANGED
|
@@ -9,9 +9,9 @@ import {
|
|
|
9
9
|
import { convertBuffer } from '../utils.js'
|
|
10
10
|
import { queryPath } from './query-path.js'
|
|
11
11
|
import type { QueryFunc } from './types.js'
|
|
12
|
-
import type { QueryEvent
|
|
12
|
+
import type { QueryEvent } from '../index.js'
|
|
13
13
|
import type { RoutingTable } from '../routing-table/index.js'
|
|
14
|
-
import type { ComponentLogger, Metric, Metrics, PeerId, Startable } from '@libp2p/interface'
|
|
14
|
+
import type { ComponentLogger, Metric, Metrics, PeerId, RoutingOptions, Startable } from '@libp2p/interface'
|
|
15
15
|
import type { DeferredPromise } from 'p-defer'
|
|
16
16
|
|
|
17
17
|
export interface CleanUpEvents {
|
|
@@ -19,7 +19,7 @@ export interface CleanUpEvents {
|
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
export interface QueryManagerInit {
|
|
22
|
-
|
|
22
|
+
logPrefix: string
|
|
23
23
|
disjointPaths?: number
|
|
24
24
|
alpha?: number
|
|
25
25
|
initialQuerySelfHasRun: DeferredPromise<void>
|
|
@@ -32,8 +32,12 @@ export interface QueryManagerComponents {
|
|
|
32
32
|
logger: ComponentLogger
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
export interface QueryOptions extends
|
|
35
|
+
export interface QueryOptions extends RoutingOptions {
|
|
36
|
+
/**
|
|
37
|
+
* A timeout for subqueries executed as part of the main query
|
|
38
|
+
*/
|
|
36
39
|
queryFuncTimeout?: number
|
|
40
|
+
|
|
37
41
|
isSelfQuery?: boolean
|
|
38
42
|
}
|
|
39
43
|
|
|
@@ -41,7 +45,6 @@ export interface QueryOptions extends RootQueryOptions {
|
|
|
41
45
|
* Keeps track of all running queries
|
|
42
46
|
*/
|
|
43
47
|
export class QueryManager implements Startable {
|
|
44
|
-
private readonly lan: boolean
|
|
45
48
|
public disjointPaths: number
|
|
46
49
|
private readonly alpha: number
|
|
47
50
|
private readonly shutDownController: AbortController
|
|
@@ -51,18 +54,19 @@ export class QueryManager implements Startable {
|
|
|
51
54
|
private readonly peerId: PeerId
|
|
52
55
|
private readonly routingTable: RoutingTable
|
|
53
56
|
private initialQuerySelfHasRun?: DeferredPromise<void>
|
|
57
|
+
private readonly logPrefix: string
|
|
54
58
|
private readonly metrics?: {
|
|
55
59
|
runningQueries: Metric
|
|
56
60
|
queryTime: Metric
|
|
57
61
|
}
|
|
58
62
|
|
|
59
63
|
constructor (components: QueryManagerComponents, init: QueryManagerInit) {
|
|
60
|
-
const {
|
|
64
|
+
const { disjointPaths = K, alpha = ALPHA, logPrefix } = init
|
|
61
65
|
|
|
66
|
+
this.logPrefix = logPrefix
|
|
62
67
|
this.disjointPaths = disjointPaths ?? K
|
|
63
68
|
this.running = false
|
|
64
69
|
this.alpha = alpha ?? ALPHA
|
|
65
|
-
this.lan = lan
|
|
66
70
|
this.queries = 0
|
|
67
71
|
this.initialQuerySelfHasRun = init.initialQuerySelfHasRun
|
|
68
72
|
this.routingTable = init.routingTable
|
|
@@ -71,8 +75,8 @@ export class QueryManager implements Startable {
|
|
|
71
75
|
|
|
72
76
|
if (components.metrics != null) {
|
|
73
77
|
this.metrics = {
|
|
74
|
-
runningQueries: components.metrics.registerMetric(
|
|
75
|
-
queryTime: components.metrics.registerMetric(
|
|
78
|
+
runningQueries: components.metrics.registerMetric(`${logPrefix.replaceAll(':', '_')}_running_queries`),
|
|
79
|
+
queryTime: components.metrics.registerMetric(`${logPrefix.replaceAll(':', '_')}_query_time_seconds`)
|
|
76
80
|
}
|
|
77
81
|
}
|
|
78
82
|
|
|
@@ -129,7 +133,7 @@ export class QueryManager implements Startable {
|
|
|
129
133
|
// so make sure we don't make a lot of noise in the logs
|
|
130
134
|
setMaxListeners(Infinity, signal)
|
|
131
135
|
|
|
132
|
-
const log = this.logger.forComponent(
|
|
136
|
+
const log = this.logger.forComponent(`${this.logPrefix}:query:` + uint8ArrayToString(key, 'base58btc'))
|
|
133
137
|
|
|
134
138
|
// query a subset of peers up to `kBucketSize / 2` in length
|
|
135
139
|
const startTime = Date.now()
|
package/src/query/query-path.ts
CHANGED
|
@@ -6,14 +6,14 @@ import { convertPeerId, convertBuffer } from '../utils.js'
|
|
|
6
6
|
import { queryErrorEvent } from './events.js'
|
|
7
7
|
import { queueToGenerator } from './utils.js'
|
|
8
8
|
import type { CleanUpEvents } from './manager.js'
|
|
9
|
-
import type { QueryEvent
|
|
9
|
+
import type { QueryEvent } from '../index.js'
|
|
10
10
|
import type { QueryFunc } from '../query/types.js'
|
|
11
|
-
import type { Logger, TypedEventTarget, PeerId } from '@libp2p/interface'
|
|
11
|
+
import type { Logger, TypedEventTarget, PeerId, RoutingOptions } from '@libp2p/interface'
|
|
12
12
|
import type { PeerSet } from '@libp2p/peer-collections'
|
|
13
13
|
|
|
14
14
|
const MAX_XOR = BigInt('0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF')
|
|
15
15
|
|
|
16
|
-
export interface QueryPathOptions extends
|
|
16
|
+
export interface QueryPathOptions extends RoutingOptions {
|
|
17
17
|
/**
|
|
18
18
|
* What are we trying to find
|
|
19
19
|
*/
|
package/src/query-self.ts
CHANGED
|
@@ -12,7 +12,7 @@ import type { ComponentLogger, Logger, PeerId, Startable } from '@libp2p/interfa
|
|
|
12
12
|
import type { DeferredPromise } from 'p-defer'
|
|
13
13
|
|
|
14
14
|
export interface QuerySelfInit {
|
|
15
|
-
|
|
15
|
+
logPrefix: string
|
|
16
16
|
peerRouting: PeerRouting
|
|
17
17
|
routingTable: RoutingTable
|
|
18
18
|
count?: number
|
|
@@ -46,10 +46,10 @@ export class QuerySelf implements Startable {
|
|
|
46
46
|
private querySelfPromise?: DeferredPromise<void>
|
|
47
47
|
|
|
48
48
|
constructor (components: QuerySelfComponents, init: QuerySelfInit) {
|
|
49
|
-
const { peerRouting,
|
|
49
|
+
const { peerRouting, logPrefix, count, interval, queryTimeout, routingTable } = init
|
|
50
50
|
|
|
51
51
|
this.peerId = components.peerId
|
|
52
|
-
this.log = components.logger.forComponent(
|
|
52
|
+
this.log = components.logger.forComponent(`${logPrefix}:query-self`)
|
|
53
53
|
this.started = false
|
|
54
54
|
this.peerRouting = peerRouting
|
|
55
55
|
this.routingTable = routingTable
|
|
@@ -1,9 +1,11 @@
|
|
|
1
|
-
import { TypedEventEmitter } from '@libp2p/interface'
|
|
1
|
+
import { CodeError, TypedEventEmitter } from '@libp2p/interface'
|
|
2
2
|
import { PeerSet } from '@libp2p/peer-collections'
|
|
3
|
-
import
|
|
3
|
+
import { PeerJobQueue } from '@libp2p/utils/peer-job-queue'
|
|
4
|
+
import { pbStream } from 'it-protobuf-stream'
|
|
5
|
+
import { Message, MessageType } from '../message/dht.js'
|
|
4
6
|
import * as utils from '../utils.js'
|
|
5
7
|
import { KBucket, type PingEventDetails } from './k-bucket.js'
|
|
6
|
-
import type { ComponentLogger, Logger, Metric, Metrics, PeerId, PeerStore, Startable } from '@libp2p/interface'
|
|
8
|
+
import type { ComponentLogger, Logger, Metric, Metrics, PeerId, PeerStore, Startable, Stream } from '@libp2p/interface'
|
|
7
9
|
import type { ConnectionManager } from '@libp2p/interface-internal'
|
|
8
10
|
|
|
9
11
|
export const KAD_CLOSE_TAG_NAME = 'kad-close'
|
|
@@ -13,7 +15,7 @@ export const PING_TIMEOUT = 10000
|
|
|
13
15
|
export const PING_CONCURRENCY = 10
|
|
14
16
|
|
|
15
17
|
export interface RoutingTableInit {
|
|
16
|
-
|
|
18
|
+
logPrefix: string
|
|
17
19
|
protocol: string
|
|
18
20
|
kBucketSize?: number
|
|
19
21
|
pingTimeout?: number
|
|
@@ -42,18 +44,17 @@ export interface RoutingTableEvents {
|
|
|
42
44
|
export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implements Startable {
|
|
43
45
|
public kBucketSize: number
|
|
44
46
|
public kb?: KBucket
|
|
45
|
-
public pingQueue:
|
|
47
|
+
public pingQueue: PeerJobQueue
|
|
46
48
|
|
|
47
49
|
private readonly log: Logger
|
|
48
50
|
private readonly components: RoutingTableComponents
|
|
49
|
-
private readonly lan: boolean
|
|
50
51
|
private readonly pingTimeout: number
|
|
51
52
|
private readonly pingConcurrency: number
|
|
52
53
|
private running: boolean
|
|
53
54
|
private readonly protocol: string
|
|
54
55
|
private readonly tagName: string
|
|
55
56
|
private readonly tagValue: number
|
|
56
|
-
private metrics?: {
|
|
57
|
+
private readonly metrics?: {
|
|
57
58
|
routingTableSize: Metric
|
|
58
59
|
pingQueueSize: Metric
|
|
59
60
|
pingRunning: Metric
|
|
@@ -62,14 +63,13 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
62
63
|
constructor (components: RoutingTableComponents, init: RoutingTableInit) {
|
|
63
64
|
super()
|
|
64
65
|
|
|
65
|
-
const { kBucketSize, pingTimeout,
|
|
66
|
+
const { kBucketSize, pingTimeout, logPrefix, pingConcurrency, protocol, tagName, tagValue } = init
|
|
66
67
|
|
|
67
68
|
this.components = components
|
|
68
|
-
this.log = components.logger.forComponent(
|
|
69
|
+
this.log = components.logger.forComponent(`${logPrefix}:routing-table`)
|
|
69
70
|
this.kBucketSize = kBucketSize ?? KBUCKET_SIZE
|
|
70
71
|
this.pingTimeout = pingTimeout ?? PING_TIMEOUT
|
|
71
72
|
this.pingConcurrency = pingConcurrency ?? PING_CONCURRENCY
|
|
72
|
-
this.lan = lan
|
|
73
73
|
this.running = false
|
|
74
74
|
this.protocol = protocol
|
|
75
75
|
this.tagName = tagName ?? KAD_CLOSE_TAG_NAME
|
|
@@ -80,11 +80,20 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
80
80
|
this.metrics?.pingRunning.update(this.pingQueue.pending)
|
|
81
81
|
}
|
|
82
82
|
|
|
83
|
-
this.pingQueue = new
|
|
83
|
+
this.pingQueue = new PeerJobQueue({ concurrency: this.pingConcurrency })
|
|
84
84
|
this.pingQueue.addListener('add', updatePingQueueSizeMetric)
|
|
85
85
|
this.pingQueue.addListener('next', updatePingQueueSizeMetric)
|
|
86
|
+
this.pingQueue.addListener('error', err => {
|
|
87
|
+
this.log.error('error pinging peer', err)
|
|
88
|
+
})
|
|
86
89
|
|
|
87
|
-
this.
|
|
90
|
+
if (this.components.metrics != null) {
|
|
91
|
+
this.metrics = {
|
|
92
|
+
routingTableSize: this.components.metrics.registerMetric(`${logPrefix.replaceAll(':', '_')}_routing_table_size`),
|
|
93
|
+
pingQueueSize: this.components.metrics.registerMetric(`${logPrefix.replaceAll(':', '_')}_ping_queue_size`),
|
|
94
|
+
pingRunning: this.components.metrics.registerMetric(`${logPrefix.replaceAll(':', '_')}_ping_running`)
|
|
95
|
+
}
|
|
96
|
+
}
|
|
88
97
|
}
|
|
89
98
|
|
|
90
99
|
isStarted (): boolean {
|
|
@@ -94,14 +103,6 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
94
103
|
async start (): Promise<void> {
|
|
95
104
|
this.running = true
|
|
96
105
|
|
|
97
|
-
if (this.components.metrics != null) {
|
|
98
|
-
this.metrics = {
|
|
99
|
-
routingTableSize: this.components.metrics.registerMetric(`libp2p_kad_dht_${this.lan ? 'lan' : 'wan'}_routing_table_size`),
|
|
100
|
-
pingQueueSize: this.components.metrics.registerMetric(`libp2p_kad_dht_${this.lan ? 'lan' : 'wan'}_ping_queue_size`),
|
|
101
|
-
pingRunning: this.components.metrics.registerMetric(`libp2p_kad_dht_${this.lan ? 'lan' : 'wan'}_ping_running`)
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
|
|
105
106
|
const kBuck = new KBucket({
|
|
106
107
|
localNodeId: await utils.convertPeerId(this.components.peerId),
|
|
107
108
|
numberOfNodesPerKBucket: this.kBucketSize,
|
|
@@ -110,7 +111,11 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
110
111
|
this.kb = kBuck
|
|
111
112
|
|
|
112
113
|
// test whether to evict peers
|
|
113
|
-
kBuck.addEventListener('ping',
|
|
114
|
+
kBuck.addEventListener('ping', (evt) => {
|
|
115
|
+
this._onPing(evt).catch(err => {
|
|
116
|
+
this.log.error('could not process k-bucket ping event', err)
|
|
117
|
+
})
|
|
118
|
+
})
|
|
114
119
|
|
|
115
120
|
// tag kad-close peers
|
|
116
121
|
this._tagPeers(kBuck)
|
|
@@ -186,60 +191,77 @@ export class RoutingTable extends TypedEventEmitter<RoutingTableEvents> implemen
|
|
|
186
191
|
* `oldContacts` will not be empty and is the list of contacts that
|
|
187
192
|
* have not been contacted for the longest.
|
|
188
193
|
*/
|
|
189
|
-
_onPing (evt: CustomEvent<PingEventDetails>): void {
|
|
194
|
+
async _onPing (evt: CustomEvent<PingEventDetails>): Promise<void> {
|
|
195
|
+
if (!this.running) {
|
|
196
|
+
return
|
|
197
|
+
}
|
|
198
|
+
|
|
190
199
|
const {
|
|
191
200
|
oldContacts,
|
|
192
201
|
newContact
|
|
193
202
|
} = evt.detail
|
|
194
203
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
204
|
+
const results = await Promise.all(
|
|
205
|
+
oldContacts.map(async oldContact => {
|
|
206
|
+
// if a previous ping wants us to ping this contact, re-use the result
|
|
207
|
+
if (this.pingQueue.hasJob(oldContact.peer)) {
|
|
208
|
+
return this.pingQueue.joinJob(oldContact.peer)
|
|
209
|
+
}
|
|
202
210
|
|
|
203
|
-
|
|
211
|
+
return this.pingQueue.add(async () => {
|
|
212
|
+
let stream: Stream | undefined
|
|
204
213
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
const options = {
|
|
210
|
-
signal: AbortSignal.timeout(this.pingTimeout)
|
|
211
|
-
}
|
|
214
|
+
try {
|
|
215
|
+
const options = {
|
|
216
|
+
signal: AbortSignal.timeout(this.pingTimeout)
|
|
217
|
+
}
|
|
212
218
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
this.metrics?.routingTableSize.update(this.size)
|
|
219
|
+
this.log('pinging old contact %p', oldContact.peer)
|
|
220
|
+
const connection = await this.components.connectionManager.openConnection(oldContact.peer, options)
|
|
221
|
+
stream = await connection.newStream(this.protocol, options)
|
|
222
|
+
|
|
223
|
+
const pb = pbStream(stream)
|
|
224
|
+
await pb.write({
|
|
225
|
+
type: MessageType.PING
|
|
226
|
+
}, Message, options)
|
|
227
|
+
const response = await pb.read(Message, options)
|
|
228
|
+
|
|
229
|
+
await pb.unwrap().close()
|
|
230
|
+
|
|
231
|
+
if (response.type !== MessageType.PING) {
|
|
232
|
+
throw new CodeError(`Incorrect message type received, expected PING got ${response.type}`, 'ERR_BAD_PING_RESPONSE')
|
|
228
233
|
}
|
|
229
|
-
})
|
|
230
|
-
)
|
|
231
234
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
235
|
+
return true
|
|
236
|
+
} catch (err: any) {
|
|
237
|
+
if (this.running && this.kb != null) {
|
|
238
|
+
// only evict peers if we are still running, otherwise we evict
|
|
239
|
+
// when dialing is cancelled due to shutdown in progress
|
|
240
|
+
this.log.error('could not ping peer %p', oldContact.peer, err)
|
|
241
|
+
this.log('evicting old contact after ping failed %p', oldContact.peer)
|
|
242
|
+
this.kb.remove(oldContact.id)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
stream?.abort(err)
|
|
246
|
+
|
|
247
|
+
return false
|
|
248
|
+
} finally {
|
|
249
|
+
this.metrics?.routingTableSize.update(this.size)
|
|
250
|
+
}
|
|
251
|
+
}, {
|
|
252
|
+
peerId: oldContact.peer
|
|
253
|
+
})
|
|
242
254
|
})
|
|
255
|
+
)
|
|
256
|
+
|
|
257
|
+
const responded = results
|
|
258
|
+
.filter(res => res)
|
|
259
|
+
.length
|
|
260
|
+
|
|
261
|
+
if (this.running && responded < oldContacts.length && this.kb != null) {
|
|
262
|
+
this.log('adding new contact %p', newContact.peer)
|
|
263
|
+
this.kb.add(newContact)
|
|
264
|
+
}
|
|
243
265
|
}
|
|
244
266
|
|
|
245
267
|
// -- Public Interface
|