UNPKG

ipfs-bitswap

Version:

JavaScript implementation of the Bitswap data exchange protocol used by IPFS

91 lines (72 loc) 2.75 kB
import { EventEmitter } from 'events' import { CustomProgressEvent, type ProgressOptions } from 'progress-events' import { toString as uint8ArrayToString } from 'uint8arrays/to-string' import * as CONSTANTS from './constants.js' import { logger } from './utils/index.js' import type { BitswapWantBlockProgressEvents } from './index.js' import type { AbortOptions, PeerId } from '@libp2p/interface' import type { Logger } from '@libp2p/logger' import type { CID } from 'multiformats/cid' const unwantEvent = (cid: CID): string => `unwant:${uint8ArrayToString(cid.multihash.bytes, 'base64')}` const blockEvent = (cid: CID): string => `block:${uint8ArrayToString(cid.multihash.bytes, 'base64')}` export class Notifications extends EventEmitter { private readonly _log: Logger /** * Internal module used to track events about incoming blocks, * wants and unwants. */ constructor (peerId: PeerId) { super() this.setMaxListeners(CONSTANTS.maxListeners) this._log = logger(peerId, 'notif') } /** * Signal the system that we received `block`. */ hasBlock (cid: CID, block: Uint8Array): void { const event = blockEvent(cid) this._log(event) this.emit(event, block) } /** * Signal the system that we are waiting to receive the * block associated with the given `cid`. * Returns a Promise that resolves to the block when it is received, * or undefined when the block is unwanted. */ async wantBlock (cid: CID, options: AbortOptions & ProgressOptions<BitswapWantBlockProgressEvents> = {}): Promise<Uint8Array> { if (cid == null) { throw new Error('Not a valid cid') } const blockEvt = blockEvent(cid) const unwantEvt = unwantEvent(cid) this._log(`wantBlock:${cid}`) return new Promise((resolve, reject) => { const onUnwant = (): void => { this.removeListener(blockEvt, onBlock) options.onProgress?.(new CustomProgressEvent<CID>('bitswap:want-block:unwant', cid)) reject(new Error(`Block for ${cid} unwanted`)) } const onBlock = (data: Uint8Array): void => { this.removeListener(unwantEvt, onUnwant) options.onProgress?.(new CustomProgressEvent<CID>('bitswap:want-block:block', cid)) resolve(data) } this.once(unwantEvt, onUnwant) this.once(blockEvt, onBlock) options.signal?.addEventListener('abort', () => { this.removeListener(blockEvt, onBlock) this.removeListener(unwantEvt, onUnwant) reject(new Error(`Want for ${cid} aborted`)) }) }) } /** * Signal that the block is not wanted anymore */ unwantBlock (cid: CID): void { const event = unwantEvent(cid) this._log(event) this.emit(event) } }