38 lines
2.2 KiB
TypeScript
38 lines
2.2 KiB
TypeScript
import { ONLINE_MAX_MS } from '../../server-freshness.js';
|
|
import { monitoringIdentity } from '../fleet/health-observations.js';
|
|
import { getServer, setServerFields, type ServerRow } from '../fleet/servers.js';
|
|
import { latestGameSubmission, telemetryReport, type VerifiedGameStatus } from '../fleet/status-evidence.js';
|
|
import { serverObservation } from '../fleet/status.js';
|
|
import { activityFields, successfulStatusFields } from '../fleet/status-updates.js';
|
|
|
|
/** Called inside the completion transaction; evidence must still describe this process. */
|
|
export function handoffVerifiedHealth(server: string, identity: string,
|
|
container: { state: string; observedAt: string }, game: VerifiedGameStatus): boolean {
|
|
const current = getServer(server);
|
|
if (!current || current.desired_state !== 'running' || monitoringIdentity(server) !== identity) return false;
|
|
const fresh = (at: string) => {
|
|
const age = Date.now() - Date.parse(at);
|
|
return age >= 0 && age <= ONLINE_MAX_MS;
|
|
};
|
|
const gameAt = game.source === 'telemetry' ? game.receivedAt : game.observedAt;
|
|
const submission = latestGameSubmission(server);
|
|
if (!fresh(container.observedAt) || !fresh(gameAt) || (submission && gameAt <= submission)) return false;
|
|
|
|
const updates: Partial<ServerRow> = {};
|
|
if (!current.container_checked_at || current.container_checked_at <= container.observedAt) {
|
|
updates.container_state = container.state;
|
|
updates.container_checked_at = container.observedAt;
|
|
}
|
|
if (game.source === 'rcon' && (!current.last_checked_at || current.last_checked_at <= game.observedAt)) {
|
|
Object.assign(updates, successfulStatusFields(game.rcon, game.observedAt));
|
|
}
|
|
const candidate = { ...current, ...updates };
|
|
// Evaluate the health readers will see after the operation and recovery slot
|
|
// complete. Newer contradictory evidence must keep verification pending.
|
|
const status = serverObservation(candidate, { provisioning: false, settling: false,
|
|
submission, telemetry: telemetryReport(server) });
|
|
if (status.health !== 'online') return false;
|
|
setServerFields(server, { ...updates, ...activityFields(candidate, status) });
|
|
return true;
|
|
}
|