import { getLogger } from "./logger"; import { WrapperStatusMessage } from "server-manager-shared"; import { JsonFileStore } from "./persistence/jsonFileStore"; const logger = getLogger("WrapperRegistry"); export interface WrapperInfo { id:string; hostname:string; commandQueue:string; cpu:number; ram:number; ramFree:number; online:boolean; lastHeartbeat:number; servers: WrapperStatusMessage["servers"]; } interface WrapperRegistryState { wrappers: Array<{ id:string; hostname:string; commandQueue:string; cpu:number; ram:number; }>; } export class WrapperRegistry { private wrappers = new Map(); private readonly persistence = new JsonFileStore( "wrapperRegistry-state.json" ); async init(): Promise { const state = await this.persistence.load(); if (!state) return; for (const wrapperData of state.wrappers) { this.wrappers.set( wrapperData.id, { id: wrapperData.id, hostname: wrapperData.hostname, commandQueue: wrapperData.commandQueue, cpu: wrapperData.cpu, ram: wrapperData.ram, ramFree: wrapperData.ram, online: false, lastHeartbeat: 0, servers: [] } ); } } private toState(): WrapperRegistryState { return { wrappers: Array.from(this.wrappers.values()).map( wrapper => ({ id: wrapper.id, hostname: wrapper.hostname, commandQueue: wrapper.commandQueue, cpu: wrapper.cpu, ram: wrapper.ram }) ) }; } private async saveState(): Promise { await this.persistence.save( this.toState() ); } add(wrapper:WrapperInfo){ this.wrappers.set( wrapper.id, wrapper ); logger.info( "Wrapper added:", wrapper.id ); void this.saveState(); } get(id:string){ return this.wrappers.get(id); } getAll(){ return Array.from( this.wrappers.values() ); } updateHeartbeat(id:string){ const wrapper = this.wrappers.get(id); if(!wrapper) return; wrapper.lastHeartbeat = Date.now(); wrapper.online = true; } update(wrapper:WrapperInfo){ this.wrappers.set( wrapper.id, wrapper ); void this.saveState(); } checkOffline(timeout:number){ const now = Date.now(); for(const wrapper of this.wrappers.values()){ if( wrapper.online && now - wrapper.lastHeartbeat > timeout ){ wrapper.online = false; logger.warn( "Wrapper offline:", wrapper.id ); } } } updateStatus(data: WrapperStatusMessage){ const wrapper = this.wrappers.get( data.wrapperId ); if(!wrapper) return; wrapper.ramFree = data.ramFree; wrapper.servers = data.servers; wrapper.lastHeartbeat = Date.now(); wrapper.online = true; } }