@helia/bitswap 0.0.0-e582c63 → 1.0.0-338885f
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 +6 -1
- package/dist/src/bitswap.d.ts +3 -2
- package/dist/src/bitswap.d.ts.map +1 -1
- package/dist/src/bitswap.js +7 -14
- package/dist/src/bitswap.js.map +1 -1
- package/dist/src/index.d.ts +2 -38
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/network.d.ts +3 -4
- package/dist/src/network.d.ts.map +1 -1
- package/dist/src/network.js +28 -50
- package/dist/src/network.js.map +1 -1
- package/dist/src/peer-want-lists/index.d.ts +2 -2
- package/dist/src/peer-want-lists/index.d.ts.map +1 -1
- package/dist/src/peer-want-lists/index.js +2 -2
- package/dist/src/peer-want-lists/index.js.map +1 -1
- package/dist/src/session.d.ts +13 -8
- package/dist/src/session.d.ts.map +1 -1
- package/dist/src/session.js +25 -88
- package/dist/src/session.js.map +1 -1
- package/dist/src/stats.d.ts +2 -2
- package/dist/src/stats.d.ts.map +1 -1
- package/dist/src/stats.js +4 -4
- package/dist/src/stats.js.map +1 -1
- package/dist/src/want-list.d.ts +20 -23
- package/dist/src/want-list.d.ts.map +1 -1
- package/dist/src/want-list.js +130 -130
- package/dist/src/want-list.js.map +1 -1
- package/package.json +3 -4
- package/src/bitswap.ts +9 -16
- package/src/index.ts +2 -43
- package/src/network.ts +32 -59
- package/src/peer-want-lists/index.ts +4 -4
- package/src/session.ts +31 -120
- package/src/stats.ts +6 -6
- package/src/want-list.ts +197 -209
package/src/bitswap.ts
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
/* eslint-disable no-loop-func */
|
|
2
|
-
import { DEFAULT_SESSION_MAX_PROVIDERS, DEFAULT_SESSION_MIN_PROVIDERS, DEFAULT_SESSION_PROVIDER_QUERY_CONCURRENCY } from '@helia/interface'
|
|
3
2
|
import { setMaxListeners } from '@libp2p/interface'
|
|
4
3
|
import { anySignal } from 'any-signal'
|
|
5
4
|
import { Network } from './network.js'
|
|
@@ -7,7 +6,8 @@ import { PeerWantLists } from './peer-want-lists/index.js'
|
|
|
7
6
|
import { createBitswapSession } from './session.js'
|
|
8
7
|
import { Stats } from './stats.js'
|
|
9
8
|
import { WantList } from './want-list.js'
|
|
10
|
-
import type { BitswapOptions, Bitswap as BitswapInterface, BitswapWantProgressEvents, BitswapNotifyProgressEvents,
|
|
9
|
+
import type { BitswapOptions, Bitswap as BitswapInterface, BitswapWantProgressEvents, BitswapNotifyProgressEvents, WantListEntry, BitswapComponents } from './index.js'
|
|
10
|
+
import type { BlockBroker, CreateSessionOptions } from '@helia/interface'
|
|
11
11
|
import type { ComponentLogger, PeerId } from '@libp2p/interface'
|
|
12
12
|
import type { Logger } from '@libp2p/logger'
|
|
13
13
|
import type { AbortOptions } from '@multiformats/multiaddr'
|
|
@@ -62,28 +62,18 @@ export class Bitswap implements BitswapInterface {
|
|
|
62
62
|
}, init)
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
const minProviders = options?.minProviders ?? DEFAULT_SESSION_MIN_PROVIDERS
|
|
67
|
-
const maxProviders = options?.maxProviders ?? DEFAULT_SESSION_MAX_PROVIDERS
|
|
68
|
-
|
|
65
|
+
createSession (options: CreateSessionOptions = {}): Required<Pick<BlockBroker<BitswapWantProgressEvents>, 'retrieve'>> {
|
|
69
66
|
return createBitswapSession({
|
|
70
67
|
wantList: this.wantList,
|
|
71
68
|
network: this.network,
|
|
72
69
|
logger: this.logger
|
|
73
|
-
},
|
|
74
|
-
root,
|
|
75
|
-
queryConcurrency: options?.providerQueryConcurrency ?? DEFAULT_SESSION_PROVIDER_QUERY_CONCURRENCY,
|
|
76
|
-
minProviders,
|
|
77
|
-
maxProviders,
|
|
78
|
-
connectedPeers: options?.queryConnectedPeers !== false ? [...this.wantList.peers.keys()] : [],
|
|
79
|
-
signal: options?.signal
|
|
80
|
-
})
|
|
70
|
+
}, options)
|
|
81
71
|
}
|
|
82
72
|
|
|
83
73
|
async want (cid: CID, options: WantOptions = {}): Promise<Uint8Array> {
|
|
84
74
|
const controller = new AbortController()
|
|
85
|
-
setMaxListeners(Infinity, controller.signal)
|
|
86
75
|
const signal = anySignal([controller.signal, options.signal])
|
|
76
|
+
setMaxListeners(Infinity, controller.signal, signal)
|
|
87
77
|
|
|
88
78
|
// find providers and connect to them
|
|
89
79
|
this.network.findAndConnect(cid, {
|
|
@@ -117,7 +107,10 @@ export class Bitswap implements BitswapInterface {
|
|
|
117
107
|
* Sends notifications about the arrival of a block
|
|
118
108
|
*/
|
|
119
109
|
async notify (cid: CID, block: Uint8Array, options: ProgressOptions<BitswapNotifyProgressEvents> & AbortOptions = {}): Promise<void> {
|
|
120
|
-
await
|
|
110
|
+
await Promise.all([
|
|
111
|
+
this.peerWantLists.receivedBlock(cid, options),
|
|
112
|
+
this.wantList.receivedBlock(cid, options)
|
|
113
|
+
])
|
|
121
114
|
}
|
|
122
115
|
|
|
123
116
|
getWantlist (): WantListEntry[] {
|
package/src/index.ts
CHANGED
|
@@ -9,10 +9,9 @@
|
|
|
9
9
|
import { Bitswap as BitswapClass } from './bitswap.js'
|
|
10
10
|
import type { BitswapNetworkNotifyProgressEvents, BitswapNetworkWantProgressEvents } from './network.js'
|
|
11
11
|
import type { WantType } from './pb/message.js'
|
|
12
|
-
import type { CreateSessionOptions } from '@helia/interface'
|
|
12
|
+
import type { BlockBroker, CreateSessionOptions } from '@helia/interface'
|
|
13
13
|
import type { Routing } from '@helia/interface/routing'
|
|
14
14
|
import type { Libp2p, AbortOptions, Startable, ComponentLogger, Metrics, PeerId } from '@libp2p/interface'
|
|
15
|
-
import type { PeerSet } from '@libp2p/peer-collections'
|
|
16
15
|
import type { Blockstore } from 'interface-blockstore'
|
|
17
16
|
import type { CID } from 'multiformats/cid'
|
|
18
17
|
import type { MultihashHasher } from 'multiformats/hashes/interface'
|
|
@@ -29,52 +28,12 @@ export type BitswapWantBlockProgressEvents =
|
|
|
29
28
|
ProgressEvent<'bitswap:want-block:block', CID> |
|
|
30
29
|
BitswapNetworkWantProgressEvents
|
|
31
30
|
|
|
32
|
-
/**
|
|
33
|
-
* A bitswap session is a network overlay consisting of peers that all have the
|
|
34
|
-
* first block in a file. Subsequent requests will only go to these peers.
|
|
35
|
-
*/
|
|
36
|
-
export interface BitswapSession {
|
|
37
|
-
/**
|
|
38
|
-
* The peers in this session
|
|
39
|
-
*/
|
|
40
|
-
peers: PeerSet
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Fetch an additional CID from this DAG
|
|
44
|
-
*/
|
|
45
|
-
want(cid: CID, options?: AbortOptions & ProgressOptions<BitswapWantProgressEvents>): Promise<Uint8Array>
|
|
46
|
-
}
|
|
47
|
-
|
|
48
31
|
export interface WantListEntry {
|
|
49
32
|
cid: CID
|
|
50
33
|
priority: number
|
|
51
34
|
wantType: WantType
|
|
52
35
|
}
|
|
53
36
|
|
|
54
|
-
export interface CreateBitswapSessionOptions extends CreateSessionOptions<BitswapWantProgressEvents> {
|
|
55
|
-
/**
|
|
56
|
-
* If true, query connected peers before searching for providers via
|
|
57
|
-
* Helia routers
|
|
58
|
-
*
|
|
59
|
-
* @default true
|
|
60
|
-
*/
|
|
61
|
-
queryConnectedPeers?: boolean
|
|
62
|
-
|
|
63
|
-
/**
|
|
64
|
-
* If true, search for providers via Helia routers to query for the root CID
|
|
65
|
-
*
|
|
66
|
-
* @default true
|
|
67
|
-
*/
|
|
68
|
-
queryRoutingPeers?: boolean
|
|
69
|
-
|
|
70
|
-
/**
|
|
71
|
-
* The priority to use when querying availability of the root CID
|
|
72
|
-
*
|
|
73
|
-
* @default 1
|
|
74
|
-
*/
|
|
75
|
-
priority?: number
|
|
76
|
-
}
|
|
77
|
-
|
|
78
37
|
export interface Bitswap extends Startable {
|
|
79
38
|
/**
|
|
80
39
|
* Returns the current state of the wantlist
|
|
@@ -100,7 +59,7 @@ export interface Bitswap extends Startable {
|
|
|
100
59
|
/**
|
|
101
60
|
* Start a session to retrieve a file from the network
|
|
102
61
|
*/
|
|
103
|
-
createSession(
|
|
62
|
+
createSession(options?: CreateSessionOptions<BitswapWantProgressEvents>): Required<Pick<BlockBroker<BitswapWantProgressEvents>, 'retrieve'>>
|
|
104
63
|
}
|
|
105
64
|
|
|
106
65
|
export interface MultihashHasherLoader {
|
package/src/network.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { CodeError, TypedEventEmitter, setMaxListeners } from '@libp2p/interface'
|
|
2
2
|
import { PeerQueue, type PeerQueueJobOptions } from '@libp2p/utils/peer-queue'
|
|
3
|
-
import { Circuit } from '@multiformats/multiaddr-matcher'
|
|
4
3
|
import { anySignal } from 'any-signal'
|
|
5
4
|
import debug from 'debug'
|
|
6
5
|
import drain from 'it-drain'
|
|
@@ -14,13 +13,13 @@ import { CID } from 'multiformats/cid'
|
|
|
14
13
|
import { CustomProgressEvent } from 'progress-events'
|
|
15
14
|
import { raceEvent } from 'race-event'
|
|
16
15
|
import { toString as uint8ArrayToString } from 'uint8arrays/to-string'
|
|
17
|
-
import { BITSWAP_120, DEFAULT_MAX_INBOUND_STREAMS, DEFAULT_MAX_OUTBOUND_STREAMS, DEFAULT_MAX_PROVIDERS_PER_REQUEST, DEFAULT_MESSAGE_RECEIVE_TIMEOUT, DEFAULT_MESSAGE_SEND_TIMEOUT, DEFAULT_RUN_ON_TRANSIENT_CONNECTIONS } from './constants.js'
|
|
16
|
+
import { BITSWAP_120, DEFAULT_MAX_INBOUND_STREAMS, DEFAULT_MAX_OUTBOUND_STREAMS, DEFAULT_MAX_PROVIDERS_PER_REQUEST, DEFAULT_MESSAGE_RECEIVE_TIMEOUT, DEFAULT_MESSAGE_SEND_CONCURRENCY, DEFAULT_MESSAGE_SEND_TIMEOUT, DEFAULT_RUN_ON_TRANSIENT_CONNECTIONS } from './constants.js'
|
|
18
17
|
import { BitswapMessage } from './pb/message.js'
|
|
19
18
|
import type { WantOptions } from './bitswap.js'
|
|
20
19
|
import type { MultihashHasherLoader } from './index.js'
|
|
21
20
|
import type { Block, BlockPresence, WantlistEntry } from './pb/message.js'
|
|
22
21
|
import type { Provider, Routing } from '@helia/interface/routing'
|
|
23
|
-
import type { Libp2p, AbortOptions, Connection, PeerId, IncomingStreamData, Topology,
|
|
22
|
+
import type { Libp2p, AbortOptions, Connection, PeerId, IncomingStreamData, Topology, ComponentLogger, IdentifyResult, Counter } from '@libp2p/interface'
|
|
24
23
|
import type { Logger } from '@libp2p/logger'
|
|
25
24
|
import type { ProgressEvent, ProgressOptions } from 'progress-events'
|
|
26
25
|
|
|
@@ -79,7 +78,6 @@ export interface NetworkComponents {
|
|
|
79
78
|
routing: Routing
|
|
80
79
|
logger: ComponentLogger
|
|
81
80
|
libp2p: Libp2p
|
|
82
|
-
metrics?: Metrics
|
|
83
81
|
}
|
|
84
82
|
|
|
85
83
|
export interface BitswapMessageEventDetail {
|
|
@@ -107,7 +105,7 @@ export class Network extends TypedEventEmitter<NetworkEvents> {
|
|
|
107
105
|
private readonly maxOutboundStreams: number
|
|
108
106
|
private readonly messageReceiveTimeout: number
|
|
109
107
|
private registrarIds: string[]
|
|
110
|
-
private readonly metrics
|
|
108
|
+
private readonly metrics: { blocksSent?: Counter, dataSent?: Counter }
|
|
111
109
|
private readonly sendQueue: PeerQueue<void, SendMessageJobOptions>
|
|
112
110
|
private readonly messageSendTimeout: number
|
|
113
111
|
private readonly runOnTransientConnections: boolean
|
|
@@ -129,18 +127,15 @@ export class Network extends TypedEventEmitter<NetworkEvents> {
|
|
|
129
127
|
this.messageReceiveTimeout = init.messageReceiveTimeout ?? DEFAULT_MESSAGE_RECEIVE_TIMEOUT
|
|
130
128
|
this.messageSendTimeout = init.messageSendTimeout ?? DEFAULT_MESSAGE_SEND_TIMEOUT
|
|
131
129
|
this.runOnTransientConnections = init.runOnTransientConnections ?? DEFAULT_RUN_ON_TRANSIENT_CONNECTIONS
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
blocksSent: components.metrics?.registerMetricGroup('ipfs_bitswap_sent_blocks'),
|
|
136
|
-
dataSent: components.metrics?.registerMetricGroup('ipfs_bitswap_sent_data_bytes')
|
|
137
|
-
}
|
|
130
|
+
this.metrics = {
|
|
131
|
+
blocksSent: components.libp2p.metrics?.registerCounter('helia_bitswap_sent_blocks_total'),
|
|
132
|
+
dataSent: components.libp2p.metrics?.registerCounter('helia_bitswap_sent_data_bytes_total')
|
|
138
133
|
}
|
|
139
134
|
|
|
140
135
|
this.sendQueue = new PeerQueue({
|
|
141
|
-
concurrency: init.messageSendConcurrency,
|
|
142
|
-
metrics: components.metrics,
|
|
143
|
-
metricName: '
|
|
136
|
+
concurrency: init.messageSendConcurrency ?? DEFAULT_MESSAGE_SEND_CONCURRENCY,
|
|
137
|
+
metrics: components.libp2p.metrics,
|
|
138
|
+
metricName: 'helia_bitswap_message_send_queue'
|
|
144
139
|
})
|
|
145
140
|
this.sendQueue.addEventListener('error', (evt) => {
|
|
146
141
|
this.log.error('error sending wantlist to peer', evt.detail)
|
|
@@ -267,29 +262,12 @@ export class Network extends TypedEventEmitter<NetworkEvents> {
|
|
|
267
262
|
options?.onProgress?.(new CustomProgressEvent<PeerId>('bitswap:network:find-providers', cid))
|
|
268
263
|
|
|
269
264
|
for await (const provider of this.routing.findProviders(cid, options)) {
|
|
270
|
-
//
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
for (let ma of provider.multiaddrs) {
|
|
276
|
-
if (ma.getPeerId() == null) {
|
|
277
|
-
ma = ma.encapsulate(`/p2p/${provider.id}`)
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
if (!Circuit.exactMatch(ma)) {
|
|
281
|
-
hasDirectAddress = true
|
|
282
|
-
break
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
if (!hasDirectAddress) {
|
|
287
|
-
continue
|
|
288
|
-
}
|
|
289
|
-
}
|
|
265
|
+
// make sure we can dial the provider
|
|
266
|
+
const dialable = await this.libp2p.isDialable(provider.multiaddrs, {
|
|
267
|
+
runOnTransientConnection: this.runOnTransientConnections
|
|
268
|
+
})
|
|
290
269
|
|
|
291
|
-
|
|
292
|
-
if (provider.protocols?.includes('transport-bitswap') === false) {
|
|
270
|
+
if (!dialable) {
|
|
293
271
|
continue
|
|
294
272
|
}
|
|
295
273
|
|
|
@@ -302,9 +280,9 @@ export class Network extends TypedEventEmitter<NetworkEvents> {
|
|
|
302
280
|
*/
|
|
303
281
|
async findAndConnect (cid: CID, options?: WantOptions): Promise<void> {
|
|
304
282
|
await drain(
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
283
|
+
map(
|
|
284
|
+
take(this.findProviders(cid, options), options?.maxProviders ?? DEFAULT_MAX_PROVIDERS_PER_REQUEST),
|
|
285
|
+
async provider => this.connectTo(provider.id, options)
|
|
308
286
|
)
|
|
309
287
|
)
|
|
310
288
|
.catch(err => {
|
|
@@ -331,13 +309,16 @@ export class Network extends TypedEventEmitter<NetworkEvents> {
|
|
|
331
309
|
pendingBytes: msg.pendingBytes ?? 0
|
|
332
310
|
}
|
|
333
311
|
|
|
334
|
-
const
|
|
335
|
-
|
|
312
|
+
const timeoutSignal = AbortSignal.timeout(this.messageSendTimeout)
|
|
313
|
+
const signal = anySignal([timeoutSignal, options?.signal])
|
|
314
|
+
setMaxListeners(Infinity, timeoutSignal, signal)
|
|
336
315
|
|
|
337
316
|
try {
|
|
338
|
-
const existingJob = this.sendQueue.find(
|
|
317
|
+
const existingJob = this.sendQueue.queue.find(job => {
|
|
318
|
+
return peerId.equals(job.options.peerId) && job.status === 'queued'
|
|
319
|
+
})
|
|
339
320
|
|
|
340
|
-
if (existingJob
|
|
321
|
+
if (existingJob != null) {
|
|
341
322
|
// merge messages instead of adding new job
|
|
342
323
|
existingJob.options.message = mergeMessages(existingJob.options.message, message)
|
|
343
324
|
|
|
@@ -371,7 +352,7 @@ export class Network extends TypedEventEmitter<NetworkEvents> {
|
|
|
371
352
|
stream.abort(err)
|
|
372
353
|
}
|
|
373
354
|
|
|
374
|
-
this._updateSentStats(
|
|
355
|
+
this._updateSentStats(message.blocks)
|
|
375
356
|
}, {
|
|
376
357
|
peerId,
|
|
377
358
|
signal,
|
|
@@ -417,23 +398,15 @@ export class Network extends TypedEventEmitter<NetworkEvents> {
|
|
|
417
398
|
return connection
|
|
418
399
|
}
|
|
419
400
|
|
|
420
|
-
_updateSentStats (
|
|
421
|
-
|
|
422
|
-
let bytes = 0
|
|
423
|
-
|
|
424
|
-
for (const block of blocks.values()) {
|
|
425
|
-
bytes += block.data.byteLength
|
|
426
|
-
}
|
|
401
|
+
_updateSentStats (blocks: Block[] = []): void {
|
|
402
|
+
let bytes = 0
|
|
427
403
|
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
[peerId.toString()]: bytes
|
|
431
|
-
})
|
|
432
|
-
this.metrics.blocksSent.increment({
|
|
433
|
-
global: blocks.length,
|
|
434
|
-
[peerId.toString()]: blocks.length
|
|
435
|
-
})
|
|
404
|
+
for (const block of blocks.values()) {
|
|
405
|
+
bytes += block.data.byteLength
|
|
436
406
|
}
|
|
407
|
+
|
|
408
|
+
this.metrics.dataSent?.increment(bytes)
|
|
409
|
+
this.metrics.blocksSent?.increment(blocks.length)
|
|
437
410
|
}
|
|
438
411
|
}
|
|
439
412
|
|
|
@@ -6,7 +6,7 @@ import { Ledger } from './ledger.js'
|
|
|
6
6
|
import type { BitswapNotifyProgressEvents, WantListEntry } from '../index.js'
|
|
7
7
|
import type { Network } from '../network.js'
|
|
8
8
|
import type { BitswapMessage } from '../pb/message.js'
|
|
9
|
-
import type { ComponentLogger,
|
|
9
|
+
import type { ComponentLogger, Libp2p, Logger, PeerId } from '@libp2p/interface'
|
|
10
10
|
import type { PeerMap } from '@libp2p/peer-collections'
|
|
11
11
|
import type { Blockstore } from 'interface-blockstore'
|
|
12
12
|
import type { AbortOptions } from 'it-length-prefixed-stream'
|
|
@@ -19,7 +19,7 @@ export interface PeerWantListsInit {
|
|
|
19
19
|
export interface PeerWantListsComponents {
|
|
20
20
|
blockstore: Blockstore
|
|
21
21
|
network: Network
|
|
22
|
-
|
|
22
|
+
libp2p: Libp2p
|
|
23
23
|
logger: ComponentLogger
|
|
24
24
|
}
|
|
25
25
|
|
|
@@ -45,8 +45,8 @@ export class PeerWantLists {
|
|
|
45
45
|
this.log = components.logger.forComponent('helia:bitswap:peer-want-lists')
|
|
46
46
|
|
|
47
47
|
this.ledgerMap = trackedPeerMap({
|
|
48
|
-
name: '
|
|
49
|
-
metrics: components.metrics
|
|
48
|
+
name: 'helia_bitswap_ledger_map',
|
|
49
|
+
metrics: components.libp2p.metrics
|
|
50
50
|
})
|
|
51
51
|
|
|
52
52
|
this.network.addEventListener('bitswap:message', (evt) => {
|
package/src/session.ts
CHANGED
|
@@ -1,16 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { PeerQueue } from '@libp2p/utils/peer-queue'
|
|
4
|
-
import map from 'it-map'
|
|
5
|
-
import merge from 'it-merge'
|
|
6
|
-
import pDefer, { type DeferredPromise } from 'p-defer'
|
|
7
|
-
import type { BitswapWantProgressEvents, BitswapSession as BitswapSessionInterface } from './index.js'
|
|
1
|
+
import { AbstractSession } from '@helia/utils'
|
|
2
|
+
import type { BitswapWantProgressEvents } from './index.js'
|
|
8
3
|
import type { Network } from './network.js'
|
|
9
4
|
import type { WantList } from './want-list.js'
|
|
10
|
-
import type {
|
|
5
|
+
import type { CreateSessionOptions } from '@helia/interface'
|
|
6
|
+
import type { ComponentLogger, PeerId } from '@libp2p/interface'
|
|
11
7
|
import type { AbortOptions } from 'interface-store'
|
|
12
8
|
import type { CID } from 'multiformats/cid'
|
|
13
|
-
import type { ProgressOptions } from 'progress-events'
|
|
14
9
|
|
|
15
10
|
export interface BitswapSessionComponents {
|
|
16
11
|
network: Network
|
|
@@ -18,133 +13,49 @@ export interface BitswapSessionComponents {
|
|
|
18
13
|
logger: ComponentLogger
|
|
19
14
|
}
|
|
20
15
|
|
|
21
|
-
|
|
22
|
-
root: CID
|
|
23
|
-
queryConcurrency: number
|
|
24
|
-
minProviders: number
|
|
25
|
-
maxProviders: number
|
|
26
|
-
connectedPeers: PeerId[]
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
class BitswapSession implements BitswapSessionInterface {
|
|
30
|
-
public readonly root: CID
|
|
31
|
-
public readonly peers: PeerSet
|
|
32
|
-
private readonly log: Logger
|
|
16
|
+
class BitswapSession extends AbstractSession<PeerId, BitswapWantProgressEvents> {
|
|
33
17
|
private readonly wantList: WantList
|
|
34
18
|
private readonly network: Network
|
|
35
|
-
private readonly queue: PeerQueue
|
|
36
|
-
private readonly maxProviders: number
|
|
37
19
|
|
|
38
|
-
constructor (components: BitswapSessionComponents, init:
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
20
|
+
constructor (components: BitswapSessionComponents, init: CreateSessionOptions) {
|
|
21
|
+
super(components, {
|
|
22
|
+
...init,
|
|
23
|
+
name: 'helia:bitswap:session'
|
|
24
|
+
})
|
|
25
|
+
|
|
43
26
|
this.wantList = components.wantList
|
|
44
27
|
this.network = components.network
|
|
45
|
-
|
|
46
|
-
this.queue = new PeerQueue({
|
|
47
|
-
concurrency: init.queryConcurrency
|
|
48
|
-
})
|
|
49
|
-
this.queue.addEventListener('error', (evt) => {
|
|
50
|
-
this.log.error('error querying peer for %c', this.root, evt.detail)
|
|
51
|
-
})
|
|
52
28
|
}
|
|
53
29
|
|
|
54
|
-
async
|
|
55
|
-
|
|
56
|
-
throw new CodeError('Bitswap session had no peers', 'ERR_NO_SESSION_PEERS')
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
this.log('sending WANT-BLOCK for %c to', cid, this.peers)
|
|
30
|
+
async queryProvider (cid: CID, provider: PeerId, options: AbortOptions): Promise<Uint8Array> {
|
|
31
|
+
this.log('sending WANT-BLOCK for %c to %p', cid, provider)
|
|
60
32
|
|
|
61
|
-
const result = await
|
|
62
|
-
[...this.peers].map(async peerId => {
|
|
63
|
-
return this.wantList.wantBlock(cid, {
|
|
64
|
-
peerId,
|
|
65
|
-
...options
|
|
66
|
-
})
|
|
67
|
-
})
|
|
68
|
-
)
|
|
33
|
+
const result = await this.wantList.wantSessionBlock(cid, provider, options)
|
|
69
34
|
|
|
70
|
-
this.log('
|
|
35
|
+
this.log('%p %s %c', provider, result.has ? 'has' : 'does not have', cid)
|
|
71
36
|
|
|
72
|
-
|
|
73
|
-
|
|
37
|
+
if (result.has && result.block != null) {
|
|
38
|
+
return result.block
|
|
39
|
+
}
|
|
74
40
|
|
|
75
|
-
|
|
41
|
+
throw new Error('Provider did not have block')
|
|
76
42
|
}
|
|
77
43
|
|
|
78
|
-
async findNewProviders (cid: CID,
|
|
79
|
-
const
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const source = merge(
|
|
85
|
-
[...this.wantList.peers.keys()],
|
|
86
|
-
map(this.network.findProviders(cid, options), prov => prov.id)
|
|
87
|
-
)
|
|
88
|
-
|
|
89
|
-
void Promise.resolve()
|
|
90
|
-
.then(async () => {
|
|
91
|
-
for await (const peerId of source) {
|
|
92
|
-
// eslint-disable-next-line no-loop-func
|
|
93
|
-
await this.queue.add(async () => {
|
|
94
|
-
try {
|
|
95
|
-
this.log('asking potential session peer %p if they have %c', peerId, cid)
|
|
96
|
-
const result = await this.wantList.wantPresence(cid, {
|
|
97
|
-
peerId,
|
|
98
|
-
...options
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
if (!result.has) {
|
|
102
|
-
this.log('potential session peer %p did not have %c', peerId, cid)
|
|
103
|
-
return
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
this.log('potential session peer %p had %c', peerId, cid)
|
|
107
|
-
found++
|
|
108
|
-
|
|
109
|
-
// add to list
|
|
110
|
-
this.peers.add(peerId)
|
|
111
|
-
|
|
112
|
-
if (found === count) {
|
|
113
|
-
this.log('found %d session peers', found)
|
|
114
|
-
|
|
115
|
-
deferred.resolve()
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (found === this.maxProviders) {
|
|
119
|
-
this.log('found max provider session peers', found)
|
|
120
|
-
|
|
121
|
-
this.queue.clear()
|
|
122
|
-
}
|
|
123
|
-
} catch (err: any) {
|
|
124
|
-
this.log.error('error querying potential session peer %p for %c', peerId, cid, err.errors ?? err)
|
|
125
|
-
}
|
|
126
|
-
}, {
|
|
127
|
-
peerId
|
|
128
|
-
})
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
this.log('found %d session peers total', found)
|
|
44
|
+
async * findNewProviders (cid: CID, options: AbortOptions = {}): AsyncGenerator<PeerId> {
|
|
45
|
+
for await (const provider of this.network.findProviders(cid, options)) {
|
|
46
|
+
yield provider.id
|
|
47
|
+
}
|
|
48
|
+
}
|
|
132
49
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
})
|
|
50
|
+
toEvictionKey (provider: PeerId): Uint8Array | string {
|
|
51
|
+
return provider.toBytes()
|
|
52
|
+
}
|
|
137
53
|
|
|
138
|
-
|
|
54
|
+
equals (providerA: PeerId, providerB: PeerId): boolean {
|
|
55
|
+
return providerA.equals(providerB)
|
|
139
56
|
}
|
|
140
57
|
}
|
|
141
58
|
|
|
142
|
-
export
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
await session.findNewProviders(init.root, init.minProviders, {
|
|
146
|
-
signal: init.signal
|
|
147
|
-
})
|
|
148
|
-
|
|
149
|
-
return session
|
|
59
|
+
export function createBitswapSession (components: BitswapSessionComponents, init: CreateSessionOptions): BitswapSession {
|
|
60
|
+
return new BitswapSession(components, init)
|
|
150
61
|
}
|
package/src/stats.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Libp2p, MetricGroup, PeerId } from '@libp2p/interface'
|
|
2
2
|
|
|
3
3
|
export interface StatsComponents {
|
|
4
|
-
|
|
4
|
+
libp2p: Libp2p
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export class Stats {
|
|
@@ -11,10 +11,10 @@ export class Stats {
|
|
|
11
11
|
private readonly duplicateDataReceived?: MetricGroup
|
|
12
12
|
|
|
13
13
|
constructor (components: StatsComponents) {
|
|
14
|
-
this.blocksReceived = components.metrics?.registerMetricGroup('
|
|
15
|
-
this.duplicateBlocksReceived = components.metrics?.registerMetricGroup('
|
|
16
|
-
this.dataReceived = components.metrics?.registerMetricGroup('
|
|
17
|
-
this.duplicateDataReceived = components.metrics?.registerMetricGroup('
|
|
14
|
+
this.blocksReceived = components.libp2p.metrics?.registerMetricGroup('helia_bitswap_received_blocks')
|
|
15
|
+
this.duplicateBlocksReceived = components.libp2p.metrics?.registerMetricGroup('helia_bitswap_duplicate_received_blocks')
|
|
16
|
+
this.dataReceived = components.libp2p.metrics?.registerMetricGroup('helia_bitswap_data_received_bytes')
|
|
17
|
+
this.duplicateDataReceived = components.libp2p.metrics?.registerMetricGroup('helia_bitswap_duplicate_data_received_bytes')
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
updateBlocksReceived (count: number = 1, peerId?: PeerId): void {
|