Files
modules/measurement-rate-control/hyper-p2p-sla-budget/index.js
T
2026-05-20 22:56:32 -04:00

89 lines
2.3 KiB
JavaScript

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 }