@libp2p/kad-dht 14.0.2 → 14.1.0-02f285fc8
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 +36 -0
- package/dist/index.min.js +2 -2
- package/dist/src/constants.d.ts +4 -3
- package/dist/src/constants.d.ts.map +1 -1
- package/dist/src/constants.js +8 -3
- package/dist/src/constants.js.map +1 -1
- package/dist/src/content-fetching/index.d.ts +1 -0
- package/dist/src/content-fetching/index.d.ts.map +1 -1
- package/dist/src/content-fetching/index.js +5 -3
- package/dist/src/content-fetching/index.js.map +1 -1
- package/dist/src/index.d.ts +107 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +36 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/kad-dht.d.ts +14 -1
- package/dist/src/kad-dht.d.ts.map +1 -1
- package/dist/src/kad-dht.js +76 -27
- package/dist/src/kad-dht.js.map +1 -1
- package/dist/src/network.d.ts +1 -0
- package/dist/src/network.d.ts.map +1 -1
- package/dist/src/network.js +4 -5
- package/dist/src/network.js.map +1 -1
- package/dist/src/peer-routing/index.d.ts.map +1 -1
- package/dist/src/peer-routing/index.js +9 -10
- package/dist/src/peer-routing/index.js.map +1 -1
- package/dist/src/providers.d.ts +21 -50
- package/dist/src/providers.d.ts.map +1 -1
- package/dist/src/providers.js +51 -192
- package/dist/src/providers.js.map +1 -1
- package/dist/src/query/manager.d.ts +1 -1
- package/dist/src/query/manager.d.ts.map +1 -1
- package/dist/src/query/manager.js +8 -19
- package/dist/src/query/manager.js.map +1 -1
- package/dist/src/query-self.d.ts +3 -1
- package/dist/src/query-self.d.ts.map +1 -1
- package/dist/src/query-self.js +17 -16
- package/dist/src/query-self.js.map +1 -1
- package/dist/src/reprovider.d.ts +63 -0
- package/dist/src/reprovider.d.ts.map +1 -0
- package/dist/src/reprovider.js +161 -0
- package/dist/src/reprovider.js.map +1 -0
- package/dist/src/routing-table/closest-peers.d.ts +1 -0
- package/dist/src/routing-table/closest-peers.d.ts.map +1 -1
- package/dist/src/routing-table/closest-peers.js +7 -0
- package/dist/src/routing-table/closest-peers.js.map +1 -1
- package/dist/src/routing-table/index.d.ts +1 -0
- package/dist/src/routing-table/index.d.ts.map +1 -1
- package/dist/src/routing-table/index.js +14 -11
- package/dist/src/routing-table/index.js.map +1 -1
- package/dist/src/rpc/handlers/get-value.d.ts +1 -0
- package/dist/src/rpc/handlers/get-value.d.ts.map +1 -1
- package/dist/src/rpc/handlers/get-value.js +3 -1
- package/dist/src/rpc/handlers/get-value.js.map +1 -1
- package/dist/src/rpc/handlers/put-value.d.ts +1 -0
- package/dist/src/rpc/handlers/put-value.d.ts.map +1 -1
- package/dist/src/rpc/handlers/put-value.js +3 -1
- package/dist/src/rpc/handlers/put-value.js.map +1 -1
- package/dist/src/rpc/index.d.ts +1 -0
- package/dist/src/rpc/index.d.ts.map +1 -1
- package/dist/src/rpc/index.js +9 -10
- package/dist/src/rpc/index.js.map +1 -1
- package/dist/src/utils.d.ts +20 -1
- package/dist/src/utils.d.ts.map +1 -1
- package/dist/src/utils.js +87 -4
- package/dist/src/utils.js.map +1 -1
- package/package.json +12 -14
- package/src/constants.ts +11 -5
- package/src/content-fetching/index.ts +5 -3
- package/src/index.ts +116 -2
- package/src/kad-dht.ts +94 -41
- package/src/network.ts +5 -5
- package/src/peer-routing/index.ts +9 -11
- package/src/providers.ts +57 -244
- package/src/query/manager.ts +12 -28
- package/src/query-self.ts +20 -17
- package/src/reprovider.ts +226 -0
- package/src/routing-table/closest-peers.ts +9 -0
- package/src/routing-table/index.ts +16 -11
- package/src/rpc/handlers/get-value.ts +3 -1
- package/src/rpc/handlers/put-value.ts +3 -1
- package/src/rpc/index.ts +10 -10
- package/src/utils.ts +102 -4
- package/dist/typedoc-urls.json +0 -56
package/src/providers.ts
CHANGED
|
@@ -1,292 +1,105 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import cache from 'hashlru'
|
|
3
|
-
import { Key } from 'interface-datastore/key'
|
|
4
|
-
import Queue from 'p-queue'
|
|
1
|
+
import { PeerMap } from '@libp2p/peer-collections'
|
|
5
2
|
import * as varint from 'uint8-varint'
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
PROVIDERS_CLEANUP_INTERVAL,
|
|
9
|
-
PROVIDERS_VALIDITY,
|
|
10
|
-
PROVIDERS_LRU_CACHE_SIZE,
|
|
11
|
-
PROVIDER_KEY_PREFIX
|
|
12
|
-
} from './constants.js'
|
|
13
|
-
import type { ComponentLogger, Logger, PeerId, Startable } from '@libp2p/interface'
|
|
3
|
+
import { parseProviderKey, readProviderTime, toProviderKey } from './utils.js'
|
|
4
|
+
import type { ComponentLogger, Logger, Metrics, PeerId } from '@libp2p/interface'
|
|
14
5
|
import type { Datastore } from 'interface-datastore'
|
|
6
|
+
import type { Mortice } from 'mortice'
|
|
15
7
|
import type { CID } from 'multiformats'
|
|
16
8
|
|
|
17
9
|
export interface ProvidersInit {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
cacheSize?: number
|
|
22
|
-
/**
|
|
23
|
-
* How often invalid records are cleaned. (in seconds)
|
|
24
|
-
*
|
|
25
|
-
* @default 5400
|
|
26
|
-
*/
|
|
27
|
-
cleanupInterval?: number
|
|
28
|
-
/**
|
|
29
|
-
* How long is a provider valid for. (in seconds)
|
|
30
|
-
*
|
|
31
|
-
* @default 86400
|
|
32
|
-
*/
|
|
33
|
-
provideValidity?: number
|
|
10
|
+
logPrefix: string
|
|
11
|
+
datastorePrefix: string
|
|
12
|
+
lock: Mortice
|
|
34
13
|
}
|
|
35
14
|
|
|
36
15
|
export interface ProvidersComponents {
|
|
37
16
|
datastore: Datastore
|
|
38
17
|
logger: ComponentLogger
|
|
18
|
+
metrics?: Metrics
|
|
39
19
|
}
|
|
40
20
|
|
|
41
21
|
/**
|
|
42
|
-
*
|
|
43
|
-
* A provider is a peer that we know to have the content for a given CID.
|
|
44
|
-
*
|
|
45
|
-
* Every `cleanupInterval` providers are checked if they
|
|
46
|
-
* are still valid, i.e. younger than the `provideValidity`.
|
|
47
|
-
* If they are not, they are deleted.
|
|
48
|
-
*
|
|
49
|
-
* To ensure the list survives restarts of the daemon,
|
|
50
|
-
* providers are stored in the datastore, but to ensure
|
|
51
|
-
* access is fast there is an LRU cache in front of that.
|
|
22
|
+
* Provides a mechanism to add and remove provider records from the datastore
|
|
52
23
|
*/
|
|
53
|
-
export class Providers
|
|
24
|
+
export class Providers {
|
|
54
25
|
private readonly log: Logger
|
|
55
26
|
private readonly datastore: Datastore
|
|
56
|
-
private readonly
|
|
57
|
-
private readonly
|
|
58
|
-
private readonly provideValidity: number
|
|
59
|
-
private readonly syncQueue: Queue
|
|
60
|
-
private started: boolean
|
|
61
|
-
private cleaner?: ReturnType<typeof setInterval>
|
|
62
|
-
|
|
63
|
-
constructor (components: ProvidersComponents, init: ProvidersInit = {}) {
|
|
64
|
-
const { cacheSize, cleanupInterval, provideValidity } = init
|
|
27
|
+
private readonly datastorePrefix: string
|
|
28
|
+
private readonly lock: Mortice
|
|
65
29
|
|
|
66
|
-
|
|
30
|
+
constructor (components: ProvidersComponents, init: ProvidersInit) {
|
|
31
|
+
this.log = components.logger.forComponent(`${init.logPrefix}:providers`)
|
|
32
|
+
this.datastorePrefix = `/${init.datastorePrefix}/provider`
|
|
67
33
|
this.datastore = components.datastore
|
|
68
|
-
this.
|
|
69
|
-
this.provideValidity = provideValidity ?? PROVIDERS_VALIDITY
|
|
70
|
-
this.cache = cache(cacheSize ?? PROVIDERS_LRU_CACHE_SIZE)
|
|
71
|
-
this.syncQueue = new Queue({ concurrency: 1 })
|
|
72
|
-
this.started = false
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
isStarted (): boolean {
|
|
76
|
-
return this.started
|
|
34
|
+
this.lock = init.lock
|
|
77
35
|
}
|
|
78
36
|
|
|
79
37
|
/**
|
|
80
|
-
*
|
|
38
|
+
* Add a new provider for the given CID
|
|
81
39
|
*/
|
|
82
|
-
async
|
|
83
|
-
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
this.started = true
|
|
40
|
+
async addProvider (cid: CID, provider: PeerId): Promise<void> {
|
|
41
|
+
const release = await this.lock.readLock()
|
|
88
42
|
|
|
89
|
-
|
|
90
|
-
(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
this.cleanupInterval
|
|
96
|
-
)
|
|
43
|
+
try {
|
|
44
|
+
this.log('%p provides %s', provider, cid)
|
|
45
|
+
await this.writeProviderEntry(cid, provider)
|
|
46
|
+
} finally {
|
|
47
|
+
release()
|
|
48
|
+
}
|
|
97
49
|
}
|
|
98
50
|
|
|
99
51
|
/**
|
|
100
|
-
*
|
|
52
|
+
* Remove a provider for the given CID
|
|
101
53
|
*/
|
|
102
|
-
async
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
this.
|
|
54
|
+
async removeProvider (cid: CID, provider: PeerId): Promise<void> {
|
|
55
|
+
const release = await this.lock.writeLock()
|
|
56
|
+
|
|
57
|
+
try {
|
|
58
|
+
const key = toProviderKey(this.datastorePrefix, cid, provider)
|
|
59
|
+
this.log('%p no longer provides %s', provider, cid)
|
|
60
|
+
await this.datastore.delete(key)
|
|
61
|
+
} finally {
|
|
62
|
+
release()
|
|
108
63
|
}
|
|
109
64
|
}
|
|
110
65
|
|
|
111
66
|
/**
|
|
112
|
-
*
|
|
67
|
+
* Get a list of providers for the given CID
|
|
113
68
|
*/
|
|
114
|
-
async
|
|
115
|
-
await this.
|
|
116
|
-
const start = Date.now()
|
|
117
|
-
|
|
118
|
-
let count = 0
|
|
119
|
-
let deleteCount = 0
|
|
120
|
-
const deleted = new Map<string, Set<string>>()
|
|
121
|
-
const batch = this.datastore.batch()
|
|
122
|
-
|
|
123
|
-
// Get all provider entries from the datastore
|
|
124
|
-
const query = this.datastore.query({ prefix: PROVIDER_KEY_PREFIX })
|
|
125
|
-
|
|
126
|
-
for await (const entry of query) {
|
|
127
|
-
try {
|
|
128
|
-
// Add a delete to the batch for each expired entry
|
|
129
|
-
const { cid, peerId } = parseProviderKey(entry.key)
|
|
130
|
-
const time = readTime(entry.value).getTime()
|
|
131
|
-
const now = Date.now()
|
|
132
|
-
const delta = now - time
|
|
133
|
-
const expired = delta > this.provideValidity
|
|
134
|
-
|
|
135
|
-
this.log('comparing: %d - %d = %d > %d %s', now, time, delta, this.provideValidity, expired ? '(expired)' : '')
|
|
136
|
-
|
|
137
|
-
if (expired) {
|
|
138
|
-
deleteCount++
|
|
139
|
-
batch.delete(entry.key)
|
|
140
|
-
const peers = deleted.get(cid) ?? new Set<string>()
|
|
141
|
-
peers.add(peerId)
|
|
142
|
-
deleted.set(cid, peers)
|
|
143
|
-
}
|
|
144
|
-
count++
|
|
145
|
-
} catch (err: any) {
|
|
146
|
-
this.log.error(err.message)
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
// Commit the deletes to the datastore
|
|
151
|
-
if (deleted.size > 0) {
|
|
152
|
-
this.log('deleting %d / %d entries', deleteCount, count)
|
|
153
|
-
await batch.commit()
|
|
154
|
-
} else {
|
|
155
|
-
this.log('nothing to delete')
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
// Clear expired entries from the cache
|
|
159
|
-
for (const [cid, peers] of deleted) {
|
|
160
|
-
const key = makeProviderKey(cid)
|
|
161
|
-
const provs = this.cache.get(key)
|
|
162
|
-
|
|
163
|
-
if (provs != null) {
|
|
164
|
-
for (const peerId of peers) {
|
|
165
|
-
provs.delete(peerId)
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
if (provs.size === 0) {
|
|
169
|
-
this.cache.remove(key)
|
|
170
|
-
} else {
|
|
171
|
-
this.cache.set(key, provs)
|
|
172
|
-
}
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
this.log('Cleanup successful (%dms)', Date.now() - start)
|
|
177
|
-
})
|
|
178
|
-
}
|
|
69
|
+
async getProviders (cid: CID): Promise<PeerId[]> {
|
|
70
|
+
const release = await this.lock.readLock()
|
|
179
71
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
async _getProvidersMap (cid: CID): Promise<Map<string, Date>> {
|
|
184
|
-
const cacheKey = makeProviderKey(cid)
|
|
185
|
-
let provs: Map<string, Date> = this.cache.get(cacheKey)
|
|
72
|
+
try {
|
|
73
|
+
this.log('get providers for %s', cid)
|
|
74
|
+
const provs = await this.loadProviders(cid)
|
|
186
75
|
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
76
|
+
return [...provs.keys()]
|
|
77
|
+
} finally {
|
|
78
|
+
release()
|
|
190
79
|
}
|
|
191
|
-
|
|
192
|
-
return provs
|
|
193
80
|
}
|
|
194
81
|
|
|
195
82
|
/**
|
|
196
|
-
*
|
|
83
|
+
* Write a provider into the given store
|
|
197
84
|
*/
|
|
198
|
-
async
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
const provs = await this._getProvidersMap(cid)
|
|
202
|
-
|
|
203
|
-
this.log('loaded %s provs', provs.size)
|
|
204
|
-
const now = new Date()
|
|
205
|
-
provs.set(provider.toString(), now)
|
|
206
|
-
|
|
207
|
-
const dsKey = makeProviderKey(cid)
|
|
208
|
-
this.cache.set(dsKey, provs)
|
|
85
|
+
private async writeProviderEntry (cid: CID, peerId: PeerId, time: Date = new Date()): Promise<void> {
|
|
86
|
+
const key = toProviderKey(this.datastorePrefix, cid, peerId)
|
|
87
|
+
const buffer = varint.encode(time.getTime())
|
|
209
88
|
|
|
210
|
-
|
|
211
|
-
})
|
|
89
|
+
await this.datastore.put(key, buffer)
|
|
212
90
|
}
|
|
213
91
|
|
|
214
92
|
/**
|
|
215
|
-
*
|
|
93
|
+
* Load providers for the given CID from the store
|
|
216
94
|
*/
|
|
217
|
-
async
|
|
218
|
-
|
|
219
|
-
this.log('get providers for %s', cid)
|
|
220
|
-
const provs = await this._getProvidersMap(cid)
|
|
221
|
-
|
|
222
|
-
return [...provs.keys()].map(peerIdStr => {
|
|
223
|
-
return peerIdFromString(peerIdStr)
|
|
224
|
-
})
|
|
225
|
-
}, {
|
|
226
|
-
// no timeout is specified for this queue so it will not
|
|
227
|
-
// throw, but this is required to get the right return
|
|
228
|
-
// type since p-queue@7.3.4
|
|
229
|
-
throwOnTimeout: true
|
|
230
|
-
})
|
|
231
|
-
}
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
/**
|
|
235
|
-
* Encode the given key its matching datastore key
|
|
236
|
-
*/
|
|
237
|
-
function makeProviderKey (cid: CID | string): string {
|
|
238
|
-
const cidStr = typeof cid === 'string' ? cid : uint8ArrayToString(cid.multihash.bytes, 'base32')
|
|
239
|
-
|
|
240
|
-
return `${PROVIDER_KEY_PREFIX}/${cidStr}`
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Write a provider into the given store
|
|
245
|
-
*/
|
|
246
|
-
async function writeProviderEntry (store: Datastore, cid: CID, peer: PeerId, time: Date): Promise<void> {
|
|
247
|
-
const dsKey = [
|
|
248
|
-
makeProviderKey(cid),
|
|
249
|
-
'/',
|
|
250
|
-
peer.toString()
|
|
251
|
-
].join('')
|
|
95
|
+
private async loadProviders (cid: CID): Promise<PeerMap<Date>> {
|
|
96
|
+
const providers = new PeerMap<Date>()
|
|
252
97
|
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
|
|
259
|
-
/**
|
|
260
|
-
* Parse the CID and provider peer id from the key
|
|
261
|
-
*/
|
|
262
|
-
function parseProviderKey (key: Key): { cid: string, peerId: string } {
|
|
263
|
-
const parts = key.toString().split('/')
|
|
264
|
-
|
|
265
|
-
if (parts.length !== 5) {
|
|
266
|
-
throw new Error(`incorrectly formatted provider entry key in datastore: ${key.toString()}`)
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
return {
|
|
270
|
-
cid: parts[3],
|
|
271
|
-
peerId: parts[4]
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
/**
|
|
276
|
-
* Load providers for the given CID from the store
|
|
277
|
-
*/
|
|
278
|
-
async function loadProviders (store: Datastore, cid: CID): Promise<Map<string, Date>> {
|
|
279
|
-
const providers = new Map<string, Date>()
|
|
280
|
-
const query = store.query({ prefix: makeProviderKey(cid) })
|
|
98
|
+
for await (const entry of this.datastore.query({ prefix: toProviderKey(this.datastorePrefix, cid).toString() })) {
|
|
99
|
+
const { peerId } = parseProviderKey(entry.key)
|
|
100
|
+
providers.set(peerId, readProviderTime(entry.value))
|
|
101
|
+
}
|
|
281
102
|
|
|
282
|
-
|
|
283
|
-
const { peerId } = parseProviderKey(entry.key)
|
|
284
|
-
providers.set(peerId, readTime(entry.value))
|
|
103
|
+
return providers
|
|
285
104
|
}
|
|
286
|
-
|
|
287
|
-
return providers
|
|
288
|
-
}
|
|
289
|
-
|
|
290
|
-
function readTime (buf: Uint8Array): Date {
|
|
291
|
-
return new Date(varint.decode(buf))
|
|
292
105
|
}
|
package/src/query/manager.ts
CHANGED
|
@@ -12,7 +12,7 @@ import { queryPath } from './query-path.js'
|
|
|
12
12
|
import type { QueryFunc } from './types.js'
|
|
13
13
|
import type { QueryEvent } from '../index.js'
|
|
14
14
|
import type { RoutingTable } from '../routing-table/index.js'
|
|
15
|
-
import type { ComponentLogger,
|
|
15
|
+
import type { ComponentLogger, Metrics, PeerId, RoutingOptions, Startable } from '@libp2p/interface'
|
|
16
16
|
import type { ConnectionManager } from '@libp2p/interface-internal'
|
|
17
17
|
import type { DeferredPromise } from 'p-defer'
|
|
18
18
|
|
|
@@ -22,6 +22,7 @@ export interface CleanUpEvents {
|
|
|
22
22
|
|
|
23
23
|
export interface QueryManagerInit {
|
|
24
24
|
logPrefix: string
|
|
25
|
+
metricsPrefix: string
|
|
25
26
|
disjointPaths?: number
|
|
26
27
|
alpha?: number
|
|
27
28
|
initialQuerySelfHasRun: DeferredPromise<void>
|
|
@@ -58,35 +59,23 @@ export class QueryManager implements Startable {
|
|
|
58
59
|
private readonly routingTable: RoutingTable
|
|
59
60
|
private initialQuerySelfHasRun?: DeferredPromise<void>
|
|
60
61
|
private readonly logPrefix: string
|
|
61
|
-
private readonly metrics: {
|
|
62
|
-
queries?: Counter
|
|
63
|
-
errors?: Counter
|
|
64
|
-
queryTime?: Metric
|
|
65
|
-
}
|
|
66
62
|
|
|
67
63
|
constructor (components: QueryManagerComponents, init: QueryManagerInit) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
this.
|
|
71
|
-
this.disjointPaths = disjointPaths ?? K
|
|
72
|
-
this.running = false
|
|
73
|
-
this.alpha = alpha ?? ALPHA
|
|
64
|
+
this.logPrefix = init.logPrefix
|
|
65
|
+
this.disjointPaths = init.disjointPaths ?? K
|
|
66
|
+
this.alpha = init.alpha ?? ALPHA
|
|
74
67
|
this.initialQuerySelfHasRun = init.initialQuerySelfHasRun
|
|
75
68
|
this.routingTable = init.routingTable
|
|
76
69
|
this.logger = components.logger
|
|
77
70
|
this.peerId = components.peerId
|
|
78
71
|
this.connectionManager = components.connectionManager
|
|
79
72
|
|
|
80
|
-
this.metrics = {
|
|
81
|
-
queries: components.metrics?.registerCounter(`${logPrefix.replaceAll(':', '_')}_queries_total`),
|
|
82
|
-
errors: components.metrics?.registerCounter(`${logPrefix.replaceAll(':', '_')}_query_errors_total`),
|
|
83
|
-
queryTime: components.metrics?.registerMetric(`${logPrefix.replaceAll(':', '_')}_query_time_seconds`)
|
|
84
|
-
}
|
|
85
|
-
|
|
86
73
|
// allow us to stop queries on shut down
|
|
87
74
|
this.shutDownController = new AbortController()
|
|
88
75
|
// make sure we don't make a lot of noise in the logs
|
|
89
76
|
setMaxListeners(Infinity, this.shutDownController.signal)
|
|
77
|
+
|
|
78
|
+
this.running = false
|
|
90
79
|
}
|
|
91
80
|
|
|
92
81
|
isStarted (): boolean {
|
|
@@ -97,6 +86,10 @@ export class QueryManager implements Startable {
|
|
|
97
86
|
* Starts the query manager
|
|
98
87
|
*/
|
|
99
88
|
async start (): Promise<void> {
|
|
89
|
+
if (this.running) {
|
|
90
|
+
return
|
|
91
|
+
}
|
|
92
|
+
|
|
100
93
|
this.running = true
|
|
101
94
|
|
|
102
95
|
// allow us to stop queries on shut down
|
|
@@ -119,8 +112,6 @@ export class QueryManager implements Startable {
|
|
|
119
112
|
throw new Error('QueryManager not started')
|
|
120
113
|
}
|
|
121
114
|
|
|
122
|
-
const stopQueryTimer = this.metrics.queryTime?.timer()
|
|
123
|
-
|
|
124
115
|
if (options.signal == null) {
|
|
125
116
|
// don't let queries run forever
|
|
126
117
|
const signal = AbortSignal.timeout(DEFAULT_QUERY_TIMEOUT)
|
|
@@ -152,7 +143,6 @@ export class QueryManager implements Startable {
|
|
|
152
143
|
const log = this.logger.forComponent(`${this.logPrefix}:query:` + uint8ArrayToString(key, 'base58btc'))
|
|
153
144
|
|
|
154
145
|
// query a subset of peers up to `kBucketSize / 2` in length
|
|
155
|
-
const startTime = Date.now()
|
|
156
146
|
let queryFinished = false
|
|
157
147
|
|
|
158
148
|
try {
|
|
@@ -165,7 +155,6 @@ export class QueryManager implements Startable {
|
|
|
165
155
|
}
|
|
166
156
|
|
|
167
157
|
log('query:start')
|
|
168
|
-
this.metrics?.queries?.increment()
|
|
169
158
|
|
|
170
159
|
const id = await convertBuffer(key)
|
|
171
160
|
const peers = this.routingTable.closestPeers(id)
|
|
@@ -220,10 +209,6 @@ export class QueryManager implements Startable {
|
|
|
220
209
|
|
|
221
210
|
queryFinished = true
|
|
222
211
|
} catch (err: any) {
|
|
223
|
-
if (!queryFinished) {
|
|
224
|
-
this.metrics?.errors?.increment()
|
|
225
|
-
}
|
|
226
|
-
|
|
227
212
|
if (!this.running && err.name === 'QueryAbortedError') {
|
|
228
213
|
// ignore query aborted errors that were thrown during query manager shutdown
|
|
229
214
|
} else {
|
|
@@ -237,8 +222,7 @@ export class QueryManager implements Startable {
|
|
|
237
222
|
|
|
238
223
|
signal.clear()
|
|
239
224
|
|
|
240
|
-
|
|
241
|
-
log('query:done in %dms', Date.now() - startTime)
|
|
225
|
+
log('query:done')
|
|
242
226
|
}
|
|
243
227
|
}
|
|
244
228
|
}
|
package/src/query-self.ts
CHANGED
|
@@ -6,6 +6,8 @@ import take from 'it-take'
|
|
|
6
6
|
import pDefer from 'p-defer'
|
|
7
7
|
import { pEvent } from 'p-event'
|
|
8
8
|
import { QUERY_SELF_INTERVAL, QUERY_SELF_TIMEOUT, K, QUERY_SELF_INITIAL_INTERVAL } from './constants.js'
|
|
9
|
+
import { timeOperationMethod } from './utils.js'
|
|
10
|
+
import type { OperationMetrics } from './kad-dht.js'
|
|
9
11
|
import type { PeerRouting } from './peer-routing/index.js'
|
|
10
12
|
import type { RoutingTable } from './routing-table/index.js'
|
|
11
13
|
import type { ComponentLogger, Logger, PeerId, Startable } from '@libp2p/interface'
|
|
@@ -20,6 +22,7 @@ export interface QuerySelfInit {
|
|
|
20
22
|
initialInterval?: number
|
|
21
23
|
queryTimeout?: number
|
|
22
24
|
initialQuerySelfHasRun: DeferredPromise<void>
|
|
25
|
+
operationMetrics: OperationMetrics
|
|
23
26
|
}
|
|
24
27
|
|
|
25
28
|
export interface QuerySelfComponents {
|
|
@@ -39,37 +42,37 @@ export class QuerySelf implements Startable {
|
|
|
39
42
|
private readonly interval: number
|
|
40
43
|
private readonly initialInterval: number
|
|
41
44
|
private readonly queryTimeout: number
|
|
42
|
-
private
|
|
45
|
+
private running: boolean
|
|
43
46
|
private timeoutId?: ReturnType<typeof setTimeout>
|
|
44
47
|
private controller?: AbortController
|
|
45
48
|
private initialQuerySelfHasRun?: DeferredPromise<void>
|
|
46
49
|
private querySelfPromise?: DeferredPromise<void>
|
|
47
50
|
|
|
48
51
|
constructor (components: QuerySelfComponents, init: QuerySelfInit) {
|
|
49
|
-
const { peerRouting, logPrefix, count, interval, queryTimeout, routingTable } = init
|
|
50
|
-
|
|
51
52
|
this.peerId = components.peerId
|
|
52
|
-
this.log = components.logger.forComponent(`${logPrefix}:query-self`)
|
|
53
|
-
this.
|
|
54
|
-
this.peerRouting = peerRouting
|
|
55
|
-
this.routingTable = routingTable
|
|
56
|
-
this.count = count ?? K
|
|
57
|
-
this.interval = interval ?? QUERY_SELF_INTERVAL
|
|
53
|
+
this.log = components.logger.forComponent(`${init.logPrefix}:query-self`)
|
|
54
|
+
this.running = false
|
|
55
|
+
this.peerRouting = init.peerRouting
|
|
56
|
+
this.routingTable = init.routingTable
|
|
57
|
+
this.count = init.count ?? K
|
|
58
|
+
this.interval = init.interval ?? QUERY_SELF_INTERVAL
|
|
58
59
|
this.initialInterval = init.initialInterval ?? QUERY_SELF_INITIAL_INTERVAL
|
|
59
|
-
this.queryTimeout = queryTimeout ?? QUERY_SELF_TIMEOUT
|
|
60
|
+
this.queryTimeout = init.queryTimeout ?? QUERY_SELF_TIMEOUT
|
|
60
61
|
this.initialQuerySelfHasRun = init.initialQuerySelfHasRun
|
|
62
|
+
|
|
63
|
+
this.querySelf = timeOperationMethod(this.querySelf.bind(this), init.operationMetrics, 'SELF_QUERY')
|
|
61
64
|
}
|
|
62
65
|
|
|
63
66
|
isStarted (): boolean {
|
|
64
|
-
return this.
|
|
67
|
+
return this.running
|
|
65
68
|
}
|
|
66
69
|
|
|
67
70
|
start (): void {
|
|
68
|
-
if (this.
|
|
71
|
+
if (this.running) {
|
|
69
72
|
return
|
|
70
73
|
}
|
|
71
74
|
|
|
72
|
-
this.
|
|
75
|
+
this.running = true
|
|
73
76
|
clearTimeout(this.timeoutId)
|
|
74
77
|
this.timeoutId = setTimeout(() => {
|
|
75
78
|
this.querySelf()
|
|
@@ -80,7 +83,7 @@ export class QuerySelf implements Startable {
|
|
|
80
83
|
}
|
|
81
84
|
|
|
82
85
|
stop (): void {
|
|
83
|
-
this.
|
|
86
|
+
this.running = false
|
|
84
87
|
|
|
85
88
|
if (this.timeoutId != null) {
|
|
86
89
|
clearTimeout(this.timeoutId)
|
|
@@ -92,7 +95,7 @@ export class QuerySelf implements Startable {
|
|
|
92
95
|
}
|
|
93
96
|
|
|
94
97
|
async querySelf (): Promise<void> {
|
|
95
|
-
if (!this.
|
|
98
|
+
if (!this.running) {
|
|
96
99
|
this.log('skip self-query because we are not started')
|
|
97
100
|
return
|
|
98
101
|
}
|
|
@@ -104,7 +107,7 @@ export class QuerySelf implements Startable {
|
|
|
104
107
|
|
|
105
108
|
this.querySelfPromise = pDefer()
|
|
106
109
|
|
|
107
|
-
if (this.
|
|
110
|
+
if (this.running) {
|
|
108
111
|
this.controller = new AbortController()
|
|
109
112
|
const signals = [this.controller.signal]
|
|
110
113
|
|
|
@@ -157,7 +160,7 @@ export class QuerySelf implements Startable {
|
|
|
157
160
|
this.querySelfPromise.resolve()
|
|
158
161
|
this.querySelfPromise = undefined
|
|
159
162
|
|
|
160
|
-
if (!this.
|
|
163
|
+
if (!this.running) {
|
|
161
164
|
return
|
|
162
165
|
}
|
|
163
166
|
|