Always show RCON reply on server detail — raw dump + parsed values
Player count says 1 but roster shows 0 for t5_ascension_1 — a parser
mismatch (likely Plutonium's status body uses Steam IDs instead of the
16+ char hex GUIDs my roster regex expects). To diagnose these without
guessing, always keep the raw RCON reply around and expose it on the
detail page.
rconStatusResult now includes rawReply on success too (used to only
persist it on bad-reply). Worker + probe-rcon endpoint persist it to
last_reply_snippet on every tick, so the byte-level truth about the
reply survives page loads.
New "RCON reply" panel on the detail page (visible whenever we have a
snippet or an endpoint) shows:
- Probe RCON button (was buried inside the offline-only diagnostic
panel; now accessible when healthy too)
- Parsed values in a grid: endpoint, players, map, gametype, roster
row count, last seen — so mismatches between "what the parser
extracted" and "what the reply actually said" are one glance apart
- Raw hex+ASCII dump of the last reply so the operator can read
literal player rows and see why the roster parser gave 0
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -249,7 +249,14 @@ export interface RconStatus {
|
||||
}
|
||||
|
||||
export type RconStatusResult =
|
||||
| { ok: true; endpoint: RconEndpoint; status: RconStatus }
|
||||
| {
|
||||
ok: true;
|
||||
endpoint: RconEndpoint;
|
||||
status: RconStatus;
|
||||
// Kept on success too, so operators can compare "what we parsed"
|
||||
// vs "what the server actually sent" from the detail page.
|
||||
rawReply: string;
|
||||
}
|
||||
| {
|
||||
ok: false;
|
||||
endpoint: RconEndpoint | null;
|
||||
@@ -366,6 +373,7 @@ export async function rconStatusResult(server: string): Promise<RconStatusResult
|
||||
map: info.mapname ?? info.sv_mapname ?? header.map ?? header.mapname ?? header.sv_mapname ?? null,
|
||||
gametype: info.g_gametype ?? header.g_gametype ?? header.gametype ?? null,
|
||||
roster: parsePlayerRoster(text)
|
||||
}
|
||||
},
|
||||
rawReply: formatRawReply(send.buf)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ async function fanoutStatus(): Promise<void> {
|
||||
setServerField(srv.name, 'last_seen_at', now);
|
||||
setServerField(srv.name, 'last_checked_at', now);
|
||||
setServerField(srv.name, 'last_error', null);
|
||||
setServerField(srv.name, 'last_reply_snippet', null);
|
||||
setServerField(srv.name, 'last_reply_snippet', result.rawReply);
|
||||
entries[i] = {
|
||||
server: srv.name,
|
||||
players: result.status.players,
|
||||
@@ -75,7 +75,7 @@ async function fanoutStatus(): Promise<void> {
|
||||
lastError: null,
|
||||
endpoint: result.endpoint,
|
||||
reason: null,
|
||||
replySnippet: null
|
||||
replySnippet: result.rawReply
|
||||
};
|
||||
} else {
|
||||
// RCON unreachable — leave last_seen_at alone (health decays
|
||||
|
||||
Reference in New Issue
Block a user