126 lines
6.8 KiB
TypeScript
126 lines
6.8 KiB
TypeScript
import type { HostLibraryCache } from './game-files.js';
|
|
|
|
export type HostMode = 'active' | 'draining' | 'disabled';
|
|
export type HostReadiness = 'preparing' | 'needs-runtime' | 'needs-game-files' | 'ready' | 'degraded' | 'draining' | 'disabled' | 'deleting';
|
|
export type HostOperationState = 'pending' | 'accepted' | 'running' | 'completed' | 'failed' | 'unknown';
|
|
|
|
export function hostReadinessLabel(readiness: HostReadiness): string {
|
|
return { preparing: 'Preparing', 'needs-runtime': 'Needs runtime', 'needs-game-files': 'Needs game files',
|
|
ready: 'Ready', degraded: 'Degraded', draining: 'Draining', disabled: 'Disabled', deleting: 'Deleting' }[readiness];
|
|
}
|
|
|
|
export interface HostDeletion { allowed: boolean; blockers: string[] }
|
|
export interface HostDecommission {
|
|
operationId: string; stage: 'queued' | 'running' | 'cleaned' | 'failed' | 'completed';
|
|
requestedAt: string; updatedAt: string; error: string | null; retryable: boolean;
|
|
}
|
|
export function hostDeletionMessage(host: Pick<Host, 'connected' | 'decommission'>): string {
|
|
if (!host.decommission) return '';
|
|
switch (host.decommission.stage) {
|
|
case 'queued': return host.connected ? 'Host cleanup is queued.' : 'Waiting for the host to reconnect before removing its files and agent.';
|
|
case 'running': return 'Removing host files, cached game libraries, and the agent installation.';
|
|
case 'cleaned': return 'Host data is removed. Waiting for confirmation that the agent has uninstalled itself.';
|
|
case 'failed': return 'Cleanup needs attention. Complete removal has not been confirmed.';
|
|
case 'completed': return 'Host files and agent removal confirmed.';
|
|
}
|
|
}
|
|
|
|
export interface HostLibrary { id: string; state: 'missing' | 'downloading' | 'verifying' | 'ready' | 'failed' | 'outdated'; progress?: number; error?: string }
|
|
export interface HostAgentUpdate {
|
|
enabled: boolean;
|
|
state: 'current' | 'checking' | 'deferred' | 'updating' | 'updated' | 'failed';
|
|
currentVersion: string;
|
|
targetVersion?: string;
|
|
error?: string;
|
|
checkedAt?: string;
|
|
}
|
|
|
|
export function hostAgentUpdatesEnabled(inventory: HostInventory): boolean {
|
|
return inventory.agentUpdate?.enabled === true && inventory.capabilities?.includes('agent.update') === true;
|
|
}
|
|
|
|
export function hostAgentUpdateLabel(inventory: HostInventory): string {
|
|
if (!hostAgentUpdatesEnabled(inventory)) return 'Setup required';
|
|
const update = inventory.agentUpdate!;
|
|
if (update.state === 'current' && !update.checkedAt) return 'Awaiting first check';
|
|
return { current: 'Current', checking: 'Checking', deferred: 'Deferred',
|
|
updating: 'Updating', updated: 'Updated', failed: 'Needs attention' }[update.state];
|
|
}
|
|
|
|
export function hostAgentUpdateMessage(inventory: HostInventory): string {
|
|
if (!hostAgentUpdatesEnabled(inventory)) return 'Run the current installer once on this host to enable automatic agent updates.';
|
|
const update = inventory.agentUpdate!;
|
|
switch (update.state) {
|
|
case 'current': return update.checkedAt ? 'The last check found no newer compatible agent release.' : 'The host timer will check for a compatible agent release automatically.';
|
|
case 'checking': return 'The host is checking the controller release and verifying its download.';
|
|
case 'deferred': return 'The updater is waiting for the reported condition to clear. The host checks again automatically.';
|
|
case 'updating': return 'The host is replacing agent code and checking that the new process connects successfully.';
|
|
case 'updated': return 'The new agent connected successfully. Automatic checks continue.';
|
|
case 'failed': return 'The update did not complete successfully. Review the reported error before retrying setup.';
|
|
}
|
|
}
|
|
|
|
export interface HostInventory {
|
|
hostname?: string; agentVersion?: string; protocolVersion?: number; os?: string; architecture?: string;
|
|
cpu?: string; cpuCount?: number; cpuUsagePercent?: number; memoryTotal?: number; memoryAvailable?: number;
|
|
storageTotal?: number; storageAvailable?: number; dockerVersion?: string; dockerRunning?: boolean;
|
|
directoriesWritable?: boolean; runtimeImages?: string[]; libraries?: HostLibrary[];
|
|
currentOperation?: string | null; [key: string]: unknown;
|
|
capabilities?: string[];
|
|
agentUpdate?: HostAgentUpdate;
|
|
instanceResources?: InstanceResources[];
|
|
instanceResourcesError?: string;
|
|
}
|
|
export interface InstanceResources {
|
|
instanceId: string; generation: number; uptimeSeconds: number; cpuCores: number; memoryBytes: number;
|
|
}
|
|
export interface ResourceAllowance {
|
|
cpuCores: number; memoryBytes: number; source: 'host' | 'fleet' | 'bootstrap';
|
|
samples: number; observedAt: string | null;
|
|
}
|
|
export interface CapacityCalibration { running: ResourceAllowance; startup: ResourceAllowance }
|
|
export interface CapacitySample {
|
|
hostId: string; hostName: string | null; instanceId: string; server: string | null;
|
|
generation: number; phase: 'startup' | 'running'; timestamp: string; cpuCores: number; memoryBytes: number;
|
|
}
|
|
export interface CapacitySamplePage {
|
|
samples: CapacitySample[]; total: number; page: number; pageSize: number;
|
|
}
|
|
export interface Host {
|
|
id: string; name: string; hostname: string; mode: HostMode; portMin: number; portMax: number;
|
|
bindAddress: string; publicAddress: string; minimumFreeBytes: number; createdAt: string;
|
|
lastHeartbeat: string | null; connected: boolean; connectionState: 'online' | 'offline';
|
|
readiness: HostReadiness; readinessReasons: string[]; inventory: HostInventory;
|
|
enrolled: boolean; credentialActive: boolean;
|
|
decommission: HostDecommission | null;
|
|
preparation?: HostPreparation;
|
|
}
|
|
export interface HostOperation {
|
|
id: string; hostId: string; kind: string; instanceId: string | null; generation: number | null;
|
|
payload: Record<string, unknown>; state: HostOperationState; result: unknown; error: string | null;
|
|
createdAt: string; updatedAt: string;
|
|
}
|
|
|
|
export interface HostPreparationItem {
|
|
kind: 'runtime' | 'library'; label: string;
|
|
state: 'waiting' | 'preparing' | 'ready' | 'blocked'; detail: string;
|
|
operationId?: string; bytesDownloaded?: number; bytesTotal?: number;
|
|
cache?: HostLibraryCache;
|
|
}
|
|
export interface HostPreparation {
|
|
state: HostPreparationItem['state']; items: HostPreparationItem[];
|
|
}
|
|
|
|
export interface NativeDeploymentSelection {
|
|
libraryIds: Partial<Record<'t5' | 't6', string>>; image: string;
|
|
bindAddress?: string; publicAddress?: string; publicPort?: number;
|
|
}
|
|
|
|
/** The host/port are provisional until the creation command is submitted. */
|
|
export interface NativePlacement {
|
|
hostId: string; libraryId: string; image?: string;
|
|
bindAddress?: string; publicAddress?: string; publicPort?: number;
|
|
automatic?: boolean;
|
|
network?: { bindAddress?: string; publicAddress?: string; publicPort?: number };
|
|
}
|