import { logger } from "@utils/logger"; import { ApiClientConfig } from "@utils/types"; export class RateLimiter { private maxRequests: number; private perMilliseconds: number; private requestTimestamps: number[] = []; constructor(config: ApiClientConfig) { this.maxRequests = config.rateLimit.maxRequests; this.perMilliseconds = config.rateLimit.perMilliseconds; logger.log( `RateLimiter initialized: ${this.maxRequests} requests per ${this.perMilliseconds}ms.` ); } private cleanupTimestamps(): void { const windowStartTime = Date.now() - this.perMilliseconds; this.requestTimestamps = this.requestTimestamps.filter( (timestamp) => timestamp >= windowStartTime ); } /** * Checks if the rate limit has been hit and calculates the required delay. * @returns {number} The delay in milliseconds required before the next request can fire. * Returns 0 if no delay is needed. */ public checkLimitAndGetDelay(): number { this.cleanupTimestamps(); // 👈 Cleanup karna zaroori hai const currentRequestCount = this.requestTimestamps.length; if (currentRequestCount < this.maxRequests) { return 0; } const oldestTimestamp = this.requestTimestamps[0]; if (oldestTimestamp === undefined) { return 0; } const windowEndTime = oldestTimestamp + this.perMilliseconds; const requiredDelay = windowEndTime - Date.now(); const delay = Math.max(0, requiredDelay); logger.warn( `Rate limit hit! Current count: ${currentRequestCount}. Delaying next request for ${delay}ms.` ); return delay; } public recordRequestStart(): void { this.cleanupTimestamps(); this.requestTimestamps.push(Date.now()); logger.log( `Request recorded. Current window count: ${this.requestTimestamps.length}/${this.maxRequests}` ); } }