ipfs-bitswap
Version:
JavaScript implementation of the Bitswap data exchange protocol used by IPFS
117 lines (95 loc) • 3.06 kB
text/typescript
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)
}
}
}