Surface raw RCON reply bytes + Probe RCON button

"unparseable reply (34 bytes)" told us Plutonium answered but hid the
actual bytes, forcing another guess-and-check round. rconStatusResult
now emits a formatRawReply() hex + ASCII dump of the raw UDP payload on
every bad-reply, persisted in a new last_reply_snippet column so it
survives page loads.

Wrong-password detection widens beyond the "bad rcon" phrasing to
"(bad|invalid|wrong)…(rcon|password|pass)"; print-body replies that
don't match get their first non-header line surfaced verbatim so at
least *some* server-supplied text reaches the UI.

Probe RCON button (POST /api/servers/[name]/probe-rcon) fires the same
code path as the periodic sweep on demand, cuts the RCON iteration loop
from 30s per attempt to sub-second, and refreshes the header/roster/
health when it succeeds. Snippet <details> auto-opens on bad-reply so
the bytes are one glance away.

migrateServers() picks up the new column automatically via the
introspection path added last commit.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
2026-09-12 11:12:50 -04:00
co-authored by Claude Opus 4.7
parent a5b9733bd0
commit 8affb11b57
11 changed files with 207 additions and 18 deletions
+2 -1
View File
@@ -24,7 +24,8 @@ const SERVERS_COLUMNS: Array<{ name: string; ddl: string }> = [
{ name: 'last_gametype', ddl: 'ALTER TABLE servers ADD COLUMN last_gametype TEXT' },
{ name: 'last_roster', ddl: 'ALTER TABLE servers ADD COLUMN last_roster TEXT' },
{ name: 'last_seen_at', ddl: 'ALTER TABLE servers ADD COLUMN last_seen_at TEXT' },
{ name: 'last_error', ddl: 'ALTER TABLE servers ADD COLUMN last_error TEXT' }
{ name: 'last_error', ddl: 'ALTER TABLE servers ADD COLUMN last_error TEXT' },
{ name: 'last_reply_snippet', ddl: 'ALTER TABLE servers ADD COLUMN last_reply_snippet TEXT' }
];
function migrateServers(handle: Database.Database): void {
+1
View File
@@ -18,6 +18,7 @@ CREATE TABLE IF NOT EXISTS servers (
last_roster TEXT, -- JSON array of RconPlayer
last_seen_at TEXT, -- ISO ts of last successful RCON reply
last_error TEXT, -- last RCON failure reason (cleared on success)
last_reply_snippet TEXT, -- hex+ASCII of last bad-reply UDP payload
created_at TEXT NOT NULL DEFAULT (strftime('%Y-%m-%dT%H:%M:%fZ','now'))
);