require('bare-process/global') const EventEmitter = require('bare-events') const { assertNonEmpty } = require('../../_shared/lib/errors.js') const PROTOCOL = 'sla-budget/v1' class HyperP2PSlaBudget extends EventEmitter { constructor (opts = {}) { super() this._services = new Map() this._stats = { allocated: 0, consumed: 0, rejected: 0 } } allocate (service, tokens) { assertNonEmpty(service, 'service') const amount = Number(tokens) if (!Number.isFinite(amount) || amount < 0) { throw new Error('tokens must be a non-negative number') } const cur = this._services.get(service) || { remaining: 0, total: 0 } cur.remaining += amount cur.total += amount this._services.set(service, cur) this._stats.allocated++ this.emit('allocate', { service, tokens: amount, remaining: cur.remaining }) return cur.remaining } consume (service, n = 1) { assertNonEmpty(service, 'service') const amount = Number(n) if (!Number.isFinite(amount) || amount < 0) { throw new Error('n must be a non-negative number') } const cur = this._services.get(service) if (!cur || cur.remaining < amount) { this._stats.rejected++ this.emit('reject', { service, requested: amount, remaining: cur ? cur.remaining : 0 }) return false } cur.remaining -= amount this._stats.consumed++ this.emit('consume', { service, n: amount, remaining: cur.remaining }) return true } remaining (service) { assertNonEmpty(service, 'service') const cur = this._services.get(service) return cur ? cur.remaining : 0 } services () { return [...this._services.keys()].sort() } snapshot (service) { const cur = this._services.get(service) if (!cur) return null return { service, remaining: cur.remaining, total: cur.total, used: cur.total - cur.remaining } } reset (service) { if (service) { this._services.delete(service) return true } this._services.clear() return true } getStats () { return { ...this._stats, services: this._services.size, protocol: PROTOCOL } } async ready () { return this } async close () { this._services.clear() this.emit('closed') } } module.exports = { HyperP2PSlaBudget, PROTOCOL }