@helia/utils 2.3.5-7bf85e0c → 2.4.0-f058fba8

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.
@@ -0,0 +1,56 @@
1
+ import type { HasherLoader } from '@helia/interface';
2
+ import type { BlockBroker, Pair, DeleteManyBlocksProgressEvents, DeleteBlockProgressEvents, GetBlockProgressEvents, GetManyBlocksProgressEvents, PutManyBlocksProgressEvents, PutBlockProgressEvents, GetAllBlocksProgressEvents, GetOfflineOptions, BlockRetrievalOptions } from '@helia/interface/blocks';
3
+ import type { AbortOptions, ComponentLogger, Logger } from '@libp2p/interface';
4
+ import type { Blockstore, InputPair } from 'interface-blockstore';
5
+ import type { AwaitIterable } from 'interface-store';
6
+ import type { CID } from 'multiformats/cid';
7
+ import type { MultihashHasher } from 'multiformats/hashes/interface';
8
+ import type { ProgressEvent, ProgressOptions } from 'progress-events';
9
+ export interface StorageComponents<Broker extends BlockBroker<ProgressEvent<any, any>, ProgressEvent<any, any>>> {
10
+ blockstore: Blockstore;
11
+ logger: ComponentLogger;
12
+ blockBrokers: Broker[];
13
+ getHasher: HasherLoader;
14
+ }
15
+ export interface StorageInit {
16
+ maxIdentityHashDigestLength?: number;
17
+ }
18
+ export declare class Storage<Broker extends BlockBroker<ProgressEvent<any, any>, ProgressEvent<any, any>>> implements Blockstore {
19
+ protected readonly child: Blockstore;
20
+ protected readonly getHasher: HasherLoader;
21
+ protected log: Logger;
22
+ protected readonly logger: ComponentLogger;
23
+ protected readonly blockBrokers: Broker[];
24
+ /**
25
+ * Create a new BlockStorage
26
+ */
27
+ constructor(components: StorageComponents<Broker>, init?: StorageInit);
28
+ /**
29
+ * Put a block to the underlying datastore
30
+ */
31
+ put(cid: CID, block: Uint8Array, options?: AbortOptions & ProgressOptions<PutBlockProgressEvents>): Promise<CID>;
32
+ /**
33
+ * Put a multiple blocks to the underlying datastore
34
+ */
35
+ putMany(blocks: AwaitIterable<InputPair>, options?: AbortOptions & ProgressOptions<PutManyBlocksProgressEvents>): AsyncGenerator<CID>;
36
+ /**
37
+ * Get a block by cid
38
+ */
39
+ get(cid: CID, options?: GetOfflineOptions & AbortOptions & ProgressOptions<GetBlockProgressEvents>): AsyncGenerator<Uint8Array>;
40
+ /**
41
+ * Get multiple blocks back from an (async) iterable of cids
42
+ */
43
+ getMany(cids: AwaitIterable<CID>, options?: GetOfflineOptions & AbortOptions & ProgressOptions<GetManyBlocksProgressEvents>): AsyncGenerator<Pair>;
44
+ /**
45
+ * Delete a block from the blockstore
46
+ */
47
+ delete(cid: CID, options?: AbortOptions & ProgressOptions<DeleteBlockProgressEvents>): Promise<void>;
48
+ /**
49
+ * Delete multiple blocks from the blockstore
50
+ */
51
+ deleteMany(cids: AwaitIterable<CID>, options?: AbortOptions & ProgressOptions<DeleteManyBlocksProgressEvents>): AsyncGenerator<CID>;
52
+ has(cid: CID, options?: AbortOptions): Promise<boolean>;
53
+ getAll(options?: AbortOptions & ProgressOptions<GetAllBlocksProgressEvents>): AsyncGenerator<Pair>;
54
+ }
55
+ export declare const getCidBlockVerifierFunction: (cid: CID, hasher: MultihashHasher) => Required<BlockRetrievalOptions>["validateFn"];
56
+ //# sourceMappingURL=storage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/utils/storage.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,225 @@
1
+ import { InvalidMultihashError, InvalidParametersError, setMaxListeners } from '@libp2p/interface';
2
+ import { anySignal } from 'any-signal';
3
+ import { IdentityBlockstore } from 'blockstore-core/identity';
4
+ import filter from 'it-filter';
5
+ import forEach from 'it-foreach';
6
+ import { CustomProgressEvent } from 'progress-events';
7
+ import { equals as uint8ArrayEquals } from 'uint8arrays/equals';
8
+ import { BlockNotFoundWhileOfflineError, InvalidConfigurationError, LoadBlockFailedError } from "../errors.js";
9
+ import { isPromise } from './is-promise.js';
10
+ const DEFAULT_MAX_IDENTITY_HASH_DIGEST_LENGTH = 128;
11
+ export class Storage {
12
+ child;
13
+ getHasher;
14
+ log;
15
+ logger;
16
+ blockBrokers;
17
+ /**
18
+ * Create a new BlockStorage
19
+ */
20
+ constructor(components, init = {}) {
21
+ this.log = components.logger.forComponent('helia:networked-storage');
22
+ this.logger = components.logger;
23
+ this.blockBrokers = components.blockBrokers;
24
+ this.child = new IdentityBlockstore(components.blockstore, {
25
+ maxDigestLength: init.maxIdentityHashDigestLength ?? DEFAULT_MAX_IDENTITY_HASH_DIGEST_LENGTH
26
+ });
27
+ this.getHasher = components.getHasher;
28
+ }
29
+ /**
30
+ * Put a block to the underlying datastore
31
+ */
32
+ async put(cid, block, options = {}) {
33
+ if (await this.child.has(cid, options)) {
34
+ options.onProgress?.(new CustomProgressEvent('blocks:put:duplicate', cid));
35
+ return cid;
36
+ }
37
+ options.onProgress?.(new CustomProgressEvent('blocks:put:providers:notify', cid));
38
+ await Promise.all(this.blockBrokers.map(async (broker) => broker.announce?.(cid, options)));
39
+ options.onProgress?.(new CustomProgressEvent('blocks:put:blockstore:put', cid));
40
+ return this.child.put(cid, block, options);
41
+ }
42
+ /**
43
+ * Put a multiple blocks to the underlying datastore
44
+ */
45
+ async *putMany(blocks, options = {}) {
46
+ const missingBlocks = filter(blocks, async ({ cid }) => {
47
+ const has = await this.child.has(cid, options);
48
+ if (has) {
49
+ options.onProgress?.(new CustomProgressEvent('blocks:put-many:duplicate', cid));
50
+ }
51
+ return !has;
52
+ });
53
+ const notifyEach = forEach(missingBlocks, async ({ cid }) => {
54
+ options.onProgress?.(new CustomProgressEvent('blocks:put-many:providers:notify', cid));
55
+ await Promise.all(this.blockBrokers.map(async (broker) => broker.announce?.(cid, options)));
56
+ });
57
+ options.onProgress?.(new CustomProgressEvent('blocks:put-many:blockstore:put-many'));
58
+ yield* this.child.putMany(notifyEach, options);
59
+ }
60
+ /**
61
+ * Get a block by cid
62
+ */
63
+ async *get(cid, options = {}) {
64
+ const has = await this.child.has(cid, options);
65
+ const offline = options.offline === true;
66
+ if (!has) {
67
+ if (offline) {
68
+ throw new BlockNotFoundWhileOfflineError('The block was present in the blockstore and the node is running offline so cannot fetch it');
69
+ }
70
+ const hasher = await this.getHasher(cid.multihash.code);
71
+ options?.signal?.throwIfAborted();
72
+ // we do not have the block locally, get it from a block provider
73
+ options.onProgress?.(new CustomProgressEvent('blocks:get:providers:get', cid));
74
+ const block = await raceBlockRetrievers(cid, this.blockBrokers, hasher, {
75
+ ...options,
76
+ log: this.log
77
+ });
78
+ options.onProgress?.(new CustomProgressEvent('blocks:get:blockstore:put', cid));
79
+ await this.child.put(cid, block, options);
80
+ // notify other block providers of the new block
81
+ options.onProgress?.(new CustomProgressEvent('blocks:get:providers:notify', cid));
82
+ await Promise.all(this.blockBrokers.map(async (broker) => broker.announce?.(cid, options)));
83
+ yield block;
84
+ return;
85
+ }
86
+ options.onProgress?.(new CustomProgressEvent('blocks:get:blockstore:get', cid));
87
+ yield* this.child.get(cid, options);
88
+ }
89
+ /**
90
+ * Get multiple blocks back from an (async) iterable of cids
91
+ */
92
+ async *getMany(cids, options = {}) {
93
+ options.onProgress?.(new CustomProgressEvent('blocks:get-many:blockstore:get-many'));
94
+ yield* this.child.getMany(forEach(cids, async (cid) => {
95
+ const has = await this.child.has(cid, options);
96
+ const offline = options.offline === true;
97
+ if (!has) {
98
+ if (offline) {
99
+ throw new BlockNotFoundWhileOfflineError('The block was present in the blockstore and the node is running offline so cannot fetch it');
100
+ }
101
+ const hasher = await this.getHasher(cid.multihash.code);
102
+ options?.signal?.throwIfAborted();
103
+ // we do not have the block locally, get it from a block provider
104
+ options.onProgress?.(new CustomProgressEvent('blocks:get-many:providers:get', cid));
105
+ const block = await raceBlockRetrievers(cid, this.blockBrokers, hasher, {
106
+ ...options,
107
+ log: this.log
108
+ });
109
+ options.onProgress?.(new CustomProgressEvent('blocks:get-many:blockstore:put', cid));
110
+ await this.child.put(cid, block, options);
111
+ // notify other block providers of the new block
112
+ options.onProgress?.(new CustomProgressEvent('blocks:get-many:providers:notify', cid));
113
+ await Promise.all(this.blockBrokers.map(async (broker) => broker.announce?.(cid, options)));
114
+ }
115
+ }));
116
+ }
117
+ /**
118
+ * Delete a block from the blockstore
119
+ */
120
+ async delete(cid, options = {}) {
121
+ options.onProgress?.(new CustomProgressEvent('blocks:delete:blockstore:delete', cid));
122
+ await this.child.delete(cid, options);
123
+ }
124
+ /**
125
+ * Delete multiple blocks from the blockstore
126
+ */
127
+ async *deleteMany(cids, options = {}) {
128
+ options.onProgress?.(new CustomProgressEvent('blocks:delete-many:blockstore:delete-many'));
129
+ yield* this.child.deleteMany((async function* () {
130
+ for await (const cid of cids) {
131
+ yield cid;
132
+ }
133
+ }()), options);
134
+ }
135
+ async has(cid, options = {}) {
136
+ return this.child.has(cid, options);
137
+ }
138
+ async *getAll(options = {}) {
139
+ options.onProgress?.(new CustomProgressEvent('blocks:get-all:blockstore:get-many'));
140
+ yield* this.child.getAll(options);
141
+ }
142
+ }
143
+ /**
144
+ * Race block providers cancelling any pending requests once the block has been
145
+ * found.
146
+ */
147
+ async function raceBlockRetrievers(cid, blockBrokers, hasher, options) {
148
+ const validateFn = getCidBlockVerifierFunction(cid, hasher);
149
+ const controller = new AbortController();
150
+ const signal = anySignal([controller.signal, options.signal]);
151
+ setMaxListeners(Infinity, controller.signal, signal);
152
+ const retrievers = [];
153
+ for (const broker of blockBrokers) {
154
+ if (isRetrievingBlockBroker(broker)) {
155
+ retrievers.push(broker);
156
+ }
157
+ }
158
+ if (retrievers.length === 0) {
159
+ throw new InvalidConfigurationError(`No block brokers capable of retrieving blocks are configured, the CID ${cid} cannot be fetched from the network`);
160
+ }
161
+ try {
162
+ return await Promise.any(retrievers
163
+ .map(async (retriever) => {
164
+ try {
165
+ let blocksWereValidated = false;
166
+ const block = await retriever.retrieve(cid, {
167
+ ...options,
168
+ signal,
169
+ validateFn: async (block) => {
170
+ await validateFn(block);
171
+ options.signal?.throwIfAborted();
172
+ blocksWereValidated = true;
173
+ }
174
+ });
175
+ if (!blocksWereValidated) {
176
+ // the blockBroker either did not throw an error when attempting to validate the block
177
+ // or did not call the validateFn at all. We should validate the block ourselves
178
+ await validateFn(block);
179
+ options.signal?.throwIfAborted();
180
+ }
181
+ return block;
182
+ }
183
+ catch (err) {
184
+ options.log.error('could not retrieve verified block for %c from %s - %e', cid, retriever.name, err);
185
+ throw err;
186
+ }
187
+ }));
188
+ }
189
+ catch (err) {
190
+ throw new LoadBlockFailedError(err.errors, `Failed to load block for ${cid}`);
191
+ }
192
+ finally {
193
+ // we have the block from the fastest block retriever, abort any still
194
+ // in-flight retrieve attempts
195
+ controller.abort();
196
+ signal.clear();
197
+ }
198
+ }
199
+ function isRetrievingBlockBroker(broker) {
200
+ return typeof broker.retrieve === 'function';
201
+ }
202
+ export const getCidBlockVerifierFunction = (cid, hasher) => {
203
+ if (hasher == null) {
204
+ throw new InvalidParametersError(`No hasher configured for multihash code 0x${cid.multihash.code.toString(16)}, please configure one. You can look up which hash this is at https://github.com/multiformats/multicodec/blob/master/table.csv`);
205
+ }
206
+ return async (block) => {
207
+ // verify block
208
+ let hash;
209
+ const res = hasher.digest(block, {
210
+ // support truncated hashes where they are truncated
211
+ truncate: cid.multihash.digest.byteLength
212
+ });
213
+ if (isPromise(res)) {
214
+ hash = await res;
215
+ }
216
+ else {
217
+ hash = res;
218
+ }
219
+ if (!uint8ArrayEquals(hash.digest, cid.multihash.digest)) {
220
+ // if a hash mismatch occurs for a TrustlessGatewayBlockBroker, we should try another gateway
221
+ throw new InvalidMultihashError('Hash of downloaded block did not match multihash from passed CID');
222
+ }
223
+ };
224
+ };
225
+ //# sourceMappingURL=storage.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"storage.js","sourceRoot":"","sources":["../../../src/utils/storage.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@helia/utils",
3
- "version": "2.3.5-7bf85e0c",
3
+ "version": "2.4.0-f058fba8",
4
4
  "description": "Shared code that implements the Helia API",
