import { GetConfiguration } from '@nitrots/nitro-renderer'; import { getAccessToken } from '../auth'; export interface EmuStatsOverview { uptimeSeconds: number; lastRefreshEpochMs: number; guiStatus: string; memoryUsedMb: number; memoryMaxMb: number; memoryAllocatedMb: number; memoryUsagePercent: number; cpuLoadPercent: number; activeOsThreads: number; connectedPlayers: number; loadedRooms: number; wiredTickables: number; peakPlayers: number; activeWebSocketSessions: number; peakWebSocketSessions: number; averageRoomCycleMs: number; worstRoomCycleMs: number; worstRoomCycleRoomId: number; worstRoomCycleRoomName: string; delayedEventsPending: number; overloadedWiredRooms: number; heavyWiredRooms: number; wiredActivityPerSecond: number; } export interface EmuStatsMemoryPoint { timestamp: number; usedMb: number; maxMb: number; usagePercent: number; } export interface EmuStatsUserRow { id: number; username: string; rank: string; credits: number; roomId: number; } export interface EmuStatsRoomRow { roomId: number; name: string; players: number; items: number; tickables: number; cpuMs: number; estimatedRamKb: number; thread: string; } export interface EmuStatsWiredRow { roomId: number; averageTickMs: number; peakTickMs: number; usagePercent: number; delayedEventsPending: number; overloaded: boolean; heavy: boolean; } export interface EmuStatsWiredTopRoomRow { roomId: number; name: string; usagePercent: number; averageTickMs: number; peakTickMs: number; delayedEventsPending: number; activityPerSecond: number; heavy: boolean; } export interface EmuStatsDatabasePool { activeConnections: number; idleConnections: number; totalConnections: number; waitingThreads: number; maxConnections: number; } export interface EmuStatsScheduler { queuedTasks: number; activeThreads: number; poolSize: number; completedTasks: number; running: boolean; } export interface EmuStatsNetwork { incomingPacketsPerSecond: number; outgoingPacketsPerSecond: number; incomingKilobytesPerSecond: number; outgoingKilobytesPerSecond: number; totalIncomingPackets: number; totalOutgoingPackets: number; } export interface EmuStatsGarbageCollector { totalCollections: number; totalCollectionTimeMs: number; collectionsSinceLastSample: number; lastObservedPauseMs: number; sampledAtEpochMs: number; } export interface EmuStatsSnapshot { overview: EmuStatsOverview; memoryHistory: EmuStatsMemoryPoint[]; users: EmuStatsUserRow[]; rooms: EmuStatsRoomRow[]; wired: EmuStatsWiredRow[]; wiredTopRooms: EmuStatsWiredTopRoomRow[]; databasePool: EmuStatsDatabasePool; scheduler: EmuStatsScheduler; network: EmuStatsNetwork; garbageCollector: EmuStatsGarbageCollector; } const interpolate = (value: string): string => { try { return GetConfiguration().interpolate(value); } catch { return value; } }; const getUrl = (): string => { const configured = GetConfiguration().getValue('emustats.endpoint', '${api.url}/api/emustats'); return interpolate(configured); }; const buildHeaders = (): Record => { const headers: Record = { Accept: 'application/json', 'X-Requested-With': 'NitroEmuStats' }; const token = getAccessToken(); if(token) headers.Authorization = `Bearer ${ token }`; return headers; }; let cacheValue: EmuStatsSnapshot = null; const parseJson = async (response: Response): Promise => { const text = await response.text(); if(!text) return {} as T; try { return JSON.parse(text) as T; } catch { throw new Error('Invalid emulator stats response.'); } }; export const fetchEmuStats = async (force = false): Promise => { if(!force && cacheValue) return cacheValue; const response = await fetch(getUrl(), { method: 'GET', credentials: 'include', headers: buildHeaders() }); const payload = await parseJson(response); if(!response.ok) { throw new Error(payload?.error || `Request failed (${ response.status }).`); } cacheValue = payload; return payload; }; export const getCachedEmuStats = (): EmuStatsSnapshot => { return cacheValue; };