From 4fd6e43bca77813e46155225fd2a75643a65dc65 Mon Sep 17 00:00:00 2001 From: q13x <84165981+WorldEditAxe@users.noreply.github.com> Date: Thu, 15 Jun 2023 17:49:27 +0000 Subject: [PATCH] begin addition of a simple ratelimit --- src/proxy/skins/SimpleRatelimit.ts | 65 ++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 src/proxy/skins/SimpleRatelimit.ts diff --git a/src/proxy/skins/SimpleRatelimit.ts b/src/proxy/skins/SimpleRatelimit.ts new file mode 100644 index 0000000..f7fe279 --- /dev/null +++ b/src/proxy/skins/SimpleRatelimit.ts @@ -0,0 +1,65 @@ +export default class SimpleRatelimit { + readonly requestCount: number + readonly resetInterval: number + private entries: Map + + constructor(requestCount: number, resetInterval: number) { + this.requestCount = requestCount + this.resetInterval = resetInterval + this.entries = new Map() + } + + public get(key: T): Ratelimit { + return this.entries.get(key) ?? { + remainingRequests: this.requestCount, + resetTime: new Date(0) + } + } + + public consume(key: T, count?: number): Ratelimit | never { + if (this.entries.has(key)) { + const ratelimit = this.entries.get(key) + if (ratelimit.remainingRequests - (count ?? 1) < 0) { + if (this.requestCount - (count ?? 1) < 0) { + throw new RatelimitExceededError(`Consume request count is higher than default available request count!`) + } else { + throw new RatelimitExceededError(`Ratelimit exceeded, try again in ${ratelimit.resetTime.getDate() - Date.now()} ms!`) + } + } + ratelimit.remainingRequests -= count ?? 1 + return ratelimit + } else { + if (this.requestCount - (count ?? 1) < 0) { + throw new RatelimitExceededError(`Consume request count is higher than default available request count!`) + } + const ratelimit: Ratelimit = { + remainingRequests: this.requestCount - (count ?? 1), + resetTime: new Date(Date.now() + this.resetInterval), + timer: null + } + this.entries.set(key, ratelimit) + ratelimit.timer = this._onAdd(ratelimit) + return ratelimit + } + } + + private _onAdd(ratelimit: Ratelimit): NodeJS.Timer { + return setInterval(() => { + // TODO: work on + }, this.resetInterval) + } +} + +export type Ratelimit = { + remainingRequests: number, + resetTime: Date, + timer?: NodeJS.Timer +} + +export class RatelimitExceededError extends Error { + constructor(message: { toString: () => string }) { + super(message.toString()) + this.name = "RatelimitExceededError" + Object.setPrototypeOf(this, RatelimitExceededError.prototype) + } +} \ No newline at end of file