From b3948d5fd13e662841211e3c8380877d7e075c6a Mon Sep 17 00:00:00 2001 From: Piyush Chhabra Date: Sun, 11 Aug 2024 21:22:09 +0530 Subject: [PATCH 1/6] ADD: rate limiter draft --- lib/limiter/RateLimiter.ts | 31 +++++++ lib/limiter/decorator.ts | 27 ++++++ lib/limiter/drivers/index.ts | 2 + lib/limiter/drivers/memory.ts | 75 +++++++++++++++ lib/limiter/drivers/redis.ts | 93 +++++++++++++++++++ lib/limiter/explorer.ts | 75 +++++++++++++++ lib/limiter/index.ts | 6 ++ lib/limiter/interfaces/LimiterDriver.ts | 9 ++ lib/limiter/strategies/BaseStrategy.ts | 37 ++++++++ .../strategies/SlidingWindowCounter.ts | 35 +++++++ lib/limiter/strategies/TokenBucket.ts | 43 +++++++++ lib/limiter/strategies/WindowCounter.ts | 43 +++++++++ lib/limiter/strategies/index.ts | 4 + 13 files changed, 480 insertions(+) create mode 100644 lib/limiter/RateLimiter.ts create mode 100644 lib/limiter/decorator.ts create mode 100644 lib/limiter/drivers/index.ts create mode 100644 lib/limiter/drivers/memory.ts create mode 100644 lib/limiter/drivers/redis.ts create mode 100644 lib/limiter/explorer.ts create mode 100644 lib/limiter/index.ts create mode 100644 lib/limiter/interfaces/LimiterDriver.ts create mode 100644 lib/limiter/strategies/BaseStrategy.ts create mode 100644 lib/limiter/strategies/SlidingWindowCounter.ts create mode 100644 lib/limiter/strategies/TokenBucket.ts create mode 100644 lib/limiter/strategies/WindowCounter.ts create mode 100644 lib/limiter/strategies/index.ts diff --git a/lib/limiter/RateLimiter.ts b/lib/limiter/RateLimiter.ts new file mode 100644 index 0000000..88feb1c --- /dev/null +++ b/lib/limiter/RateLimiter.ts @@ -0,0 +1,31 @@ +import { LimiterDriver } from "./interfaces/LimiterDriver"; +import { BaseStrategy } from "./strategies/BaseStrategy"; +import { Injectable } from "@nestjs/common"; +import { RedisDriver } from "./drivers/redis"; + +@Injectable() +export class Limiter { + private static driver: LimiterDriver; + private static strategy: BaseStrategy; + constructor() { + Limiter.driver = new RedisDriver({ + driver: "redis", + host: "localhost", + port: 6379, + database: 0, + }); + Limiter.strategy = new BaseStrategy(Limiter.driver); + } + + static initializeToken = ( + key: string, + tokensCount: number, + intervalInSeconds: number + ) => { + Limiter.strategy.initializeToken(key, tokensCount, intervalInSeconds); + }; + + static useToken = (key: string) => { + Limiter.strategy.useToken(key); + }; +} diff --git a/lib/limiter/decorator.ts b/lib/limiter/decorator.ts new file mode 100644 index 0000000..6e80e85 --- /dev/null +++ b/lib/limiter/decorator.ts @@ -0,0 +1,27 @@ +export const Limit = (tokens: number, seconds: number) => { + console.log('first(): factory evaluated'); + return function ( + target: any, + propertyKey: string, + descriptor: PropertyDescriptor, + ) { + Reflect.defineMetadata('rate-limiter-tokens', tokens, target, propertyKey), + Reflect.defineMetadata( + 'rate-limiter-interval', + seconds, + target, + propertyKey, + ), + console.log('first(): called', propertyKey, descriptor, target); + + // var originalMethod = descriptor.value; + + // descriptor.value = function (...args: any[]) { + // console.log('Rate Limited'); + // // Limiter.useToken(funcKey); + // return originalMethod.apply(target, args); + // }; + + return descriptor; + }; +}; diff --git a/lib/limiter/drivers/index.ts b/lib/limiter/drivers/index.ts new file mode 100644 index 0000000..0d34fcd --- /dev/null +++ b/lib/limiter/drivers/index.ts @@ -0,0 +1,2 @@ +export * from "./memory"; +export * from "./redis"; diff --git a/lib/limiter/drivers/memory.ts b/lib/limiter/drivers/memory.ts new file mode 100644 index 0000000..e501d72 --- /dev/null +++ b/lib/limiter/drivers/memory.ts @@ -0,0 +1,75 @@ +import { LimiterDriver } from '../interfaces/LimiterDriver'; + +export class MemoryDriver implements LimiterDriver { + private static keyCounts = {}; + private static keyScores = {}; + private options = { prefix: 'in-memory-keys' }; + + async setCounter( + key: string, + value: number, + ttlInSec?: number, + ): Promise { + await this.set(key, value, ttlInSec); + } + + async incrementCounter(key: string): Promise { + MemoryDriver.keyCounts[this.storeKey(key)] += 1; + } + + async decrementCounter(key: string): Promise { + if ([undefined, 0].includes(await this.getCount(key))) { + return false; + } + MemoryDriver.keyCounts[this.storeKey(key)] -= 1; + return true; + } + + async delScoresLessThan(key: string, val: number): Promise { + let ele = MemoryDriver.keyScores[this.storeKey(key)]?.[0]; + if (!ele) return; + while (ele && ele < val) { + delete MemoryDriver.keyScores[this.storeKey(key)]?.[0]; + ele = MemoryDriver.keyScores[this.storeKey(key)]?.[0]; + } + } + + async addNewScore(key: string, val: number) { + if (!MemoryDriver.keyScores[this.storeKey(key)]) { + MemoryDriver.keyScores[this.storeKey(key)] = []; + } + return MemoryDriver.keyScores[this.storeKey(key)].append(val); + } + + async getScoresCount(key: string): Promise { + return MemoryDriver.keyScores[this.storeKey(key)]?.length ?? 0; + } + async getCount(key: string): Promise { + return MemoryDriver.keyCounts[this.storeKey(key)]; + } + + private async get(key: string): Promise { + const value = MemoryDriver.keyCounts[this.storeKey(key)]; + if (!value) return null; + return value; + } + + private async set( + key: string, + value: number, + ttlInSec?: number, + ): Promise { + const redisKey = this.storeKey(key); + MemoryDriver.keyCounts[redisKey] = value; + if (ttlInSec) { + setTimeout(() => { + delete MemoryDriver.keyCounts[redisKey]; + }, ttlInSec * 1000); + } + return true; + } + + private storeKey(key: string): string { + return `${this.options.prefix}:::${key}`; + } +} diff --git a/lib/limiter/drivers/redis.ts b/lib/limiter/drivers/redis.ts new file mode 100644 index 0000000..26d48a6 --- /dev/null +++ b/lib/limiter/drivers/redis.ts @@ -0,0 +1,93 @@ +import { RedisDriverOption } from "../../cache"; +import { Package } from "../../utils"; +import { LimiterDriver } from "../interfaces/LimiterDriver"; + +export class RedisDriver implements LimiterDriver { + private client: any; + + constructor(private options: RedisDriverOption) { + const IORedis = Package.load("ioredis"); + if (options.url) { + this.client = new IORedis(options.url, { db: options.database || 0 }); + } else { + this.client = new IORedis({ + host: options.host, + port: options.port, + username: options.username, + password: options.password, + db: options.database, + }); + } + } + + async setCounter( + key: string, + value: number, + ttlInSec?: number + ): Promise { + await this.set(key, value, ttlInSec); + } + + async incrementCounter(key: string): Promise { + await this.client.incr(this.storeKey(key)); + } + + async decrementCounter(key: string): Promise { + if ([undefined, 0].includes(+(await this.get(key)))) { + return false; + } + await this.client.decr(this.storeKey(key)); + return true; + } + + async delScoresLessThan(key: string, val: number): Promise { + let ele = await this.client.lindex(this.storeKey(key), 0); + if (!ele) return; + while (ele && ele < val) { + await this.client.lpop(this.storeKey(key), 0); + ele = await this.client.lindex(this.storeKey(key), 0); + } + } + + async addNewScore(key: string, val: number) { + await this.client.ladd(this.storeKey(key), val); + } + + async getScoresCount(key: string): Promise { + return await this.client.llen(this.storeKey(key)); + } + + async getCount(key: string): Promise { + return +(await this.client.get(key)); + } + + private async get(key: string): Promise { + const value = await this.client.get(this.storeKey(key)); + if (!value) return null; + try { + return JSON.parse(value); + } catch (e) { + return value; + } + } + + private async set( + key: string, + value: string | number | Record, + ttlInSec?: number + ): Promise { + try { + const redisKey = this.storeKey(key); + ttlInSec + ? await this.client.set(redisKey, JSON.stringify(value), "EX", ttlInSec) + : await this.client.set(redisKey, JSON.stringify(value)); + return true; + } catch { + return false; + } + } + + private storeKey(key: string): string { + return `${this.options.prefix}:::${key}`; + } +} diff --git a/lib/limiter/explorer.ts b/lib/limiter/explorer.ts new file mode 100644 index 0000000..291125a --- /dev/null +++ b/lib/limiter/explorer.ts @@ -0,0 +1,75 @@ +import { Injectable } from "@nestjs/common"; +import { DiscoveryService, MetadataScanner } from "@nestjs/core"; +import { ulid } from "ulid"; +import { Limiter } from "./rateLimiter"; +import { GenericFunction } from "../interfaces"; + +@Injectable() +export class LimiterExplorer { + constructor( + private readonly discovery: DiscoveryService, + private readonly metadataScanner: MetadataScanner + ) {} + + onModuleInit() { + const wrappers = this.discovery.getProviders(); + wrappers.forEach((w) => { + const { instance } = w; + if ( + !instance || + typeof instance === "string" || + !Object.getPrototypeOf(instance) + ) { + return; + } + + this.metadataScanner.scanFromPrototype( + instance, + Object.getPrototypeOf(instance), + (key: string) => this.lookupConsoleCommands(instance, key) + ); + }); + } + + lookupConsoleCommands( + instance: Record, + key: string + ) { + let methodRef = instance[key]; + const hasCommandMeta = Reflect.hasMetadata( + "rate-limiter-tokens", + instance, + key + ); + + if (!hasCommandMeta) return; + + const tokensCount = Reflect.getMetadata( + "rate-limiter-tokens", + instance, + key + ); + const frequency = Reflect.getMetadata( + "rate-limiter-interval", + instance, + key + ); + console.log("limiter found", methodRef, key, tokensCount, frequency); + const funcKey = ulid(); + Limiter.initializeToken(key + funcKey, tokensCount, frequency); + instance[key] = function (...args) { + Limiter.useToken(key + funcKey); + console.log("Rate Limited"); + return methodRef.apply(instance, args); + }; + + // const options: CommandMetaOptions = + // Reflect.getMetadata(ConsoleConstants.commandOptions, instance, key) || + // Reflect.getMetadata( + // ConsoleConstants.commandOptions, + // instance.constructor, + // ); + + // CommandMeta.setCommand(command, options, methodRef.bind(instance)); + } +} diff --git a/lib/limiter/index.ts b/lib/limiter/index.ts new file mode 100644 index 0000000..fc81bf4 --- /dev/null +++ b/lib/limiter/index.ts @@ -0,0 +1,6 @@ +export * from "./rateLimiter"; +export * from "./strategies"; +export * from "./drivers"; +export * from "./rateLimiter"; +export * from "./explorer"; +export * from "./decorator"; diff --git a/lib/limiter/interfaces/LimiterDriver.ts b/lib/limiter/interfaces/LimiterDriver.ts new file mode 100644 index 0000000..89f934e --- /dev/null +++ b/lib/limiter/interfaces/LimiterDriver.ts @@ -0,0 +1,9 @@ +export interface LimiterDriver { + setCounter(key: string, value: number, ttlInSec?: number): Promise; + incrementCounter(key: string): Promise; + decrementCounter(key: string): Promise; + delScoresLessThan(key: string, val: number): Promise; + addNewScore(key: string, val: number): void; + getScoresCount(key: string): Promise; + getCount(key: string): Promise; +} diff --git a/lib/limiter/strategies/BaseStrategy.ts b/lib/limiter/strategies/BaseStrategy.ts new file mode 100644 index 0000000..34476a8 --- /dev/null +++ b/lib/limiter/strategies/BaseStrategy.ts @@ -0,0 +1,37 @@ +import { GenericException } from "../../exceptions"; +import { LimiterDriver } from "../interfaces/LimiterDriver"; + +export class BaseStrategy { + protected static tokensQuota = {}; + protected static tokensIntervals = {}; + + constructor(protected driver: LimiterDriver) { + this.driver = driver; + } + + initializeToken = async ( + key: string, + tokensCount: number, + intervalInSeconds: number + ) => { + BaseStrategy.tokensQuota[key] = tokensCount; + BaseStrategy.tokensIntervals[key] = intervalInSeconds; + await this.driver.setCounter(key, tokensCount, intervalInSeconds); + }; + + useToken = async (key: string) => { + if ((await this.driver.getCount(key)) == undefined) { + await this.initializeToken( + key, + BaseStrategy.tokensQuota[key] - 1, + BaseStrategy.tokensIntervals[key] + ); + return; + } + const cut = await this.driver.decrementCounter(key); + console.log("current Count", await this.driver.getCount(key), cut); + if (!cut) { + throw new GenericException("Cannot be called."); + } + }; +} diff --git a/lib/limiter/strategies/SlidingWindowCounter.ts b/lib/limiter/strategies/SlidingWindowCounter.ts new file mode 100644 index 0000000..9855b50 --- /dev/null +++ b/lib/limiter/strategies/SlidingWindowCounter.ts @@ -0,0 +1,35 @@ +import { GenericException } from "../../exceptions"; +import { LimiterDriver } from "../interfaces/LimiterDriver"; +import { BaseStrategy } from "./BaseStrategy"; + +export class SlidingWindowCounter extends BaseStrategy { + constructor(driver: LimiterDriver) { + super(driver); + } + + initializeToken = async ( + key: string, + tokensCount: number, + intervalInSeconds: number + ) => { + SlidingWindowCounter.tokensQuota[key] = tokensCount; + SlidingWindowCounter.tokensIntervals[key] = intervalInSeconds; + await this.driver.setCounter(key, tokensCount); + }; + + useToken = async (key: string) => { + const current = new Date().valueOf(); + await this.driver.delScoresLessThan(key, current); + + if ( + (await this.driver.getScoresCount(key)) >= BaseStrategy.tokensQuota[key] + ) { + throw new GenericException("Cannot be called."); + } + await this.driver.addNewScore(key, current); + }; + + setTimer = () => { + // this.setTokens(); + }; +} diff --git a/lib/limiter/strategies/TokenBucket.ts b/lib/limiter/strategies/TokenBucket.ts new file mode 100644 index 0000000..497f4d1 --- /dev/null +++ b/lib/limiter/strategies/TokenBucket.ts @@ -0,0 +1,43 @@ +import { BaseStrategy } from "./BaseStrategy"; +import { LimiterDriver } from "../interfaces/LimiterDriver"; +import { GenericException } from "../../exceptions"; + +export class TokenBucketStrategy extends BaseStrategy { + constructor(driver: LimiterDriver) { + super(driver); + } + + initializeToken = async ( + key: string, + tokensCount: number, + intervalInSeconds: number + ) => { + TokenBucketStrategy.tokensQuota[key] = tokensCount; + TokenBucketStrategy.tokensIntervals[key] = intervalInSeconds; + await this.driver.setCounter(key, tokensCount); + }; + + useToken = async (key: string) => { + if (!(await this.driver.decrementCounter(key))) { + throw new GenericException("Cannot be called."); + } + }; + + incrementTokens = async () => { + for (const key in TokenBucketStrategy.tokensQuota) { + if ( + (await this.driver.getCount(key)) == + TokenBucketStrategy.tokensQuota[key] + ) { + continue; + } + setInterval(async () => { + await this.driver.incrementCounter(key); + }, TokenBucketStrategy.tokensIntervals[key] * 1000); + } + }; + + setTimer = () => { + this.incrementTokens(); + }; +} diff --git a/lib/limiter/strategies/WindowCounter.ts b/lib/limiter/strategies/WindowCounter.ts new file mode 100644 index 0000000..b855155 --- /dev/null +++ b/lib/limiter/strategies/WindowCounter.ts @@ -0,0 +1,43 @@ +import { BaseStrategy } from "./BaseStrategy"; +import { LimiterDriver } from "../interfaces/LimiterDriver"; +import { GenericException } from "../../exceptions"; + +export class WindowCounterStrategy extends BaseStrategy { + constructor(driver: LimiterDriver) { + super(driver); + } + + initializeToken = async ( + key: string, + tokensCount: number, + intervalInSeconds: number + ) => { + WindowCounterStrategy.tokensQuota[key] = tokensCount; + WindowCounterStrategy.tokensIntervals[key] = intervalInSeconds; + await this.driver.setCounter(key, tokensCount); + }; + + useToken = async (key: string) => { + if (!(await this.driver.decrementCounter(key))) { + throw new GenericException("Cannot be called."); + } + }; + + resetTokens = async () => { + for (const key in BaseStrategy.tokensQuota) { + if ((await this.driver.getCount(key)) == BaseStrategy.tokensQuota[key]) { + continue; + } + setInterval(async () => { + await this.driver.setCounter( + key, + WindowCounterStrategy.tokensQuota[key] + ); + }, BaseStrategy.tokensIntervals[key] * 1000); + } + }; + + setTimer = () => { + this.resetTokens(); + }; +} diff --git a/lib/limiter/strategies/index.ts b/lib/limiter/strategies/index.ts new file mode 100644 index 0000000..9eddde2 --- /dev/null +++ b/lib/limiter/strategies/index.ts @@ -0,0 +1,4 @@ +export * from "./BaseStrategy"; +export * from "./SlidingWindowCounter"; +export * from "./TokenBucket"; +export * from "./WindowCounter"; From cb6b1bc5c16ed27f40984bd97ecd4445b10d4a03 Mon Sep 17 00:00:00 2001 From: Piyush Chhabra Date: Mon, 2 Sep 2024 14:03:23 +0530 Subject: [PATCH 2/6] ADD: config keys --- lib/limiter/RateLimiter.ts | 25 ++++++++++++++++------- lib/limiter/constants.ts | 2 ++ lib/limiter/decorator.ts | 24 ++++++---------------- lib/limiter/explorer.ts | 30 ++++------------------------ lib/limiter/interfaces/options.ts | 33 +++++++++++++++++++++++++++++++ 5 files changed, 63 insertions(+), 51 deletions(-) create mode 100644 lib/limiter/constants.ts create mode 100644 lib/limiter/interfaces/options.ts diff --git a/lib/limiter/RateLimiter.ts b/lib/limiter/RateLimiter.ts index 88feb1c..52f85b5 100644 --- a/lib/limiter/RateLimiter.ts +++ b/lib/limiter/RateLimiter.ts @@ -2,18 +2,29 @@ import { LimiterDriver } from "./interfaces/LimiterDriver"; import { BaseStrategy } from "./strategies/BaseStrategy"; import { Injectable } from "@nestjs/common"; import { RedisDriver } from "./drivers/redis"; +import { IntentConfig } from "../config/service"; +import { + DriversMap, + LimiterDriverType, + LimiterOptions, +} from "./interfaces/options"; @Injectable() export class Limiter { private static driver: LimiterDriver; private static strategy: BaseStrategy; - constructor() { - Limiter.driver = new RedisDriver({ - driver: "redis", - host: "localhost", - port: 6379, - database: 0, - }); + constructor(private config: IntentConfig) { + const options = this.config.get("queue"); + switch (options.driver) { + case LimiterDriverType.REDIS: { + Limiter.driver = new DriversMap[LimiterDriverType.REDIS]( + options.connection + ); + } + default: { + Limiter.driver = new DriversMap[LimiterDriverType.IN_MEMORY](); + } + } Limiter.strategy = new BaseStrategy(Limiter.driver); } diff --git a/lib/limiter/constants.ts b/lib/limiter/constants.ts new file mode 100644 index 0000000..06c9e52 --- /dev/null +++ b/lib/limiter/constants.ts @@ -0,0 +1,2 @@ +export const TOKEN_COUNT = "__TOKEN_COUNT__"; +export const REFILL_INTERVAL = "__REFILL_INTERVAL__"; diff --git a/lib/limiter/decorator.ts b/lib/limiter/decorator.ts index 6e80e85..6068e03 100644 --- a/lib/limiter/decorator.ts +++ b/lib/limiter/decorator.ts @@ -1,26 +1,14 @@ +import { REFILL_INTERVAL, TOKEN_COUNT } from "./constants"; + export const Limit = (tokens: number, seconds: number) => { - console.log('first(): factory evaluated'); + console.log("first(): factory evaluated"); return function ( target: any, propertyKey: string, - descriptor: PropertyDescriptor, + descriptor: PropertyDescriptor ) { - Reflect.defineMetadata('rate-limiter-tokens', tokens, target, propertyKey), - Reflect.defineMetadata( - 'rate-limiter-interval', - seconds, - target, - propertyKey, - ), - console.log('first(): called', propertyKey, descriptor, target); - - // var originalMethod = descriptor.value; - - // descriptor.value = function (...args: any[]) { - // console.log('Rate Limited'); - // // Limiter.useToken(funcKey); - // return originalMethod.apply(target, args); - // }; + Reflect.defineMetadata(TOKEN_COUNT, tokens, target, propertyKey); + Reflect.defineMetadata(REFILL_INTERVAL, seconds, target, propertyKey); return descriptor; }; diff --git a/lib/limiter/explorer.ts b/lib/limiter/explorer.ts index 291125a..75c535d 100644 --- a/lib/limiter/explorer.ts +++ b/lib/limiter/explorer.ts @@ -3,6 +3,7 @@ import { DiscoveryService, MetadataScanner } from "@nestjs/core"; import { ulid } from "ulid"; import { Limiter } from "./rateLimiter"; import { GenericFunction } from "../interfaces"; +import { REFILL_INTERVAL, TOKEN_COUNT } from "./constants"; @Injectable() export class LimiterExplorer { @@ -36,40 +37,17 @@ export class LimiterExplorer { key: string ) { let methodRef = instance[key]; - const hasCommandMeta = Reflect.hasMetadata( - "rate-limiter-tokens", - instance, - key - ); + const hasCommandMeta = Reflect.hasMetadata(TOKEN_COUNT, instance, key); if (!hasCommandMeta) return; - const tokensCount = Reflect.getMetadata( - "rate-limiter-tokens", - instance, - key - ); - const frequency = Reflect.getMetadata( - "rate-limiter-interval", - instance, - key - ); - console.log("limiter found", methodRef, key, tokensCount, frequency); + const tokensCount = Reflect.getMetadata(TOKEN_COUNT, instance, key); + const frequency = Reflect.getMetadata(REFILL_INTERVAL, instance, key); const funcKey = ulid(); Limiter.initializeToken(key + funcKey, tokensCount, frequency); instance[key] = function (...args) { Limiter.useToken(key + funcKey); - console.log("Rate Limited"); return methodRef.apply(instance, args); }; - - // const options: CommandMetaOptions = - // Reflect.getMetadata(ConsoleConstants.commandOptions, instance, key) || - // Reflect.getMetadata( - // ConsoleConstants.commandOptions, - // instance.constructor, - // ); - - // CommandMeta.setCommand(command, options, methodRef.bind(instance)); } } diff --git a/lib/limiter/interfaces/options.ts b/lib/limiter/interfaces/options.ts new file mode 100644 index 0000000..3c03d47 --- /dev/null +++ b/lib/limiter/interfaces/options.ts @@ -0,0 +1,33 @@ +import { MemoryDriver, RedisDriver } from "../drivers"; + +export interface LimiterOptions { + isGlobal?: boolean; + driver: LimiterDriver; + defaultTokensCount?: number; + defaultRefillIntervalInSeconds?: number; + connection?: RedisConnection; +} + +export interface RedisConnection { + host: string; + port: number; + database: number; + password: string; +} + +export enum LimiterDriverType { + REDIS = "redis", + IN_MEMORY = "in-memory", +} + +export const defaultOptions = { + isGlobal: true, + driver: LimiterDriverType.IN_MEMORY, + defaultTokensCount: 40, + defaultRefillIntervalInSeconds: 10, +}; + +export const DriversMap = { + [LimiterDriverType.REDIS]: RedisDriver, + [LimiterDriverType.IN_MEMORY]: MemoryDriver, +}; From 5c6feb7c835fbfc1ac125bf4482486badf3d63d7 Mon Sep 17 00:00:00 2001 From: Piyush Chhabra Date: Mon, 2 Sep 2024 14:05:32 +0530 Subject: [PATCH 3/6] FIX: driver type in options --- lib/limiter/interfaces/options.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/limiter/interfaces/options.ts b/lib/limiter/interfaces/options.ts index 3c03d47..d79ff1f 100644 --- a/lib/limiter/interfaces/options.ts +++ b/lib/limiter/interfaces/options.ts @@ -2,7 +2,7 @@ import { MemoryDriver, RedisDriver } from "../drivers"; export interface LimiterOptions { isGlobal?: boolean; - driver: LimiterDriver; + driver: LimiterDriverType; defaultTokensCount?: number; defaultRefillIntervalInSeconds?: number; connection?: RedisConnection; From a48d848d4f5d443fe3eb303d7ec94c974299f892 Mon Sep 17 00:00:00 2001 From: Piyush Chhabra Date: Tue, 17 Sep 2024 01:08:54 +0530 Subject: [PATCH 4/6] CHANGE: case of files --- .../interfaces/{LimiterDriver.ts => limiterDriver.ts} | 0 lib/limiter/{RateLimiter.ts => rateLimiter.ts} | 0 .../strategies/{BaseStrategy.ts => baseStrategy.ts} | 0 lib/limiter/strategies/index.ts | 8 ++++---- .../{SlidingWindowCounter.ts => slidingWindowCounter.ts} | 0 lib/limiter/strategies/{TokenBucket.ts => tokenBucket.ts} | 0 .../strategies/{WindowCounter.ts => windowCounter.ts} | 0 7 files changed, 4 insertions(+), 4 deletions(-) rename lib/limiter/interfaces/{LimiterDriver.ts => limiterDriver.ts} (100%) rename lib/limiter/{RateLimiter.ts => rateLimiter.ts} (100%) rename lib/limiter/strategies/{BaseStrategy.ts => baseStrategy.ts} (100%) rename lib/limiter/strategies/{SlidingWindowCounter.ts => slidingWindowCounter.ts} (100%) rename lib/limiter/strategies/{TokenBucket.ts => tokenBucket.ts} (100%) rename lib/limiter/strategies/{WindowCounter.ts => windowCounter.ts} (100%) diff --git a/lib/limiter/interfaces/LimiterDriver.ts b/lib/limiter/interfaces/limiterDriver.ts similarity index 100% rename from lib/limiter/interfaces/LimiterDriver.ts rename to lib/limiter/interfaces/limiterDriver.ts diff --git a/lib/limiter/RateLimiter.ts b/lib/limiter/rateLimiter.ts similarity index 100% rename from lib/limiter/RateLimiter.ts rename to lib/limiter/rateLimiter.ts diff --git a/lib/limiter/strategies/BaseStrategy.ts b/lib/limiter/strategies/baseStrategy.ts similarity index 100% rename from lib/limiter/strategies/BaseStrategy.ts rename to lib/limiter/strategies/baseStrategy.ts diff --git a/lib/limiter/strategies/index.ts b/lib/limiter/strategies/index.ts index 9eddde2..dbddbe4 100644 --- a/lib/limiter/strategies/index.ts +++ b/lib/limiter/strategies/index.ts @@ -1,4 +1,4 @@ -export * from "./BaseStrategy"; -export * from "./SlidingWindowCounter"; -export * from "./TokenBucket"; -export * from "./WindowCounter"; +export * from './baseStrategy'; +export * from './slidingWindowCounter'; +export * from './tokenBucket'; +export * from './windowCounter'; diff --git a/lib/limiter/strategies/SlidingWindowCounter.ts b/lib/limiter/strategies/slidingWindowCounter.ts similarity index 100% rename from lib/limiter/strategies/SlidingWindowCounter.ts rename to lib/limiter/strategies/slidingWindowCounter.ts diff --git a/lib/limiter/strategies/TokenBucket.ts b/lib/limiter/strategies/tokenBucket.ts similarity index 100% rename from lib/limiter/strategies/TokenBucket.ts rename to lib/limiter/strategies/tokenBucket.ts diff --git a/lib/limiter/strategies/WindowCounter.ts b/lib/limiter/strategies/windowCounter.ts similarity index 100% rename from lib/limiter/strategies/WindowCounter.ts rename to lib/limiter/strategies/windowCounter.ts From 5d3c1fe54d0550f87e21a4c358b06b95641a3e6d Mon Sep 17 00:00:00 2001 From: Piyush Chhabra Date: Tue, 17 Sep 2024 01:17:20 +0530 Subject: [PATCH 5/6] REFACTOR: prettier formatting --- lib/limiter/constants.ts | 4 ++-- lib/limiter/decorator.ts | 6 +++--- lib/limiter/drivers/index.ts | 4 ++-- lib/limiter/drivers/redis.ts | 14 +++++++------- lib/limiter/index.ts | 10 ++++------ lib/limiter/interfaces/options.ts | 6 +++--- lib/limiter/rateLimiter.ts | 18 +++++++++--------- lib/limiter/strategies/baseStrategy.ts | 12 ++++++------ .../strategies/slidingWindowCounter.ts | 10 +++++----- lib/limiter/strategies/tokenBucket.ts | 10 +++++----- lib/limiter/strategies/windowCounter.ts | 12 ++++++------ packages/core/lib/explorer.ts | 19 +++++++++++++++++++ 12 files changed, 71 insertions(+), 54 deletions(-) diff --git a/lib/limiter/constants.ts b/lib/limiter/constants.ts index 06c9e52..b2ed399 100644 --- a/lib/limiter/constants.ts +++ b/lib/limiter/constants.ts @@ -1,2 +1,2 @@ -export const TOKEN_COUNT = "__TOKEN_COUNT__"; -export const REFILL_INTERVAL = "__REFILL_INTERVAL__"; +export const TOKEN_COUNT = '__TOKEN_COUNT__'; +export const REFILL_INTERVAL = '__REFILL_INTERVAL__'; diff --git a/lib/limiter/decorator.ts b/lib/limiter/decorator.ts index 6068e03..abd3a87 100644 --- a/lib/limiter/decorator.ts +++ b/lib/limiter/decorator.ts @@ -1,11 +1,11 @@ -import { REFILL_INTERVAL, TOKEN_COUNT } from "./constants"; +import { REFILL_INTERVAL, TOKEN_COUNT } from './constants'; export const Limit = (tokens: number, seconds: number) => { - console.log("first(): factory evaluated"); + console.log('first(): factory evaluated'); return function ( target: any, propertyKey: string, - descriptor: PropertyDescriptor + descriptor: PropertyDescriptor, ) { Reflect.defineMetadata(TOKEN_COUNT, tokens, target, propertyKey); Reflect.defineMetadata(REFILL_INTERVAL, seconds, target, propertyKey); diff --git a/lib/limiter/drivers/index.ts b/lib/limiter/drivers/index.ts index 0d34fcd..a187a39 100644 --- a/lib/limiter/drivers/index.ts +++ b/lib/limiter/drivers/index.ts @@ -1,2 +1,2 @@ -export * from "./memory"; -export * from "./redis"; +export * from './memory'; +export * from './redis'; diff --git a/lib/limiter/drivers/redis.ts b/lib/limiter/drivers/redis.ts index 26d48a6..1940a8f 100644 --- a/lib/limiter/drivers/redis.ts +++ b/lib/limiter/drivers/redis.ts @@ -1,12 +1,12 @@ -import { RedisDriverOption } from "../../cache"; -import { Package } from "../../utils"; -import { LimiterDriver } from "../interfaces/LimiterDriver"; +import { RedisDriverOption } from '../../cache'; +import { Package } from '../../utils'; +import { LimiterDriver } from '../interfaces/limiterDriver'; export class RedisDriver implements LimiterDriver { private client: any; constructor(private options: RedisDriverOption) { - const IORedis = Package.load("ioredis"); + const IORedis = Package.load('ioredis'); if (options.url) { this.client = new IORedis(options.url, { db: options.database || 0 }); } else { @@ -23,7 +23,7 @@ export class RedisDriver implements LimiterDriver { async setCounter( key: string, value: number, - ttlInSec?: number + ttlInSec?: number, ): Promise { await this.set(key, value, ttlInSec); } @@ -74,12 +74,12 @@ export class RedisDriver implements LimiterDriver { private async set( key: string, value: string | number | Record, - ttlInSec?: number + ttlInSec?: number, ): Promise { try { const redisKey = this.storeKey(key); ttlInSec - ? await this.client.set(redisKey, JSON.stringify(value), "EX", ttlInSec) + ? await this.client.set(redisKey, JSON.stringify(value), 'EX', ttlInSec) : await this.client.set(redisKey, JSON.stringify(value)); return true; } catch { diff --git a/lib/limiter/index.ts b/lib/limiter/index.ts index fc81bf4..651635c 100644 --- a/lib/limiter/index.ts +++ b/lib/limiter/index.ts @@ -1,6 +1,4 @@ -export * from "./rateLimiter"; -export * from "./strategies"; -export * from "./drivers"; -export * from "./rateLimiter"; -export * from "./explorer"; -export * from "./decorator"; +export * from './rateLimiter'; +export * from './strategies'; +export * from './drivers'; +export * from './decorator'; diff --git a/lib/limiter/interfaces/options.ts b/lib/limiter/interfaces/options.ts index d79ff1f..c93523a 100644 --- a/lib/limiter/interfaces/options.ts +++ b/lib/limiter/interfaces/options.ts @@ -1,4 +1,4 @@ -import { MemoryDriver, RedisDriver } from "../drivers"; +import { MemoryDriver, RedisDriver } from '../drivers'; export interface LimiterOptions { isGlobal?: boolean; @@ -16,8 +16,8 @@ export interface RedisConnection { } export enum LimiterDriverType { - REDIS = "redis", - IN_MEMORY = "in-memory", + REDIS = 'redis', + IN_MEMORY = 'in-memory', } export const defaultOptions = { diff --git a/lib/limiter/rateLimiter.ts b/lib/limiter/rateLimiter.ts index 52f85b5..4d1e309 100644 --- a/lib/limiter/rateLimiter.ts +++ b/lib/limiter/rateLimiter.ts @@ -1,24 +1,24 @@ -import { LimiterDriver } from "./interfaces/LimiterDriver"; -import { BaseStrategy } from "./strategies/BaseStrategy"; -import { Injectable } from "@nestjs/common"; -import { RedisDriver } from "./drivers/redis"; -import { IntentConfig } from "../config/service"; +import { LimiterDriver } from './interfaces/limiterDriver'; +import { BaseStrategy } from './strategies/baseStrategy'; +import { Injectable } from '@nestjs/common'; +import { RedisDriver } from './drivers/redis'; +import { IntentConfig } from '../config/service'; import { DriversMap, LimiterDriverType, LimiterOptions, -} from "./interfaces/options"; +} from './interfaces/options'; @Injectable() export class Limiter { private static driver: LimiterDriver; private static strategy: BaseStrategy; constructor(private config: IntentConfig) { - const options = this.config.get("queue"); + const options = this.config.get('queue'); switch (options.driver) { case LimiterDriverType.REDIS: { Limiter.driver = new DriversMap[LimiterDriverType.REDIS]( - options.connection + options.connection, ); } default: { @@ -31,7 +31,7 @@ export class Limiter { static initializeToken = ( key: string, tokensCount: number, - intervalInSeconds: number + intervalInSeconds: number, ) => { Limiter.strategy.initializeToken(key, tokensCount, intervalInSeconds); }; diff --git a/lib/limiter/strategies/baseStrategy.ts b/lib/limiter/strategies/baseStrategy.ts index 34476a8..1d108cd 100644 --- a/lib/limiter/strategies/baseStrategy.ts +++ b/lib/limiter/strategies/baseStrategy.ts @@ -1,5 +1,5 @@ -import { GenericException } from "../../exceptions"; -import { LimiterDriver } from "../interfaces/LimiterDriver"; +import { GenericException } from '../../exceptions'; +import { LimiterDriver } from '../interfaces/limiterDriver'; export class BaseStrategy { protected static tokensQuota = {}; @@ -12,7 +12,7 @@ export class BaseStrategy { initializeToken = async ( key: string, tokensCount: number, - intervalInSeconds: number + intervalInSeconds: number, ) => { BaseStrategy.tokensQuota[key] = tokensCount; BaseStrategy.tokensIntervals[key] = intervalInSeconds; @@ -24,14 +24,14 @@ export class BaseStrategy { await this.initializeToken( key, BaseStrategy.tokensQuota[key] - 1, - BaseStrategy.tokensIntervals[key] + BaseStrategy.tokensIntervals[key], ); return; } const cut = await this.driver.decrementCounter(key); - console.log("current Count", await this.driver.getCount(key), cut); + console.log('current Count', await this.driver.getCount(key), cut); if (!cut) { - throw new GenericException("Cannot be called."); + throw new GenericException('Cannot be called.'); } }; } diff --git a/lib/limiter/strategies/slidingWindowCounter.ts b/lib/limiter/strategies/slidingWindowCounter.ts index 9855b50..3a6b5db 100644 --- a/lib/limiter/strategies/slidingWindowCounter.ts +++ b/lib/limiter/strategies/slidingWindowCounter.ts @@ -1,6 +1,6 @@ -import { GenericException } from "../../exceptions"; -import { LimiterDriver } from "../interfaces/LimiterDriver"; -import { BaseStrategy } from "./BaseStrategy"; +import { GenericException } from '../../exceptions'; +import { LimiterDriver } from '../interfaces/limiterDriver'; +import { BaseStrategy } from './baseStrategy'; export class SlidingWindowCounter extends BaseStrategy { constructor(driver: LimiterDriver) { @@ -10,7 +10,7 @@ export class SlidingWindowCounter extends BaseStrategy { initializeToken = async ( key: string, tokensCount: number, - intervalInSeconds: number + intervalInSeconds: number, ) => { SlidingWindowCounter.tokensQuota[key] = tokensCount; SlidingWindowCounter.tokensIntervals[key] = intervalInSeconds; @@ -24,7 +24,7 @@ export class SlidingWindowCounter extends BaseStrategy { if ( (await this.driver.getScoresCount(key)) >= BaseStrategy.tokensQuota[key] ) { - throw new GenericException("Cannot be called."); + throw new GenericException('Cannot be called.'); } await this.driver.addNewScore(key, current); }; diff --git a/lib/limiter/strategies/tokenBucket.ts b/lib/limiter/strategies/tokenBucket.ts index 497f4d1..2a8bcbb 100644 --- a/lib/limiter/strategies/tokenBucket.ts +++ b/lib/limiter/strategies/tokenBucket.ts @@ -1,6 +1,6 @@ -import { BaseStrategy } from "./BaseStrategy"; -import { LimiterDriver } from "../interfaces/LimiterDriver"; -import { GenericException } from "../../exceptions"; +import { BaseStrategy } from './baseStrategy'; +import { LimiterDriver } from '../interfaces/limiterDriver'; +import { GenericException } from '../../exceptions'; export class TokenBucketStrategy extends BaseStrategy { constructor(driver: LimiterDriver) { @@ -10,7 +10,7 @@ export class TokenBucketStrategy extends BaseStrategy { initializeToken = async ( key: string, tokensCount: number, - intervalInSeconds: number + intervalInSeconds: number, ) => { TokenBucketStrategy.tokensQuota[key] = tokensCount; TokenBucketStrategy.tokensIntervals[key] = intervalInSeconds; @@ -19,7 +19,7 @@ export class TokenBucketStrategy extends BaseStrategy { useToken = async (key: string) => { if (!(await this.driver.decrementCounter(key))) { - throw new GenericException("Cannot be called."); + throw new GenericException('Cannot be called.'); } }; diff --git a/lib/limiter/strategies/windowCounter.ts b/lib/limiter/strategies/windowCounter.ts index b855155..7e4fb95 100644 --- a/lib/limiter/strategies/windowCounter.ts +++ b/lib/limiter/strategies/windowCounter.ts @@ -1,6 +1,6 @@ -import { BaseStrategy } from "./BaseStrategy"; -import { LimiterDriver } from "../interfaces/LimiterDriver"; -import { GenericException } from "../../exceptions"; +import { BaseStrategy } from './baseStrategy'; +import { LimiterDriver } from '../interfaces/limiterDriver'; +import { GenericException } from '../../exceptions'; export class WindowCounterStrategy extends BaseStrategy { constructor(driver: LimiterDriver) { @@ -10,7 +10,7 @@ export class WindowCounterStrategy extends BaseStrategy { initializeToken = async ( key: string, tokensCount: number, - intervalInSeconds: number + intervalInSeconds: number, ) => { WindowCounterStrategy.tokensQuota[key] = tokensCount; WindowCounterStrategy.tokensIntervals[key] = intervalInSeconds; @@ -19,7 +19,7 @@ export class WindowCounterStrategy extends BaseStrategy { useToken = async (key: string) => { if (!(await this.driver.decrementCounter(key))) { - throw new GenericException("Cannot be called."); + throw new GenericException('Cannot be called.'); } }; @@ -31,7 +31,7 @@ export class WindowCounterStrategy extends BaseStrategy { setInterval(async () => { await this.driver.setCounter( key, - WindowCounterStrategy.tokensQuota[key] + WindowCounterStrategy.tokensQuota[key], ); }, BaseStrategy.tokensIntervals[key] * 1000); } diff --git a/packages/core/lib/explorer.ts b/packages/core/lib/explorer.ts index 416a219..336697e 100644 --- a/packages/core/lib/explorer.ts +++ b/packages/core/lib/explorer.ts @@ -98,4 +98,23 @@ export class IntentExplorer { CommandMeta.setCommand(command, options, methodRef.bind(instance)); } + + lookupLimittedMethods( + instance: Record, + key: string, + ) { + let methodRef = instance[key]; + const hasCommandMeta = Reflect.hasMetadata(TOKEN_COUNT, instance, key); + + if (!hasCommandMeta) return; + + const tokensCount = Reflect.getMetadata(TOKEN_COUNT, instance, key); + const frequency = Reflect.getMetadata(REFILL_INTERVAL, instance, key); + const funcKey = ulid(); + Limiter.initializeToken(key + funcKey, tokensCount, frequency); + instance[key] = function (...args) { + Limiter.useToken(key + funcKey); + return methodRef.apply(instance, args); + }; + } } From e74fe53469fb82a6da1be546ef905cd51223a61b Mon Sep 17 00:00:00 2001 From: Piyush Chhabra Date: Thu, 23 Jan 2025 16:54:31 +0000 Subject: [PATCH 6/6] refactor: code directory --- lib/limiter/explorer.ts | 53 ------------------- packages/core/lib/explorer.ts | 3 ++ .../core/lib}/limiter/constants.ts | 0 .../core/lib}/limiter/decorator.ts | 0 .../core/lib}/limiter/drivers/index.ts | 0 .../core/lib}/limiter/drivers/memory.ts | 2 +- .../core/lib}/limiter/drivers/redis.ts | 0 {lib => packages/core/lib}/limiter/index.ts | 0 .../lib}/limiter/interfaces/limiterDriver.ts | 0 .../core/lib}/limiter/interfaces/options.ts | 0 .../core/lib}/limiter/rateLimiter.ts | 9 ++-- .../lib}/limiter/strategies/baseStrategy.ts | 0 .../core/lib}/limiter/strategies/index.ts | 0 .../strategies/slidingWindowCounter.ts | 0 .../lib}/limiter/strategies/tokenBucket.ts | 0 .../lib}/limiter/strategies/windowCounter.ts | 0 16 files changed, 8 insertions(+), 59 deletions(-) delete mode 100644 lib/limiter/explorer.ts rename {lib => packages/core/lib}/limiter/constants.ts (100%) rename {lib => packages/core/lib}/limiter/decorator.ts (100%) rename {lib => packages/core/lib}/limiter/drivers/index.ts (100%) rename {lib => packages/core/lib}/limiter/drivers/memory.ts (97%) rename {lib => packages/core/lib}/limiter/drivers/redis.ts (100%) rename {lib => packages/core/lib}/limiter/index.ts (100%) rename {lib => packages/core/lib}/limiter/interfaces/limiterDriver.ts (100%) rename {lib => packages/core/lib}/limiter/interfaces/options.ts (100%) rename {lib => packages/core/lib}/limiter/rateLimiter.ts (81%) rename {lib => packages/core/lib}/limiter/strategies/baseStrategy.ts (100%) rename {lib => packages/core/lib}/limiter/strategies/index.ts (100%) rename {lib => packages/core/lib}/limiter/strategies/slidingWindowCounter.ts (100%) rename {lib => packages/core/lib}/limiter/strategies/tokenBucket.ts (100%) rename {lib => packages/core/lib}/limiter/strategies/windowCounter.ts (100%) diff --git a/lib/limiter/explorer.ts b/lib/limiter/explorer.ts deleted file mode 100644 index 75c535d..0000000 --- a/lib/limiter/explorer.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Injectable } from "@nestjs/common"; -import { DiscoveryService, MetadataScanner } from "@nestjs/core"; -import { ulid } from "ulid"; -import { Limiter } from "./rateLimiter"; -import { GenericFunction } from "../interfaces"; -import { REFILL_INTERVAL, TOKEN_COUNT } from "./constants"; - -@Injectable() -export class LimiterExplorer { - constructor( - private readonly discovery: DiscoveryService, - private readonly metadataScanner: MetadataScanner - ) {} - - onModuleInit() { - const wrappers = this.discovery.getProviders(); - wrappers.forEach((w) => { - const { instance } = w; - if ( - !instance || - typeof instance === "string" || - !Object.getPrototypeOf(instance) - ) { - return; - } - - this.metadataScanner.scanFromPrototype( - instance, - Object.getPrototypeOf(instance), - (key: string) => this.lookupConsoleCommands(instance, key) - ); - }); - } - - lookupConsoleCommands( - instance: Record, - key: string - ) { - let methodRef = instance[key]; - const hasCommandMeta = Reflect.hasMetadata(TOKEN_COUNT, instance, key); - - if (!hasCommandMeta) return; - - const tokensCount = Reflect.getMetadata(TOKEN_COUNT, instance, key); - const frequency = Reflect.getMetadata(REFILL_INTERVAL, instance, key); - const funcKey = ulid(); - Limiter.initializeToken(key + funcKey, tokensCount, frequency); - instance[key] = function (...args) { - Limiter.useToken(key + funcKey); - return methodRef.apply(instance, args); - }; - } -} diff --git a/packages/core/lib/explorer.ts b/packages/core/lib/explorer.ts index 336697e..f4c8546 100644 --- a/packages/core/lib/explorer.ts +++ b/packages/core/lib/explorer.ts @@ -7,6 +7,9 @@ import { GenericFunction } from './interfaces'; import { JOB_NAME, JOB_OPTIONS } from './queue/constants'; import { QueueMetadata } from './queue/metadata'; import { Injectable } from './foundation'; +import { REFILL_INTERVAL, TOKEN_COUNT } from './limiter/constants'; +import { ulid } from 'ulid'; +import { Limiter } from './limiter'; @Injectable() export class IntentExplorer { diff --git a/lib/limiter/constants.ts b/packages/core/lib/limiter/constants.ts similarity index 100% rename from lib/limiter/constants.ts rename to packages/core/lib/limiter/constants.ts diff --git a/lib/limiter/decorator.ts b/packages/core/lib/limiter/decorator.ts similarity index 100% rename from lib/limiter/decorator.ts rename to packages/core/lib/limiter/decorator.ts diff --git a/lib/limiter/drivers/index.ts b/packages/core/lib/limiter/drivers/index.ts similarity index 100% rename from lib/limiter/drivers/index.ts rename to packages/core/lib/limiter/drivers/index.ts diff --git a/lib/limiter/drivers/memory.ts b/packages/core/lib/limiter/drivers/memory.ts similarity index 97% rename from lib/limiter/drivers/memory.ts rename to packages/core/lib/limiter/drivers/memory.ts index e501d72..92e6934 100644 --- a/lib/limiter/drivers/memory.ts +++ b/packages/core/lib/limiter/drivers/memory.ts @@ -1,4 +1,4 @@ -import { LimiterDriver } from '../interfaces/LimiterDriver'; +import { LimiterDriver } from '../interfaces/limiterDriver'; export class MemoryDriver implements LimiterDriver { private static keyCounts = {}; diff --git a/lib/limiter/drivers/redis.ts b/packages/core/lib/limiter/drivers/redis.ts similarity index 100% rename from lib/limiter/drivers/redis.ts rename to packages/core/lib/limiter/drivers/redis.ts diff --git a/lib/limiter/index.ts b/packages/core/lib/limiter/index.ts similarity index 100% rename from lib/limiter/index.ts rename to packages/core/lib/limiter/index.ts diff --git a/lib/limiter/interfaces/limiterDriver.ts b/packages/core/lib/limiter/interfaces/limiterDriver.ts similarity index 100% rename from lib/limiter/interfaces/limiterDriver.ts rename to packages/core/lib/limiter/interfaces/limiterDriver.ts diff --git a/lib/limiter/interfaces/options.ts b/packages/core/lib/limiter/interfaces/options.ts similarity index 100% rename from lib/limiter/interfaces/options.ts rename to packages/core/lib/limiter/interfaces/options.ts diff --git a/lib/limiter/rateLimiter.ts b/packages/core/lib/limiter/rateLimiter.ts similarity index 81% rename from lib/limiter/rateLimiter.ts rename to packages/core/lib/limiter/rateLimiter.ts index 4d1e309..d3d53f9 100644 --- a/lib/limiter/rateLimiter.ts +++ b/packages/core/lib/limiter/rateLimiter.ts @@ -1,20 +1,19 @@ import { LimiterDriver } from './interfaces/limiterDriver'; import { BaseStrategy } from './strategies/baseStrategy'; import { Injectable } from '@nestjs/common'; -import { RedisDriver } from './drivers/redis'; -import { IntentConfig } from '../config/service'; +import { ConfigService } from '../config/service'; import { DriversMap, LimiterDriverType, - LimiterOptions, } from './interfaces/options'; @Injectable() export class Limiter { private static driver: LimiterDriver; private static strategy: BaseStrategy; - constructor(private config: IntentConfig) { - const options = this.config.get('queue'); + constructor(private config: ConfigService) { + const options = this.config.get('limiter'); + if(!options) return switch (options.driver) { case LimiterDriverType.REDIS: { Limiter.driver = new DriversMap[LimiterDriverType.REDIS]( diff --git a/lib/limiter/strategies/baseStrategy.ts b/packages/core/lib/limiter/strategies/baseStrategy.ts similarity index 100% rename from lib/limiter/strategies/baseStrategy.ts rename to packages/core/lib/limiter/strategies/baseStrategy.ts diff --git a/lib/limiter/strategies/index.ts b/packages/core/lib/limiter/strategies/index.ts similarity index 100% rename from lib/limiter/strategies/index.ts rename to packages/core/lib/limiter/strategies/index.ts diff --git a/lib/limiter/strategies/slidingWindowCounter.ts b/packages/core/lib/limiter/strategies/slidingWindowCounter.ts similarity index 100% rename from lib/limiter/strategies/slidingWindowCounter.ts rename to packages/core/lib/limiter/strategies/slidingWindowCounter.ts diff --git a/lib/limiter/strategies/tokenBucket.ts b/packages/core/lib/limiter/strategies/tokenBucket.ts similarity index 100% rename from lib/limiter/strategies/tokenBucket.ts rename to packages/core/lib/limiter/strategies/tokenBucket.ts diff --git a/lib/limiter/strategies/windowCounter.ts b/packages/core/lib/limiter/strategies/windowCounter.ts similarity index 100% rename from lib/limiter/strategies/windowCounter.ts rename to packages/core/lib/limiter/strategies/windowCounter.ts