import * as electronRemote from '@electron/remote'; const electronConsole = electronRemote.getGlobal('console') as Console; import Logger from '../../logger/logger'; const LOG = Logger.create(__filename, electronConsole); import Globals from './globals'; class ShouldNeverHappenError extends Error { constructor(...args: any[]) { super(...args); this.name = 'ShouldNeverHappenError'; } } 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 - a.value.lastUsed); // 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}`; if (!ResourceRAMCache._data.has(id)) { return null; } let v = ResourceRAMCache._data.get(id); v.lastUsed = new Date(); return v.resourceBuff; } } module.exports = ResourceRAMCache;