32 lines
839 B
TypeScript
32 lines
839 B
TypeScript
// A sliding-window count per key, for the doors a stranger can knock on.
|
|
|
|
export class RateLimit {
|
|
private hits = new Map<string, number[]>();
|
|
|
|
constructor(
|
|
private limit: number,
|
|
private windowMs: number
|
|
) {}
|
|
|
|
/** True if the key may act now; the act is recorded when it is allowed. */
|
|
allow(key: string, now = Date.now()): boolean {
|
|
const since = now - this.windowMs;
|
|
const recent = (this.hits.get(key) ?? []).filter((t) => t > since);
|
|
if (recent.length >= this.limit) {
|
|
this.hits.set(key, recent);
|
|
return false;
|
|
}
|
|
recent.push(now);
|
|
this.hits.set(key, recent);
|
|
if (this.hits.size > 10000) this.prune(now);
|
|
return true;
|
|
}
|
|
|
|
prune(now = Date.now()): void {
|
|
const since = now - this.windowMs;
|
|
for (const [key, times] of this.hits) {
|
|
if (!times.some((t) => t > since)) this.hits.delete(key);
|
|
}
|
|
}
|
|
}
|