@daiso-tech/core
Version:
The library offers flexible, framework-agnostic solutions for modern web applications, built on adaptable components that integrate seamlessly with popular frameworks like Next Js.
113 lines (109 loc) • 4.48 kB
JavaScript
/**
* @module RateLimiter
*/
import {} from "ioredis";
import { BACKOFFS, resolveBackoffSettingsEnum, serializeBackoffSettingsEnum, } from "../../../../backoff-policies/implementations/_module.js";
import {} from "../../../../execution-context/contracts/_module.js";
import {} from "../../../../rate-limiter/contracts/_module.js";
import { rateLimiterFactoryLua } from "../../../../rate-limiter/implementations/adapters/redis-rate-limiter-adapter/lua/_module.js";
import { LIMITER_POLICIES, resolveRateLimiterPolicySettings, serializeRateLimiterPolicySettingsEnum, } from "../../../../rate-limiter/implementations/policies/_module.js";
import { TimeSpan } from "../../../../time-span/implementations/time-span.js";
/**
* IMPORT_PATH: `"@daiso-tech/core/rate-limiter/redis-rate-limiter-adapter"`
* @group Adapters
*/
export class RedisRateLimiterAdapter {
backoff;
policy;
database;
/**
* @example
* ```ts
* import { RedisRateLimiterAdapter } from "@daiso-tech/core/rate-limiter/redis-rate-limiter-adapter";
* import Redis from "ioredis";
*
* const database = new Redis("YOUR_REDIS_CONNECTION_STRING");
* const rateLimiterAdapter = new RedisRateLimiterAdapter({
* database
* });
* ```
*/
constructor(settings) {
const { database, backoffPolicy = {
type: BACKOFFS.EXPONENTIAL,
}, rateLimiterPolicy = {
type: LIMITER_POLICIES.FIXED_WINDOW,
}, } = settings;
this.database = database;
this.backoff = resolveBackoffSettingsEnum(backoffPolicy);
this.policy = resolveRateLimiterPolicySettings(rateLimiterPolicy);
this.initGetStateCommand();
this.initUpdateStateCommmand();
}
initGetStateCommand() {
if (typeof this.database.daiso_rate_limiter_get_state === "function") {
return;
}
this.database.defineCommand("daiso_rate_limiter_get_state", {
numberOfKeys: 1,
lua: `
${rateLimiterFactoryLua}
local key = KEYS[1];
local backoffSettings = cjson.decode(ARGV[1]);
local policySettings = cjson.decode(ARGV[2]);
local currentDate = tonumber(ARGV[3]);
local rateLimiter = rateLimiterFactory(backoffSettings, policySettings, currentDate)
local state = rateLimiter.getState(key)
return cjson.encode(state)
`,
});
}
initUpdateStateCommmand() {
if (typeof this.database.daiso_rate_limiter_update_state === "function") {
return;
}
this.database.defineCommand("daiso_rate_limiter_update_state", {
numberOfKeys: 1,
lua: `
${rateLimiterFactoryLua}
local key = KEYS[1];
local limit = tonumber(ARGV[1]);
local backoffSettings = cjson.decode(ARGV[2]);
local policySettings = cjson.decode(ARGV[3]);
local currentDate = tonumber(ARGV[4]);
local rateLimiter = rateLimiterFactory(backoffSettings, policySettings, currentDate)
local state = rateLimiter.updateState(key, limit)
return cjson.encode(state)
`,
});
}
async getState(_context, key) {
const json = await this.database.daiso_rate_limiter_get_state(key, JSON.stringify(serializeBackoffSettingsEnum(this.backoff)), JSON.stringify(serializeRateLimiterPolicySettingsEnum(this.policy)), Date.now());
const state = JSON.parse(json);
if (state === null) {
return null;
}
return {
success: state.success,
attempt: state.attempt,
resetTime: TimeSpan.fromDateRange({
end: new Date(state.resetTime),
}),
};
}
async updateState(_context, key, limit) {
const json = await this.database.daiso_rate_limiter_update_state(key, limit, JSON.stringify(serializeBackoffSettingsEnum(this.backoff)), JSON.stringify(serializeRateLimiterPolicySettingsEnum(this.policy)), Date.now());
const state = JSON.parse(json);
return {
success: state.success,
attempt: state.attempt,
resetTime: TimeSpan.fromDateRange({
end: new Date(state.resetTime),
}),
};
}
async reset(_context, key) {
await this.database.del(key);
}
}
//# sourceMappingURL=redis-rate-limiter-adapter.js.map