5
5
  "license": "Apache-2.0 OR MIT",
6
6
  "homepage": "https://github.com/ipfs/helia/tree/main/packages/utils#readme",
@@ -47,13 +47,12 @@
47
47
  "test:electron-main": "aegir test -t electron-main"
48
48
  },
49
49
  "dependencies": {
50
- "@helia/interface": "6.0.3-7bf85e0c",
50
+ "@helia/interface": "6.1.0-f058fba8",
51
51
  "@ipld/dag-cbor": "^9.2.5",
52
52
  "@ipld/dag-json": "^10.2.5",
53
53
  "@ipld/dag-pb": "^4.1.5",
54
54
  "@libp2p/interface": "^3.1.0",
55
55
  "@libp2p/keychain": "^6.0.5",
56
- "@libp2p/logger": "^6.0.5",
57
56
  "@libp2p/utils": "^7.0.5",
58
57
  "@multiformats/dns": "^1.0.9",
59
58
  "@multiformats/multiaddr": "^13.0.1",
@@ -78,6 +77,7 @@
78
77
  },
79
78
  "devDependencies": {
80
79
  "@libp2p/crypto": "^5.1.12",
80
+ "@libp2p/logger": "^6.0.5",
81
81
  "@libp2p/peer-id": "^6.0.3",
82
82
  "@types/sinon": "^21.0.0",
83
83
  "aegir": "^47.0.22",
@@ -27,12 +27,14 @@ export interface BlockstoreSessionEvents<Provider> {
27
27
  interface Request {
28
28
  promise: Promise<Uint8Array>
29
29
  observers: number
30
+ queryFilter: Filter
30
31
  }
31
32
 
32
33
  export abstract class AbstractSession<Provider, RetrieveBlockProgressEvents extends ProgressEvent> extends TypedEventEmitter<BlockstoreSessionEvents<Provider>> implements BlockBroker<RetrieveBlockProgressEvents> {
34
+ public abstract name: string
33
35
  private initialPeerSearchComplete?: Promise<void>
34
36
  private readonly requests: Map<string, Request>
35
- private readonly name: string
37
+ private readonly logName: string
36
38
  protected log: Logger
37
39
  protected logger: ComponentLogger
38
40
  private readonly minProviders: number
@@ -45,15 +47,15 @@ export abstract class AbstractSession<Provider, RetrieveBlockProgressEvents exte
45
47
  super()
46
48
 
47
49
  setMaxListeners(Infinity, this)
48
- this.name = init.name
50
+ this.logName = init.name
49
51
  this.logger = components.logger
50
- this.log = components.logger.forComponent(this.name)
52
+ this.log = components.logger.forComponent(this.logName)
51
53
  this.requests = new Map()
52
54
  this.minProviders = init.minProviders ?? DEFAULT_SESSION_MIN_PROVIDERS
53
55
  this.maxProviders = init.maxProviders ?? DEFAULT_SESSION_MAX_PROVIDERS
54
56
  this.providers = []
55
57
  this.evictionFilter = createScalableCuckooFilter(this.maxProviders)
56
- this.initialProviders = init.providers ?? []
58
+ this.initialProviders = [...(init.providers ?? [])]
57
59
  }
58
60
 
59
61
  async retrieve (cid: CID, options: BlockRetrievalOptions<RetrieveBlockProgressEvents> = {}): Promise<Uint8Array> {
@@ -70,41 +72,18 @@ export abstract class AbstractSession<Provider, RetrieveBlockProgressEvents exte
70
72
  const deferred: DeferredPromise<Uint8Array> = pDefer()
71
73
  const request = {
72
74
  promise: deferred.promise,
73
- observers: 1
75
+ observers: 1,
76
+ queryFilter: createScalableCuckooFilter(1024)
74
77
  }
75
78
  this.requests.set(cidStr, request)
76
79
 
77
- if (this.providers.length === 0) {
78
- let first = false
80
+ // if this is the first time this session has been used
81
+ let first = false
79
82
 
80
- if (this.initialPeerSearchComplete == null) {
81
- first = true
82
- this.log = this.logger.forComponent(`${this.name}:${cid}`)
83
- this.initialPeerSearchComplete = this.findProviders(cid, this.minProviders, options)
84
- }
85
-
86
- try {
87
- await raceSignal(this.initialPeerSearchComplete, options.signal)
88
-
89
- if (first) {
90
- this.log('found initial session peers for %c', cid)
91
- }
92
- } catch (err) {
93
- if (first) {
94
- this.log('failed to find initial session peers for %c - %e', cid, err)
95
- }
96
-
97
- this.requests.delete(cidStr)
98
-
99
- if (request.observers > 1) {
100
- // only need to reject request if another context is now also waiting
101
- // for the result - otherwise we can end up with an unhandled promise
102
- // rejection
103
- deferred.reject(err)
104
- }
105
-
106
- throw err
107
- }
83
+ if (this.initialPeerSearchComplete == null) {
84
+ first = true
85
+ this.log = this.logger.forComponent(`${this.logName}:${cid}`)
86
+ this.initialPeerSearchComplete = this.findProviders(cid, this.minProviders, options)
108
87
  }
109
88
 
110
89
  let foundBlock = false
@@ -166,6 +145,17 @@ export abstract class AbstractSession<Provider, RetrieveBlockProgressEvents exte
166
145
  })
167
146
 
168
147
  const peerAddedToSessionListener = (event: CustomEvent<Provider>): void => {
148
+ const filterKey = this.toFilterKey(event.detail)
149
+
150
+ if (request.queryFilter.has(filterKey)) {
151
+ return
152
+ }
153
+
154
+ request.queryFilter.add(filterKey)
155
+
156
+ // dispatch progress notification
157
+ this.emitFoundProviderProgressEvent(cid, event.detail, options)
158
+
169
159
  queue.add(async () => {
170
160
  return this.queryProvider(cid, event.detail, options)
171
161
  }, {
@@ -185,14 +175,50 @@ export abstract class AbstractSession<Provider, RetrieveBlockProgressEvents exte
185
175
  // add new session peers to query as they are discovered
186
176
  this.addEventListener('provider', peerAddedToSessionListener)
187
177
 
178
+ if (first) {
179
+ try {
180
+ await raceSignal(this.initialPeerSearchComplete, options.signal)
181
+
182
+ if (first) {
183
+ this.log('found initial session peers for %c', cid)
184
+ }
185
+ } catch (err) {
186
+ if (first) {
187
+ this.log('failed to find initial session peers for %c - %e', cid, err)
188
+ }
189
+
190
+ this.requests.delete(cidStr)
191
+
192
+ if (request.observers > 1) {
193
+ // only need to reject request if another context is now also waiting
194
+ // for the result - otherwise we can end up with an unhandled promise
195
+ // rejection
196
+ deferred.reject(err)
197
+ }
198
+
199
+ throw err
200
+ }
201
+ }
202
+
188
203
  // query each session peer directly
189
- Promise.all([...this.providers].map(async (provider) => {
190
- return queue.add(async () => {
191
- return this.queryProvider(cid, provider, options)
192
- }, {
193
- provider
194
- })
195
- }))
204
+ Promise.all(
205
+ [...this.providers]
206
+ .filter(provider => {
207
+ const filterKey = this.toFilterKey(provider)
208
+ const has = request.queryFilter.has(filterKey)
209
+
210
+ if (!has) {
211
+ request.queryFilter.add(this.toFilterKey(provider))
212
+ }
213
+
214
+ return !has
215
+ })
216
+ .map(async (provider) => {
217
+ return queue.add(async () => this.queryProvider(cid, provider, options), {
218
+ provider
219
+ })
220
+ })
221
+ )
196
222
  .catch(err => {
197
223
  if (options.signal?.aborted === true) {
198
224
  // skip logging error if signal was aborted because abort can happen
@@ -221,7 +247,7 @@ export abstract class AbstractSession<Provider, RetrieveBlockProgressEvents exte
221
247
  }
222
248
 
223
249
  evict (provider: Provider): void {
224
- this.evictionFilter.add(this.toEvictionKey(provider))
250
+ this.evictionFilter.add(this.toFilterKey(provider))
225
251
  const index = this.providers.findIndex(prov => this.equals(prov, provider))
226
252
 
227
253
  if (index === -1) {
@@ -232,7 +258,7 @@ export abstract class AbstractSession<Provider, RetrieveBlockProgressEvents exte
232
258
  }
233
259
 
234
260
  isEvicted (provider: Provider): boolean {
235
- return this.evictionFilter.has(this.toEvictionKey(provider))
261
+ return this.evictionFilter.has(this.toFilterKey(provider))
236
262
  }
237
263
 
238
264
  hasProvider (provider: Provider): boolean {
@@ -249,7 +275,22 @@ export abstract class AbstractSession<Provider, RetrieveBlockProgressEvents exte
249
275
  return false
250
276
  }
251
277
 
252
- private async findProviders (cid: CID, count: number, options: AbortOptions): Promise<void> {
278
+ async addPeer (peer: PeerId | Multiaddr | Multiaddr[], options?: AbortOptions): Promise<void> {
279
+ const provider = await this.convertToProvider(peer, 'manually-added', options)
280
+
281
+ if (provider == null || this.hasProvider(provider)) {
282
+ return
283
+ }
284
+
285
+ this.providers.push(provider)
286
+
287
+ // let the new peer join current queries
288
+ this.safeDispatchEvent('provider', {
289
+ detail: provider
290
+ })
291
+ }
292
+
293
+ private async findProviders (cid: CID, count: number, options: BlockRetrievalOptions<RetrieveBlockProgressEvents>): Promise<void> {
253
294
  const deferred: DeferredPromise<void> = pDefer()
254
295
  let found = 0
255
296
 
@@ -257,7 +298,7 @@ export abstract class AbstractSession<Provider, RetrieveBlockProgressEvents exte
257
298
  // found but continue util this.providers reaches this.maxProviders
258
299
  void Promise.resolve()
259
300
  .then(async () => {
260
- this.log('finding %d-%d new provider(s) for %c', count, this.maxProviders, cid)
301
+ this.log('finding %d-%d new provider(s) for %c - %d initial providers', count, this.maxProviders, cid, this.initialProviders.length)
261
302
 
262
303
  // process any specific providers for this session
263
304
  if (this.initialProviders.length > 0) {
@@ -268,7 +309,7 @@ export abstract class AbstractSession<Provider, RetrieveBlockProgressEvents exte
268
309
  break
269
310
  }
270
311
 
271
- const provider = await this.convertToProvider(prov, options)
312
+ const provider = await this.convertToProvider(prov, 'manual', options)
272
313
 
273
314
  if (options.signal?.aborted === true) {
274
315
  break
@@ -293,7 +334,7 @@ export abstract class AbstractSession<Provider, RetrieveBlockProgressEvents exte
293
334
  found++
294
335
 
295
336
  if (found === count) {
296
- this.log('session is ready')
337
+ this.log('session is ready with %d peer(s), only initial peers present', count)
297
338
  deferred.resolve()
298
339
  // continue finding peers until we reach this.maxProviders
299
340
  }
@@ -327,7 +368,7 @@ export abstract class AbstractSession<Provider, RetrieveBlockProgressEvents exte
327
368
  found++
328
369
 
329
370
  if (found === count) {
330
- this.log('session is ready')
371
+ this.log('session is ready with %d peer(s), new peers present', count)
331
372
  deferred.resolve()
332
373
  // continue finding peers until we reach this.maxProviders
333
374
  }
@@ -358,7 +399,7 @@ export abstract class AbstractSession<Provider, RetrieveBlockProgressEvents exte
358
399
  * into the format required or return `undefined` if the provider is not
359
400
  * compatible with this session implementation
360
401
  */
361
- abstract convertToProvider (provider: PeerId | Multiaddr | Multiaddr[], options?: AbortOptions): Promise<Provider | undefined>
402
+ abstract convertToProvider (provider: PeerId | Multiaddr | Multiaddr[], routing: string, options?: AbortOptions): Promise<Provider | undefined>
362
403
 
363
404
  /**
364
405
  * This method should search for new providers and yield them.
@@ -376,12 +417,17 @@ export abstract class AbstractSession<Provider, RetrieveBlockProgressEvents exte
376
417
 
377
418
  /**
378
419
  * Turn a provider into a concise Uint8Array representation for use in a Bloom
379
- * filter
420
+ * or Cuckoo filter
380
421
  */
381
- abstract toEvictionKey (provider: Provider): Uint8Array | string
422
+ abstract toFilterKey (provider: Provider): Uint8Array | string
382
423
 
383
424
  /**
384
425
  * Return `true` if we consider one provider to be the same as another
385
426
  */
386
427
  abstract equals (providerA: Provider, providerB: Provider): boolean
428
+
429
+ /**
430
+ * Invoke the progress handler with the session-specific found provider event
431
+ */
432
+ abstract emitFoundProviderProgressEvent (cid: CID, provider: Provider, options: BlockRetrievalOptions<RetrieveBlockProgressEvents>): void
387
433
  }
package/src/index.ts CHANGED
@@ -6,7 +6,6 @@
6
6
  */
7
7
 
8
8
  import { contentRoutingSymbol, peerRoutingSymbol, start, stop, TypedEventEmitter } from '@libp2p/interface'
9
- import { defaultLogger } from '@libp2p/logger'
10
9
  import { dns } from '@multiformats/dns'
11
10
  import drain from 'it-drain'
12
11
  import { CustomProgressEvent } from 'progress-events'
@@ -208,7 +207,7 @@ export class Helia<T extends Libp2p> implements HeliaInterface<T> {
208
207
  private readonly log: Logger
209
208
 
210
209
  constructor (init: Omit<HeliaInit, 'start' | 'libp2p'> & { libp2p: T }) {
211
- this.logger = init.logger ?? defaultLogger()
210
+ this.logger = init.logger ?? init.libp2p.logger
212
211
  this.log = this.logger.forComponent('helia')
213
212
  this.getHasher = getHasher(init.hashers, init.loadHasher)
214
213
  this.getCodec = getCodec(init.codecs, init.loadCodec)
@@ -259,16 +258,16 @@ export class Helia<T extends Libp2p> implements HeliaInterface<T> {
259
258
  providerLookupConcurrency: init.providerLookupConcurrency
260
259
  })
261
260
 
261
+ components.blockBrokers = init.blockBrokers.map((fn) => {
262
+ return fn(components)
263
+ })
264
+
262
265
  const networkedStorage = new NetworkedStorage(components, init)
263
266
  this.pins = new PinsImpl(init.datastore, networkedStorage, this.getCodec)
264
267
  this.blockstore = new BlockStorage(networkedStorage, this.pins, {
265
268
  holdGcLock: init.holdGcLock ?? true
266
269
  })
267
270
  this.datastore = init.datastore
268
-
269
- components.blockBrokers = init.blockBrokers.map((fn) => {
270
- return fn(components)
271
- })
272
271
  }
273
272
 
274
273
  async start (): Promise<void> {