Supplement telemetry rosters with fresh RCON pings
This commit is contained in:
@@ -50,15 +50,27 @@ export function freshTelemetry(report: GameTelemetry | undefined, now: number, a
|
||||
export function selectServerObservation<T extends ServerObservation>(server: T, report: GameTelemetry | undefined, now: number): T {
|
||||
if (server.telemetry && (!report || Date.parse(server.telemetry.receivedAt) > Date.parse(report.receivedAt))) report = server.telemetry;
|
||||
const raw = server.rcon_status ?? server;
|
||||
const result: T = { ...server, ...raw, last_error: rconHealthError(raw), telemetry: report, status_source: raw.last_seen_at ? 'rcon' : null };
|
||||
const result: T = { ...server, ...raw, rcon_status: raw, last_error: rconHealthError(raw), telemetry: report, status_source: raw.last_seen_at ? 'rcon' : null };
|
||||
const containerUnknown = server.container_state === 'unknown';
|
||||
if (['provisioning','starting'].includes(server.health) || (server.container_state && server.container_state !== 'running' && !containerUnknown) || (!server.container_state && server.health === 'offline')) {
|
||||
return { ...result, health: server.health, last_error: null, last_players: null, roster: null, status_source: null };
|
||||
}
|
||||
const checked = server.container_checked_at ?? server.last_checked_at ?? raw.last_seen_at;
|
||||
const containerFresh = server.container_state === 'running' && freshStatusTimestamp(checked ?? null, now);
|
||||
const after = !server.telemetry_after || Date.parse(raw.last_seen_at ?? '') > Date.parse(server.telemetry_after);
|
||||
const fresh = after && freshStatusTimestamp(raw.last_seen_at, now) && !result.last_error;
|
||||
if (containerFresh && report?.server === server.name && freshTelemetry(report, now, server.telemetry_after)) {
|
||||
const players = report.players.length;
|
||||
// Telemetry owns roster membership. Supplement missing pings only with
|
||||
// unambiguous RCON identities from the current map and server lifecycle.
|
||||
const pings = new Map<string, number | null>();
|
||||
if (fresh && raw.last_map === report.map) {
|
||||
for (const player of raw.roster ?? []) {
|
||||
if (!player.guid) continue;
|
||||
const ping = player.ping;
|
||||
pings.set(player.guid, pings.has(player.guid) || ping === null || !Number.isSafeInteger(ping) || ping < 0 ? null : ping);
|
||||
}
|
||||
}
|
||||
// New reports carry persisted anchors through both SSE and HTTP. Keep
|
||||
// the fallback for telemetry saved before server timing was included.
|
||||
const timing = report.timing?.server ?? {
|
||||
@@ -70,14 +82,12 @@ export function selectServerObservation<T extends ServerObservation>(server: T,
|
||||
return { ...result, health: 'online', status_source: 'telemetry', last_players: players,
|
||||
last_map: report.map, last_seen_at: report.receivedAt, last_error: null,
|
||||
roster: report.players.map(player => ({ num: null, score: 'score' in player ? player.score : null,
|
||||
ping: player.ping ?? null, guid: player.guid, name: player.name })),
|
||||
ping: player.ping ?? pings.get(player.guid) ?? null, guid: player.guid, name: player.name })),
|
||||
active_since: players > 0 ? timing.activeSince : null,
|
||||
inactive_since: players === 0 ? timing.inactiveSince : null,
|
||||
game_started_at: players === 0 ? null : timing.gameStartedAt,
|
||||
game_ended_at: players === 0 ? null : timing.gameEndedAt };
|
||||
}
|
||||
const after = !server.telemetry_after || Date.parse(raw.last_seen_at ?? '') > Date.parse(server.telemetry_after);
|
||||
const fresh = after && freshStatusTimestamp(raw.last_seen_at, now) && !result.last_error;
|
||||
// A current authenticated RCON reply can establish game liveness when
|
||||
// inspection is unavailable, without claiming the container was inspected.
|
||||
const containerExpired = !containerUnknown && !!server.container_checked_at && !containerFresh;
|
||||
|
||||
Reference in New Issue
Block a user