mirror of
https://github.com/Cameri/nostream.git
synced 2025-04-05 02:18:03 +02:00
feat: add sliding window rate limiter
This commit is contained in:
parent
6235e1aeed
commit
42083a2f98
src
8
src/@types/utils.ts
Normal file
8
src/@types/utils.ts
Normal file
@ -0,0 +1,8 @@
|
||||
export interface IRateLimiterOptions {
|
||||
period: number;
|
||||
rate: number;
|
||||
}
|
||||
|
||||
export interface IRateLimiter {
|
||||
hit(key: string, step: number, options: IRateLimiterOptions): Promise<boolean>
|
||||
}
|
35
src/utils/sliding-window-rate-limiter.ts
Normal file
35
src/utils/sliding-window-rate-limiter.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { IRateLimiter, IRateLimiterOptions } from '../@types/utils'
|
||||
import { createLogger } from '../factories/logger-factory'
|
||||
import { ICacheAdapter } from '../@types/adapters'
|
||||
|
||||
const debug = createLogger('sliding-window-rate-limiter')
|
||||
|
||||
export class SlidingWindowRateLimiter implements IRateLimiter {
|
||||
public constructor(
|
||||
private readonly cache: ICacheAdapter,
|
||||
) {}
|
||||
|
||||
public async hit(
|
||||
key: string,
|
||||
step: number,
|
||||
options: IRateLimiterOptions,
|
||||
): Promise<boolean> {
|
||||
const timestamp = Date.now()
|
||||
const { period } = options
|
||||
|
||||
debug('add %d hits on %s bucket', step, key)
|
||||
|
||||
const [,, entries] = await Promise.all([
|
||||
this.cache.removeRangeByScoreFromSortedSet(key, 0, timestamp - period),
|
||||
this.cache.addToSortedSet(key, { [`${timestamp}:${step}`]: timestamp.toString() }),
|
||||
this.cache.getRangeFromSortedSet(key, 0, -1),
|
||||
this.cache.setKeyExpiry(key, period),
|
||||
])
|
||||
|
||||
const hits = entries.reduce((acc, timestampAndStep) => acc + Number(timestampAndStep.split(':')[1]), 0)
|
||||
|
||||
debug('hit count on %s bucket: %d', key, hits)
|
||||
|
||||
return hits > options.rate
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user