import Globals from './globals'; import { ShouldNeverHappenError } from './data-types'; export default class ResourceRAMCache { static data = new Map(); // (serverId, resourceId) -> { resource, lastUsed } static size = 0; static putResource(serverId: string, resourceId: string, resourceBuff: Buffer): void { if (resourceBuff.length > Globals.MAX_RESOURCE_SIZE) { // skip resources if they would flood the cache return; } let id = `s#${serverId}/r#${resourceId}`; ResourceRAMCache.data.set(id, { resource: resourceBuff, lastUsed: new Date() }); ResourceRAMCache.size += resourceBuff.length; if (ResourceRAMCache.size > Globals.MAX_SERVER_RESOURCE_CACHE_SIZE) { // TODO: this feature needs to be tested let entries = Array.from(ResourceRAMCache.data.entries()) .map(([ key, value ]) => { return { id: key, value: value }; }) .sort((a, b) => b.value.lastUsed.getTime() - a.value.lastUsed.getTime()); // oldest last (for pop) while (ResourceRAMCache.size > Globals.MAX_SERVER_RESOURCE_CACHE_SIZE) { let entry = entries.pop(); if (entry === undefined) throw new ShouldNeverHappenError('No entry in the array but the ram cache still has a size...'); ResourceRAMCache.data.delete(entry.id); ResourceRAMCache.size -= entry.value.resource.length; } } } static getResource(serverId: string, resourceId: string): Buffer | null { let id = `s#${serverId}/r#${resourceId}`; let v = ResourceRAMCache.data.get(id); if (!v) return null; v.lastUsed = new Date(); return v.resource; } }