@evolplus/evo-utils
Version:
Simple utilities solution.
106 lines (105 loc) • 3.83 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.DecayLimiter = exports.TimeBasedLimiter = void 0;
const cache_1 = require("./cache");
const queue_1 = require("./queue");
/**
* Class implementing a time-based rate limiter.
* Allows requests based on specified timeframes and their respective limits.
*/
class TimeBasedLimiter {
/**
* Creates an instance of the TimeBasedLimiter class with specified timeframes and limits.
*
* @param {TimeBasedLimiterConfig} config - The configuration mapping timeframes to their respective limits.
*/
constructor(config, capacity) {
this.timeframes = [];
this.limits = [];
for (const tf in config) {
this.timeframes.push(parseInt(tf));
this.limits.push(config[tf]);
}
this.queues = new cache_1.DecayCache(capacity);
}
/**
* Initializes the request queues for a specific key.
* Each key will have multiple queues, each corresponding to a specific timeframe and its limit.
*
* @private
* @returns {Dequeue<number>[]} An array of deques representing the request queues for the key.
*/
initKey() {
let queues = new Array(this.timeframes.length);
for (let i = 0; i < this.timeframes.length; i++) {
queues[i] = new queue_1.Dequeue(this.limits[i]);
}
return queues;
}
/**
* Makes a request within the rate limiter.
* Checks if the request is allowed based on the timeframes and their limits.
*
* @returns {boolean} True if the request is allowed, otherwise false.
*/
hit(key) {
let queues = this.queues.get(key);
if (!queues) {
queues = this.initKey();
this.queues.put(key, queues);
}
let now = Date.now();
for (let i = 0; i < this.timeframes.length; i++) {
let tf = this.timeframes[i], q = queues[i];
while (q.count() > 0) {
let ts = q.peekFirst();
if (ts && ts < now - tf) {
q.shift();
}
else {
break;
}
}
if (!q.add(now)) {
return false;
}
}
return true;
}
}
exports.TimeBasedLimiter = TimeBasedLimiter;
/**
* Class implementing a decay-based rate limiter.
* Limits requests based on a decay function over time.
*/
class DecayLimiter {
/**
* Creates an instance of the DecayLimiter class with specified configuration.
* Initializes the decay cache to manage the request scores and sets the half-life and limit properties.
*
* @param {number} capacity - The maximum capacity for the decay cache to store request scores.
* @param {number} halfLife - The time period (in milliseconds) over which the scores decay.
* @param {number} limit - The maximum score allowed for a request to be considered valid.
*/
constructor(capacity, halfLife, limit) {
this.decays = new cache_1.DecayCache(capacity, halfLife);
this.limit = limit;
}
/**
* Processes a request for a specific key within the rate limiter.
* The request's score decays over time and is adjusted based on subsequent requests.
* Checks if the request's score is below the set limit to determine if it's allowed.
*
* @param {string} key - The key for which the request is made.
* @returns {boolean} True if the request is allowed based on its decayed score, otherwise false.
*/
hit(key) {
let score = this.decays.hit(key);
if (!score) {
this.decays.put(key, 1);
score = 1;
}
return score <= this.limit;
}
}
exports.DecayLimiter = DecayLimiter;