UNPKG

redis-sliding-rate-limiter

Version:

Flexible and performant rate limiter based on sliding window algorithm with arbitrary precision

70 lines (69 loc) 2.77 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; Object.defineProperty(exports, "__esModule", { value: true }); exports.IORedisStrategy = void 0; const Strategy_1 = require("./Strategy"); const lua_1 = require("../lua"); class IORedisStrategy extends Strategy_1.Strategy { sendCommand(cmd, ...args) { return __awaiter(this, void 0, void 0, function* () { return yield this.limiter.client.call(cmd, args); }); } loadScript() { return __awaiter(this, void 0, void 0, function* () { const args = [ 'LOAD', lua_1.LuaScript ]; return yield this.sendCommand('SCRIPT', ...args); }); } execScript(key) { return __awaiter(this, void 0, void 0, function* () { if (!this.scriptSha1) { this.scriptSha1 = yield this.loadScript(); } const args = [ this.scriptSha1, 1, // number of keys key, this.limiter.window, lua_1.MicrosecondsToWindowSubdivision[this.limiter.windowSubdivisionUnit], this.limiter.windowExpireMs, this.limiter.limit, this.limiter.limitOverhead ]; let res; try { res = yield this.sendCommand('EVALSHA', ...args); } catch (err) { // Script expired in Redis cache, reload and try again if (err && err.message && err.message.includes('NOSCRIPT')) { this.scriptSha1 = yield this.loadScript(); args[0] = this.scriptSha1; res = yield this.sendCommand('EVALSHA', ...args); } else { throw err; } } return { allowed: !!res[0], remaining: Math.max(0, res[1]), firstExpireAtMs: res[2], windowExpireAtMs: res[3] }; }); } } exports.IORedisStrategy = IORedisStrategy;