@canmertinyo/rate-limiter-memcached
Version:
A simple rate-limiting middleware for Express.js with support for in-memory, Redis, and MongoDB storage
120 lines (119 loc) • 5.2 kB
JavaScript
;
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());
});
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MemcachedStore = void 0;
const memcached_1 = __importDefault(require("memcached"));
const util_1 = require("util");
class MemcachedStore {
constructor(server, memcachedOptions) {
this.server = server;
this.memcachedOptions = memcachedOptions;
}
initialize() {
return __awaiter(this, void 0, void 0, function* () {
try {
this.memcached = new memcached_1.default(this.server, this.memcachedOptions);
}
catch (error) {
throw new Error("Failed to initialize Memcached.");
}
return this;
});
}
getRateLimitRecord(key) {
return __awaiter(this, void 0, void 0, function* () {
const getAsync = (0, util_1.promisify)(this.memcached.get).bind(this.memcached);
try {
const record = yield getAsync(key);
return record ? JSON.parse(record) : undefined;
}
catch (error) {
throw new Error("Error getting rate limit record.");
}
});
}
createRateLimitRecord(record) {
return __awaiter(this, void 0, void 0, function* () {
const createAsync = (0, util_1.promisify)(this.memcached.set).bind(this.memcached);
const getAsync = (0, util_1.promisify)(this.memcached.get).bind(this.memcached);
try {
const success = yield createAsync(record.key, JSON.stringify(record), 5000);
if (success) {
const storedRecord = yield getAsync(record.key);
if (storedRecord) {
return JSON.parse(storedRecord);
}
else {
throw new Error("Record not found.");
}
}
else {
throw new Error("Failed to create rate limit record.");
}
}
catch (error) {
throw new Error("Error creating rate limit record: " + error);
}
});
}
updateRateLimitRecord(key, timestamp, count) {
return __awaiter(this, void 0, void 0, function* () {
const getAsync = (0, util_1.promisify)(this.memcached.get).bind(this.memcached);
const setAsync = (0, util_1.promisify)(this.memcached.set).bind(this.memcached);
try {
const existingRecord = yield getAsync(key);
if (!existingRecord) {
throw new Error(`Record with key "${key}" not found.`);
}
const updatedRecord = Object.assign(Object.assign({}, JSON.parse(existingRecord)), { timestamp,
count });
const success = yield setAsync(key, JSON.stringify(updatedRecord), 5000);
if (success) {
return updatedRecord;
}
else {
throw new Error(`Failed to update record with key "${key}".`);
}
}
catch (error) {
throw new Error("Error updating the rate limit record.");
}
});
}
increment(key) {
return __awaiter(this, void 0, void 0, function* () {
const getAsync = (0, util_1.promisify)(this.memcached.get).bind(this.memcached);
const setAsync = (0, util_1.promisify)(this.memcached.set).bind(this.memcached);
try {
const recordJSON = yield getAsync(key);
if (!recordJSON) {
throw new Error("Record not found");
}
const record = JSON.parse(recordJSON);
const updatedRecord = Object.assign(Object.assign({}, record), { count: record.count + 1 });
const success = yield setAsync(key, JSON.stringify(updatedRecord), 5000);
if (success) {
return updatedRecord;
}
else {
throw new Error("Failed to update record");
}
}
catch (error) {
throw new Error("Failed to update record");
}
});
}
}
exports.MemcachedStore = MemcachedStore;