UNPKG

ipfs-bitswap

Version:

JavaScript implementation of the Bitswap data exchange protocol used by IPFS

117 lines (95 loc) 3.06 kB
import { EventEmitter } from 'events' import { trackedMap } from '@libp2p/utils/tracked-map' import { Stat } from './stat.js' import type { Libp2p, PeerId } from '@libp2p/interface' import type { IMovingAverage } from '@vascosantos/moving-average' export interface StatsOptions { enabled?: boolean computeThrottleTimeout?: number computeThrottleMaxQueueSize?: number movingAverageIntervals?: number[] } const defaultOptions: Required<StatsOptions> = { enabled: false, computeThrottleTimeout: 1000, computeThrottleMaxQueueSize: 1000, movingAverageIntervals: [ 60 * 1000, // 1 minute 5 * 60 * 1000, // 5 minutes 15 * 60 * 1000 // 15 minutes ] } export class Stats extends EventEmitter { private readonly _initialCounters: string[] private readonly _options: Required<StatsOptions> private _enabled: boolean private readonly _global: Stat private readonly _peers: Map<string, Stat> constructor (libp2p: Libp2p, initialCounters: string[] = [], _options: StatsOptions = defaultOptions) { super() const options = Object.assign({}, defaultOptions, _options) if (typeof options.computeThrottleTimeout !== 'number') { throw new Error('need computeThrottleTimeout') } if (typeof options.computeThrottleMaxQueueSize !== 'number') { throw new Error('need computeThrottleMaxQueueSize') } this._initialCounters = initialCounters this._options = options this._enabled = this._options.enabled this._global = new Stat(initialCounters, options) this._global.on('update', (stats) => this.emit('update', stats)) this._peers = trackedMap({ name: 'ipfs_bitswap_stats_peers', metrics: libp2p.metrics }) } enable (): void { this._enabled = true this._options.enabled = true this._global.enable() } disable (): void { this._enabled = false this._options.enabled = false this._global.disable() } stop (): void { this._enabled = false this._global.stop() for (const peerStat of this._peers) { peerStat[1].stop() } } get snapshot (): Record<string, bigint> { return this._global.snapshot } get movingAverages (): Record<string, Record<number, IMovingAverage>> { return this._global.movingAverages } forPeer (peerId: PeerId | string): Stat | undefined { const peerIdStr = peerId.toString() return this._peers.get(peerIdStr) } push (peer: string | undefined, counter: string, inc: number): void { if (this._enabled) { this._global.push(counter, inc) if (peer != null) { let peerStats = this._peers.get(peer) if (peerStats == null) { peerStats = new Stat(this._initialCounters, this._options) this._peers.set(peer, peerStats) } peerStats.push(counter, inc) } } } disconnected (peer: PeerId): void { const peerId = peer.toString() const peerStats = this._peers.get(peerId) if (peerStats != null) { peerStats.stop() this._peers.delete(peerId) } } }