import { createLogger } from './logger'; import { Settings } from './settings'; const logger = createLogger('cache'); class CacheItem { constructor( public value: T, public lastAccessed: number, public ttl: number // Time-To-Live in milliseconds ) {} } export class Cache { private static instances: Map = new Map(); private cache: Map>; private maxSize: number; private constructor(maxSize: number) { this.cache = new Map>(); this.maxSize = maxSize; } /** * Get an instance of the cache with a specific name * @param name Unique identifier for this cache instance * @param maxSize Maximum size of the cache (only used when creating a new instance) */ public static getInstance( name: string, maxSize: number = Settings.MAX_CACHE_SIZE ): Cache { if (!this.instances.has(name)) { logger.debug(`Creating new cache instance: ${name}`); this.instances.set(name, new Cache(maxSize)); } return this.instances.get(name) as Cache; } stats(): string { return `Cache size: ${this.cache.size}`; } /** * Wrap a function with caching logic by immediately executing it with the provided arguments. * @param fn The function to wrap * @param key A unique key for caching * @param ttl Time-To-Live in seconds for the cached value * @param args The arguments to pass to the function */ wrap any>( fn: T, key: K, ttl: number, ...args: Parameters ): ReturnType { const cachedValue = this.get(key); if (cachedValue !== undefined) { return cachedValue as ReturnType; } const result = fn(...args); this.set(key, result, ttl); return result; } get(key: K): V | undefined { const item = this.cache.get(key); if (item) { const now = Date.now(); if (now - item.lastAccessed > item.ttl) { this.cache.delete(key); return undefined; } item.lastAccessed = now; return item.value; } return undefined; } set(key: K, value: V, ttl: number): void { if (this.cache.size >= this.maxSize) { this.evict(); } this.cache.set(key, new CacheItem(value, Date.now(), ttl * 1000)); } clear(): void { this.cache.clear(); } private evict(): void { let oldestKey: K | undefined; let oldestTime = Infinity; for (const [key, item] of this.cache.entries()) { if (item.lastAccessed < oldestTime) { oldestTime = item.lastAccessed; oldestKey = key; } } if (oldestKey !== undefined) { this.cache.delete(oldestKey); } } }