Aethel Bot OSS repository! aethel.xyz
bot fun ai discord discord-bot aethel
at dev 3.3 kB view raw
1import logger from './logger'; 2interface MemoryManagerOptions { 3 maxSize?: number; 4 cleanupInterval?: number; 5 maxAge?: number; 6} 7 8class MemoryManager<K, V> { 9 private map = new Map<K, V & { timestamp: number }>(); 10 private maxSize: number; 11 private maxAge: number; 12 private cleanupTimer?: NodeJS.Timeout; 13 14 constructor(options: MemoryManagerOptions = {}) { 15 this.maxSize = options.maxSize || 1000; 16 this.maxAge = options.maxAge || 24 * 60 * 60 * 1000; 17 18 if (options.cleanupInterval) { 19 this.startCleanupTimer(options.cleanupInterval); 20 } 21 } 22 23 set(key: K, value: V): void { 24 if (this.map.size >= this.maxSize) { 25 const oldestKey = this.map.keys().next().value; 26 if (oldestKey !== undefined) { 27 this.map.delete(oldestKey); 28 } 29 } 30 31 const wrappedValue = Array.isArray(value) 32 ? Object.assign([...value], { timestamp: Date.now() }) 33 : { ...value, timestamp: Date.now() }; 34 this.map.set(key, wrappedValue as V & { timestamp: number }); 35 } 36 37 get(key: K): V | undefined { 38 const entry = this.map.get(key); 39 if (!entry) return undefined; 40 41 if (Date.now() - entry.timestamp > this.maxAge) { 42 this.map.delete(key); 43 return undefined; 44 } 45 46 if (Array.isArray(entry)) { 47 const result = [...entry]; 48 delete (result as unknown as Record<string, unknown>).timestamp; 49 return result as V; 50 } 51 const { timestamp: _timestamp, ...valueWithoutTimestamp } = entry; 52 return valueWithoutTimestamp as V; 53 } 54 55 delete(key: K): boolean { 56 return this.map.delete(key); 57 } 58 59 has(key: K): boolean { 60 const entry = this.map.get(key); 61 if (!entry) return false; 62 63 if (Date.now() - entry.timestamp > this.maxAge) { 64 this.map.delete(key); 65 return false; 66 } 67 68 return true; 69 } 70 71 clear(): void { 72 this.map.clear(); 73 } 74 75 size(): number { 76 return this.map.size; 77 } 78 79 entries(): IterableIterator<[K, V]> { 80 const entries: [K, V][] = []; 81 for (const [key, value] of this.map.entries()) { 82 if (Date.now() - value.timestamp <= this.maxAge) { 83 if (Array.isArray(value)) { 84 const result = [...value]; 85 delete (result as unknown as Record<string, unknown>).timestamp; 86 entries.push([key, result as V]); 87 } else { 88 const { timestamp: _timestamp, ...valueWithoutTimestamp } = value; 89 entries.push([key, valueWithoutTimestamp as V]); 90 } 91 } 92 } 93 return entries[Symbol.iterator](); 94 } 95 96 cleanup(): number { 97 const now = Date.now(); 98 let removedCount = 0; 99 100 for (const [key, value] of this.map.entries()) { 101 if (now - value.timestamp > this.maxAge) { 102 this.map.delete(key); 103 removedCount++; 104 } 105 } 106 107 if (removedCount > 0) { 108 logger.debug(`Memory cleanup: removed ${removedCount} expired entries`); 109 } 110 111 return removedCount; 112 } 113 114 private startCleanupTimer(interval: number): void { 115 this.cleanupTimer = setInterval(() => { 116 this.cleanup(); 117 }, interval); 118 } 119 120 destroy(): void { 121 if (this.cleanupTimer) { 122 clearInterval(this.cleanupTimer); 123 } 124 this.clear(); 125 } 126} 127 128export function createMemoryManager<K, V>(options?: MemoryManagerOptions): MemoryManager<K, V> { 129 return new MemoryManager<K, V>(options); 130} 131 132export { MemoryManager };