From fd312032a4188ddfd658355933169dafc8406f87 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 25 Jan 2025 15:31:49 -0600 Subject: [PATCH] MultiRateLimiter: ensure the active limiter is used for ratelimit values --- src/utils/ratelimiter/MultiRateLimiter.test.ts | 2 ++ src/utils/ratelimiter/MultiRateLimiter.ts | 14 ++++++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/utils/ratelimiter/MultiRateLimiter.test.ts b/src/utils/ratelimiter/MultiRateLimiter.test.ts index 3cfa4696..9b1fd648 100644 --- a/src/utils/ratelimiter/MultiRateLimiter.test.ts +++ b/src/utils/ratelimiter/MultiRateLimiter.test.ts @@ -34,6 +34,8 @@ Deno.test('MultiRateLimiter', async (t) => { }); await t.step('throws when hit if second limit exceeded', () => { + assertEquals(limiter.client('test').limiter, limiter1); assertThrows(() => limiter.client('test').hit(), Error); + assertEquals(limiter.client('test').limiter, limiter2); }); }); diff --git a/src/utils/ratelimiter/MultiRateLimiter.ts b/src/utils/ratelimiter/MultiRateLimiter.ts index dc9b62a7..14b23142 100644 --- a/src/utils/ratelimiter/MultiRateLimiter.ts +++ b/src/utils/ratelimiter/MultiRateLimiter.ts @@ -3,7 +3,7 @@ import { RateLimiter, RateLimiterClient } from './types.ts'; export class MultiRateLimiter { constructor(private limiters: RateLimiter[]) {} - client(key: string): RateLimiterClient { + client(key: string): MultiRateLimiterClient { return new MultiRateLimiterClient(key, this.limiters); } } @@ -15,16 +15,22 @@ class MultiRateLimiterClient implements RateLimiterClient { } } + /** Returns the _active_ limiter, which is either the first exceeded or the first. */ + get limiter(): RateLimiter { + const exceeded = this.limiters.find((limiter) => limiter.client(this.key).remaining < 0); + return exceeded ?? this.limiters[0]; + } + get hits(): number { - return this.limiters[0].client(this.key).hits; + return this.limiter.client(this.key).hits; } get resetAt(): Date { - return this.limiters[0].client(this.key).resetAt; + return this.limiter.client(this.key).resetAt; } get remaining(): number { - return this.limiters[0].client(this.key).remaining; + return this.limiter.client(this.key).remaining; } hit(n?: number): void {