@helia/utils 0.1.0-9c8a2c0 → 0.1.0-9ea934e
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/abstract-session.d.ts +53 -0
- package/dist/src/abstract-session.d.ts.map +1 -0
- package/dist/src/abstract-session.js +205 -0
- package/dist/src/abstract-session.js.map +1 -0
- package/dist/src/bloom-filter.d.ts +33 -0
- package/dist/src/bloom-filter.d.ts.map +1 -0
- package/dist/src/bloom-filter.js +113 -0
- package/dist/src/bloom-filter.js.map +1 -0
- package/dist/src/index.d.ts +19 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +4 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/routing.d.ts +4 -1
- package/dist/src/routing.d.ts.map +1 -1
- package/dist/src/routing.js +47 -2
- package/dist/src/routing.js.map +1 -1
- package/dist/src/storage.d.ts +2 -2
- package/dist/src/storage.d.ts.map +1 -1
- package/dist/src/storage.js +12 -13
- package/dist/src/storage.js.map +1 -1
- package/dist/src/utils/networked-storage.d.ts +28 -23
- package/dist/src/utils/networked-storage.d.ts.map +1 -1
- package/dist/src/utils/networked-storage.js +180 -32
- package/dist/src/utils/networked-storage.js.map +1 -1
- package/package.json +9 -2
- package/src/abstract-session.ts +287 -0
- package/src/bloom-filter.ts +141 -0
- package/src/index.ts +23 -1
- package/src/routing.ts +55 -1
- package/src/storage.ts +13 -16
- package/src/utils/networked-storage.ts +214 -47
|
@@ -5,75 +5,47 @@ import filter from 'it-filter'
|
|
|
5
5
|
import forEach from 'it-foreach'
|
|
6
6
|
import { CustomProgressEvent, type ProgressOptions } from 'progress-events'
|
|
7
7
|
import { equals as uint8ArrayEquals } from 'uint8arrays/equals'
|
|
8
|
-
import type { BlockBroker, Blocks, Pair, DeleteManyBlocksProgressEvents, DeleteBlockProgressEvents, GetBlockProgressEvents, GetManyBlocksProgressEvents, PutManyBlocksProgressEvents, PutBlockProgressEvents, GetAllBlocksProgressEvents, GetOfflineOptions, BlockRetrievalOptions } from '@helia/interface/blocks'
|
|
8
|
+
import type { BlockBroker, Blocks, Pair, DeleteManyBlocksProgressEvents, DeleteBlockProgressEvents, GetBlockProgressEvents, GetManyBlocksProgressEvents, PutManyBlocksProgressEvents, PutBlockProgressEvents, GetAllBlocksProgressEvents, GetOfflineOptions, BlockRetrievalOptions, CreateSessionOptions, SessionBlockstore } from '@helia/interface/blocks'
|
|
9
9
|
import type { AbortOptions, ComponentLogger, Logger, LoggerOptions, Startable } from '@libp2p/interface'
|
|
10
10
|
import type { Blockstore } from 'interface-blockstore'
|
|
11
11
|
import type { AwaitIterable } from 'interface-store'
|
|
12
12
|
import type { CID } from 'multiformats/cid'
|
|
13
13
|
import type { MultihashHasher } from 'multiformats/hashes/interface'
|
|
14
14
|
|
|
15
|
-
export interface NetworkedStorageInit {
|
|
16
|
-
root?: CID
|
|
17
|
-
}
|
|
18
|
-
|
|
19
15
|
export interface GetOptions extends AbortOptions {
|
|
20
16
|
progress?(evt: Event): void
|
|
21
17
|
}
|
|
22
18
|
|
|
23
|
-
export interface
|
|
19
|
+
export interface StorageComponents {
|
|
24
20
|
blockstore: Blockstore
|
|
25
21
|
logger: ComponentLogger
|
|
26
22
|
blockBrokers: BlockBroker[]
|
|
27
23
|
hashers: Record<number, MultihashHasher>
|
|
28
24
|
}
|
|
29
25
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
private readonly hashers: Record<number, MultihashHasher>
|
|
37
|
-
private started: boolean
|
|
38
|
-
private readonly log: Logger
|
|
39
|
-
private readonly logger: ComponentLogger
|
|
40
|
-
private readonly components: NetworkedStorageComponents
|
|
26
|
+
class Storage implements Blockstore {
|
|
27
|
+
protected readonly child: Blockstore
|
|
28
|
+
protected readonly hashers: Record<number, MultihashHasher>
|
|
29
|
+
protected log: Logger
|
|
30
|
+
protected readonly logger: ComponentLogger
|
|
31
|
+
protected readonly components: StorageComponents
|
|
41
32
|
|
|
42
33
|
/**
|
|
43
34
|
* Create a new BlockStorage
|
|
44
35
|
*/
|
|
45
|
-
constructor (components:
|
|
46
|
-
this.log = components.logger.forComponent(
|
|
36
|
+
constructor (components: StorageComponents) {
|
|
37
|
+
this.log = components.logger.forComponent('helia:networked-storage')
|
|
47
38
|
this.logger = components.logger
|
|
48
39
|
this.components = components
|
|
49
40
|
this.child = new IdentityBlockstore(components.blockstore)
|
|
50
41
|
this.hashers = components.hashers ?? {}
|
|
51
|
-
this.started = false
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
isStarted (): boolean {
|
|
55
|
-
return this.started
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
async start (): Promise<void> {
|
|
59
|
-
await start(this.child, ...this.components.blockBrokers)
|
|
60
|
-
this.started = true
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
async stop (): Promise<void> {
|
|
64
|
-
await stop(this.child, ...this.components.blockBrokers)
|
|
65
|
-
this.started = false
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
unwrap (): Blockstore {
|
|
69
|
-
return this.child
|
|
70
42
|
}
|
|
71
43
|
|
|
72
44
|
/**
|
|
73
45
|
* Put a block to the underlying datastore
|
|
74
46
|
*/
|
|
75
47
|
async put (cid: CID, block: Uint8Array, options: AbortOptions & ProgressOptions<PutBlockProgressEvents> = {}): Promise<CID> {
|
|
76
|
-
if (await this.child.has(cid)) {
|
|
48
|
+
if (await this.child.has(cid, options)) {
|
|
77
49
|
options.onProgress?.(new CustomProgressEvent<CID>('blocks:put:duplicate', cid))
|
|
78
50
|
return cid
|
|
79
51
|
}
|
|
@@ -94,7 +66,7 @@ export class NetworkedStorage implements Blocks, Startable {
|
|
|
94
66
|
*/
|
|
95
67
|
async * putMany (blocks: AwaitIterable<{ cid: CID, block: Uint8Array }>, options: AbortOptions & ProgressOptions<PutManyBlocksProgressEvents> = {}): AsyncIterable<CID> {
|
|
96
68
|
const missingBlocks = filter(blocks, async ({ cid }): Promise<boolean> => {
|
|
97
|
-
const has = await this.child.has(cid)
|
|
69
|
+
const has = await this.child.has(cid, options)
|
|
98
70
|
|
|
99
71
|
if (has) {
|
|
100
72
|
options.onProgress?.(new CustomProgressEvent<CID>('blocks:put-many:duplicate', cid))
|
|
@@ -118,7 +90,7 @@ export class NetworkedStorage implements Blocks, Startable {
|
|
|
118
90
|
* Get a block by cid
|
|
119
91
|
*/
|
|
120
92
|
async get (cid: CID, options: GetOfflineOptions & AbortOptions & ProgressOptions<GetBlockProgressEvents> = {}): Promise<Uint8Array> {
|
|
121
|
-
if (options.offline !== true && !(await this.child.has(cid))) {
|
|
93
|
+
if (options.offline !== true && !(await this.child.has(cid, options))) {
|
|
122
94
|
// we do not have the block locally, get it from a block provider
|
|
123
95
|
options.onProgress?.(new CustomProgressEvent<CID>('blocks:get:providers:get', cid))
|
|
124
96
|
const block = await raceBlockRetrievers(cid, this.components.blockBrokers, this.hashers[cid.multihash.code], {
|
|
@@ -149,7 +121,7 @@ export class NetworkedStorage implements Blocks, Startable {
|
|
|
149
121
|
options.onProgress?.(new CustomProgressEvent('blocks:get-many:blockstore:get-many'))
|
|
150
122
|
|
|
151
123
|
yield * this.child.getMany(forEach(cids, async (cid): Promise<void> => {
|
|
152
|
-
if (options.offline !== true && !(await this.child.has(cid))) {
|
|
124
|
+
if (options.offline !== true && !(await this.child.has(cid, options))) {
|
|
153
125
|
// we do not have the block locally, get it from a block provider
|
|
154
126
|
options.onProgress?.(new CustomProgressEvent<CID>('blocks:get-many:providers:get', cid))
|
|
155
127
|
const block = await raceBlockRetrievers(cid, this.components.blockBrokers, this.hashers[cid.multihash.code], {
|
|
@@ -197,17 +169,54 @@ export class NetworkedStorage implements Blocks, Startable {
|
|
|
197
169
|
options.onProgress?.(new CustomProgressEvent('blocks:get-all:blockstore:get-many'))
|
|
198
170
|
yield * this.child.getAll(options)
|
|
199
171
|
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export type NetworkedStorageComponents = StorageComponents
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Networked storage wraps a regular blockstore - when getting blocks if the
|
|
178
|
+
* blocks are not present, the configured BlockBrokers will be used to fetch them.
|
|
179
|
+
*/
|
|
180
|
+
export class NetworkedStorage extends Storage implements Blocks, Startable {
|
|
181
|
+
private started: boolean
|
|
200
182
|
|
|
201
|
-
|
|
202
|
-
|
|
183
|
+
/**
|
|
184
|
+
* Create a new BlockStorage
|
|
185
|
+
*/
|
|
186
|
+
constructor (components: NetworkedStorageComponents) {
|
|
187
|
+
super(components)
|
|
188
|
+
|
|
189
|
+
this.started = false
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
isStarted (): boolean {
|
|
193
|
+
return this.started
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
async start (): Promise<void> {
|
|
197
|
+
await start(this.child, ...this.components.blockBrokers)
|
|
198
|
+
this.started = true
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async stop (): Promise<void> {
|
|
202
|
+
await stop(this.child, ...this.components.blockBrokers)
|
|
203
|
+
this.started = false
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
unwrap (): Blockstore {
|
|
207
|
+
return this.child
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
createSession (root: CID, options?: CreateSessionOptions): SessionBlockstore {
|
|
211
|
+
const blockBrokers = this.components.blockBrokers.map(broker => {
|
|
203
212
|
if (broker.createSession == null) {
|
|
204
213
|
return broker
|
|
205
214
|
}
|
|
206
215
|
|
|
207
|
-
return broker.createSession(
|
|
208
|
-
})
|
|
216
|
+
return broker.createSession(options)
|
|
217
|
+
})
|
|
209
218
|
|
|
210
|
-
return new
|
|
219
|
+
return new SessionStorage({
|
|
211
220
|
blockstore: this.child,
|
|
212
221
|
blockBrokers,
|
|
213
222
|
hashers: this.hashers,
|
|
@@ -218,9 +227,167 @@ export class NetworkedStorage implements Blocks, Startable {
|
|
|
218
227
|
}
|
|
219
228
|
}
|
|
220
229
|
|
|
230
|
+
interface SessionStorageInit {
|
|
231
|
+
root: CID
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Storage subclass that can cancel any ongoing operation at any point.
|
|
236
|
+
*/
|
|
237
|
+
class SessionStorage extends Storage implements SessionBlockstore {
|
|
238
|
+
private readonly closeController: AbortController
|
|
239
|
+
|
|
240
|
+
constructor (components: StorageComponents, init: SessionStorageInit) {
|
|
241
|
+
super(components)
|
|
242
|
+
|
|
243
|
+
// because brokers are allowed to continue searching for providers after the
|
|
244
|
+
// session has been created, we need a way to tell them that the user has
|
|
245
|
+
// finished using the session any in-flight requests should be cancelled
|
|
246
|
+
this.closeController = new AbortController()
|
|
247
|
+
setMaxListeners(Infinity, this.closeController.signal)
|
|
248
|
+
|
|
249
|
+
this.log = components.logger.forComponent(`helia:session-storage${init.root}`)
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
close (): void {
|
|
253
|
+
this.closeController.abort()
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Put a block to the underlying datastore
|
|
258
|
+
*/
|
|
259
|
+
async put (cid: CID, block: Uint8Array, options: AbortOptions & ProgressOptions<PutBlockProgressEvents> = {}): Promise<CID> {
|
|
260
|
+
const signal = anySignal([this.closeController.signal, options.signal])
|
|
261
|
+
setMaxListeners(Infinity, signal)
|
|
262
|
+
|
|
263
|
+
try {
|
|
264
|
+
return await super.put(cid, block, {
|
|
265
|
+
...options,
|
|
266
|
+
signal
|
|
267
|
+
})
|
|
268
|
+
} finally {
|
|
269
|
+
signal.clear()
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/**
|
|
274
|
+
* Put a multiple blocks to the underlying datastore
|
|
275
|
+
*/
|
|
276
|
+
async * putMany (blocks: AwaitIterable<{ cid: CID, block: Uint8Array }>, options: AbortOptions & ProgressOptions<PutManyBlocksProgressEvents> = {}): AsyncIterable<CID> {
|
|
277
|
+
const signal = anySignal([this.closeController.signal, options.signal])
|
|
278
|
+
setMaxListeners(Infinity, signal)
|
|
279
|
+
|
|
280
|
+
try {
|
|
281
|
+
yield * super.putMany(blocks, {
|
|
282
|
+
...options,
|
|
283
|
+
signal
|
|
284
|
+
})
|
|
285
|
+
} finally {
|
|
286
|
+
signal.clear()
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Get a block by cid
|
|
292
|
+
*/
|
|
293
|
+
async get (cid: CID, options: GetOfflineOptions & AbortOptions & ProgressOptions<GetBlockProgressEvents> = {}): Promise<Uint8Array> {
|
|
294
|
+
const signal = anySignal([this.closeController.signal, options.signal])
|
|
295
|
+
setMaxListeners(Infinity, signal)
|
|
296
|
+
|
|
297
|
+
try {
|
|
298
|
+
return await super.get(cid, {
|
|
299
|
+
...options,
|
|
300
|
+
signal
|
|
301
|
+
})
|
|
302
|
+
} finally {
|
|
303
|
+
signal.clear()
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
/**
|
|
308
|
+
* Get multiple blocks back from an (async) iterable of cids
|
|
309
|
+
*/
|
|
310
|
+
async * getMany (cids: AwaitIterable<CID>, options: GetOfflineOptions & AbortOptions & ProgressOptions<GetManyBlocksProgressEvents> = {}): AsyncIterable<Pair> {
|
|
311
|
+
const signal = anySignal([this.closeController.signal, options.signal])
|
|
312
|
+
setMaxListeners(Infinity, signal)
|
|
313
|
+
|
|
314
|
+
try {
|
|
315
|
+
yield * super.getMany(cids, {
|
|
316
|
+
...options,
|
|
317
|
+
signal
|
|
318
|
+
})
|
|
319
|
+
} finally {
|
|
320
|
+
signal.clear()
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Delete a block from the blockstore
|
|
326
|
+
*/
|
|
327
|
+
async delete (cid: CID, options: AbortOptions & ProgressOptions<DeleteBlockProgressEvents> = {}): Promise<void> {
|
|
328
|
+
const signal = anySignal([this.closeController.signal, options.signal])
|
|
329
|
+
setMaxListeners(Infinity, signal)
|
|
330
|
+
|
|
331
|
+
try {
|
|
332
|
+
await super.delete(cid, {
|
|
333
|
+
...options,
|
|
334
|
+
signal
|
|
335
|
+
})
|
|
336
|
+
} finally {
|
|
337
|
+
signal.clear()
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Delete multiple blocks from the blockstore
|
|
343
|
+
*/
|
|
344
|
+
async * deleteMany (cids: AwaitIterable<CID>, options: AbortOptions & ProgressOptions<DeleteManyBlocksProgressEvents> = {}): AsyncIterable<CID> {
|
|
345
|
+
const signal = anySignal([this.closeController.signal, options.signal])
|
|
346
|
+
setMaxListeners(Infinity, signal)
|
|
347
|
+
|
|
348
|
+
try {
|
|
349
|
+
yield * super.deleteMany(cids, {
|
|
350
|
+
...options,
|
|
351
|
+
signal
|
|
352
|
+
})
|
|
353
|
+
} finally {
|
|
354
|
+
signal.clear()
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
async has (cid: CID, options: AbortOptions = {}): Promise<boolean> {
|
|
359
|
+
const signal = anySignal([this.closeController.signal, options.signal])
|
|
360
|
+
setMaxListeners(Infinity, signal)
|
|
361
|
+
|
|
362
|
+
try {
|
|
363
|
+
return await super.has(cid, {
|
|
364
|
+
...options,
|
|
365
|
+
signal
|
|
366
|
+
})
|
|
367
|
+
} finally {
|
|
368
|
+
signal.clear()
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
async * getAll (options: AbortOptions & ProgressOptions<GetAllBlocksProgressEvents> = {}): AwaitIterable<Pair> {
|
|
373
|
+
const signal = anySignal([this.closeController.signal, options.signal])
|
|
374
|
+
setMaxListeners(Infinity, signal)
|
|
375
|
+
|
|
376
|
+
try {
|
|
377
|
+
yield * super.getAll({
|
|
378
|
+
...options,
|
|
379
|
+
signal
|
|
380
|
+
})
|
|
381
|
+
} finally {
|
|
382
|
+
signal.clear()
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
|
|
221
387
|
function isRetrievingBlockBroker (broker: BlockBroker): broker is Required<Pick<BlockBroker, 'retrieve'>> {
|
|
222
388
|
return typeof broker.retrieve === 'function'
|
|
223
389
|
}
|
|
390
|
+
|
|
224
391
|
export const getCidBlockVerifierFunction = (cid: CID, hasher: MultihashHasher): Required<BlockRetrievalOptions>['validateFn'] => {
|
|
225
392
|
if (hasher == null) {
|
|
226
393
|
throw new CodeError(`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`, 'ERR_UNKNOWN_HASH_ALG')
|