UNPKG

hypershield

Version:

Middleware suite for high-performance and resilient APIs

167 lines 6.44 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.MemoryCache = void 0; const compressionService_1 = require("../../domains/compression/application/compressionService"); class MemoryCache { constructor(options = {}) { this.cache = new Map(); this.currentSize = 0; this.compression = new compressionService_1.CompressionService(); this.options = Object.assign({ compression: true, maxItems: 1000, maxMemorySize: 100 * 1024 * 1024, pruneInterval: 60000, ttl: 3600, maxSize: 1024 * 1024 }, options); this.startPruneInterval(); } startPruneInterval() { this.pruneIntervalId = setInterval(() => this.prune(), this.options.pruneInterval); this.pruneIntervalId.unref(); } cleanup() { if (this.pruneIntervalId) { clearInterval(this.pruneIntervalId); this.pruneIntervalId = undefined; } } prune() { return __awaiter(this, void 0, void 0, function* () { const now = Date.now(); let deletedSize = 0; for (const [key, entry] of this.cache.entries()) { if (this.isExpired(entry, now)) { deletedSize += entry.size; this.cache.delete(key); } } this.currentSize -= deletedSize; if (this.cache.size > this.options.maxItems || this.currentSize > this.options.maxMemorySize) { this.pruneLRU(); } }); } pruneLRU() { const entries = Array.from(this.cache.entries()) .sort((a, b) => a[1].lastAccessed - b[1].lastAccessed); while (this.cache.size > this.options.maxItems || this.currentSize > this.options.maxMemorySize) { const [key, entry] = entries.shift(); this.currentSize -= entry.size; this.cache.delete(key); } } isExpired(entry, now) { return entry.expiresAt !== undefined && entry.expiresAt <= now; } calculateSize(value) { const str = JSON.stringify(value); return Buffer.byteLength(str, 'utf8'); } get(key) { return __awaiter(this, void 0, void 0, function* () { const entry = this.cache.get(key); if (!entry) return null; if (this.isExpired(entry, Date.now())) { this.cache.delete(key); this.currentSize -= entry.size; return null; } entry.lastAccessed = Date.now(); this.cache.set(key, entry); try { if (this.options.compression && Buffer.isBuffer(entry.value)) { const decompressed = yield this.compression.decompress(entry.value); return JSON.parse(decompressed.toString()); } return entry.value; } catch (error) { console.error('Cache decompression error:', error); return null; } }); } set(key, value, ttl) { return __awaiter(this, void 0, void 0, function* () { const size = this.calculateSize(value); let valueToStore = value; if (this.options.compression) { valueToStore = yield this.compression.compress(JSON.stringify(value)); } const entry = { value: valueToStore, size, expiresAt: ttl ? Date.now() + ttl * 1000 : Date.now() + this.options.ttl * 1000, lastAccessed: Date.now() }; this.cache.set(key, entry); this.currentSize += size; if (this.cache.size > this.options.maxItems || this.currentSize > this.options.maxMemorySize) { yield this.prune(); } }); } delete(key) { return __awaiter(this, void 0, void 0, function* () { const entry = this.cache.get(key); if (entry) { this.currentSize -= entry.size; this.cache.delete(key); } }); } clear() { return __awaiter(this, void 0, void 0, function* () { this.cache.clear(); this.currentSize = 0; }); } mget(keys) { return __awaiter(this, void 0, void 0, function* () { return Promise.all(keys.map(key => this.get(key))); }); } exists(key) { return __awaiter(this, void 0, void 0, function* () { const entry = this.cache.get(key); if (!entry) return false; if (this.isExpired(entry, Date.now())) { this.cache.delete(key); this.currentSize -= entry.size; return false; } return true; }); } updateTTL(key, ttl) { return __awaiter(this, void 0, void 0, function* () { const entry = this.cache.get(key); if (!entry) return false; entry.expiresAt = Date.now() + ttl * 1000; entry.lastAccessed = Date.now(); this.cache.set(key, entry); return true; }); } getTTL(key) { return __awaiter(this, void 0, void 0, function* () { const entry = this.cache.get(key); if (!(entry === null || entry === void 0 ? void 0 : entry.expiresAt)) return null; const ttl = Math.ceil((entry.expiresAt - Date.now()) / 1000); return ttl > 0 ? ttl : null; }); } } exports.MemoryCache = MemoryCache; //# sourceMappingURL=memory.js.map