7 Commits
Author SHA1 Message Date
手瓜一十雪 0f358b2ac2 fix(webui): stop idle polling and release background timers 2026-10-18 13:49:48 +08:00
手瓜一十雪 4e2b6b1200 refactor: use native async discovery and simplify shared state 2026-10-18 12:57:18 +08:00
DrSmoothl 7c0519f75f lint 2026-10-12 15:43:34 +08:00
DrSmoothl a67614fa09 feat(logging): complete runtime trace diagnostics
Complete byte-level diagnostics for network, upload, runtime lifecycle, authenticated write, and background operation paths.

Preserve streaming behavior, file-storage boundaries, and default log volume while making failures, retries, cancellation, and final outcomes independently diagnosable.

Add focused regression coverage for correlation, partial data, resource context ownership, and terminal-state accuracy.
2026-07-31 11:21:12 +08:00
DrSmoothl e5f256f4dc feat(webui): report account storage update progress
Surface account storage preparation and background history progress through the existing live connection status channel. Clearly distinguish unavailable accounts from accounts that remain fully usable during maintenance.

Show processed totals, completion percentage, estimated remaining time, and retry states in both the global notice and account overview. Preserve existing connection update filtering to avoid unnecessary refreshes.
2026-07-30 09:57:31 +08:00
DrSmoothl bae9f8edb0 fix(webui): connection-diff-loop compares ONLY level — strip detail timestamps
Adversarial review caught: HttpPostAdapter.describeStatus() embeds
HH:MM:SS in 'detail' (e.g. "上次推送 14:53:01"). Every webhook delivery
rotates that string every second under any active push — and the diff
loop's raw JSON.stringify compared everything, so it published on every
500ms tick under any non-idle webhook. Net effect: SSE pushed a full
connections frame at 2 Hz, exactly the polling the loop was meant to
replace, just on the push channel.

Add an optional pickComparable projector. server.ts caller passes one
that returns { uin, nickname, adapters[{ name, kind, status }] } — the
LEVEL only, not the live-rendered detail string. The SSE handler still
ships the FULL snapshot (including detail) to the WebUI; only the diff
key is pruned.

2 new tests pin the invariant: 10 detail-only ticks → ZERO publishes; a
real status-level transition publishes exactly once. Plus a throwing-
projector isolation test. 7/7 diff-loop tests green.
2026-06-24 22:55:51 +08:00
DrSmoothl a9f5f277f1 feat(core): connection-status diff loop — publish 'connections' on change
Phase 4b. OneBot adapters expose no event-emitter for connection-state edges
(listening / connected / client-count / last-delivery), so the SSE handler
can't subscribe — without this loop a connection change would only reach the
WebUI on the 30s REST reconcile fallback.

startConnectionDiffLoop polls getConnectionStatuses() at 500ms, compares
JSON-serialised snapshots, and publishes 'connections' through the StateBus
when (and only when) it actually moves. The first SUCCESSFUL observation is
treated as a baseline (no publish): the SSE handler's sendAllInitial has
already shipped the initial snapshot to every connected client on connect.
Snapshot exceptions are isolated — the loop retries on the next tick without
clobbering the baseline.

Started once per initWebUI lifetime; lives until process exit (consistent
with the other heartbeat-style intervals like the SSE 15s keepalives).

431/431 core suite green (5 new tests cover stable=silent, change=publish,
first-observation=baseline, dispose stops, snapshot-throw isolation).
2026-06-24 22:09:13 +08:00