2021-11-23 00:03:59 +03:00
|
|
|
import { Deque } from '@mtcute/core'
|
|
|
|
|
|
|
|
export class RpsMeter {
|
|
|
|
_hits: Deque<bigint>
|
|
|
|
time: bigint
|
|
|
|
|
|
|
|
constructor(readonly size = 500, time = 5000) {
|
2023-06-05 03:30:48 +03:00
|
|
|
if (typeof process === 'undefined' || !process.hrtime.bigint) { throw new Error('RPS meter is not supported on this platform') }
|
2021-11-23 00:03:59 +03:00
|
|
|
|
|
|
|
this._hits = new Deque<bigint>(size)
|
2022-06-30 16:32:56 +03:00
|
|
|
this.time = BigInt(time) * BigInt(1e6)
|
2021-11-23 00:03:59 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
hit(): void {
|
|
|
|
this._hits.pushBack(process.hrtime.bigint())
|
|
|
|
}
|
|
|
|
|
|
|
|
getRps(): number {
|
|
|
|
// calculate average load based on last `size` hits in the last `time` ms
|
|
|
|
if (!this._hits.length) return 0 // no hits at all
|
|
|
|
|
|
|
|
const now = process.hrtime.bigint()
|
|
|
|
const window = now - this.time
|
|
|
|
// find the first hit within the last `time` ms
|
|
|
|
const iter = this._hits.iter()
|
|
|
|
let first = iter.next()
|
|
|
|
let idx = 0
|
2023-06-05 03:30:48 +03:00
|
|
|
|
2021-11-23 00:03:59 +03:00
|
|
|
while (!first.done && first.value < window) {
|
|
|
|
first = iter.next()
|
|
|
|
idx += 1
|
|
|
|
}
|
|
|
|
if (!first.value) return 0 // no recent hits
|
|
|
|
|
|
|
|
// number of hits within the window
|
|
|
|
const hits = this._hits.length - idx
|
|
|
|
|
|
|
|
// average load per second
|
2022-06-30 16:32:56 +03:00
|
|
|
return (hits * 1e9) / Number(now - first.value)
|
2021-11-23 00:03:59 +03:00
|
|
|
}
|
|
|
|
}
|