Commit Graph
3 Commits
Author SHA1 Message Date
agessaman 2a1c2f86d8 feat(web_viewer): rebuild Real-time as one tape of what the radio heard
Real-time was three equal panels (commands, packets, messages) that each scrolled on their own, couldn't be held still, and showed the same transmission up to three times. It's now one tape with one row per transmission: a packet, the channel message decrypted from it and a command it triggered share a row, joined by packet hash, and the bot's reply hangs under the command with how many times a repeater was heard echoing it. Those echoes fold into the reply instead of getting rows of their own, and a packet heard several times is one row with a count and every reception (SNR, RSSI, hops, path) when opened.

A receiver strip at the top says whether the bot is listening or the radio is offline or not responding (from the banner poll base.html already runs, now published as a banner-status event), when it last heard a packet, the packet rate and a 10-minute activity bar. The tape holds still while you read it: Pause (P), scrolling down, a moving mouse pointer or keyboard focus queue new rows behind an "N new" button. Rows can be kept (safe from the 300-row limit and from Clear), filtered to messages or commands, by packet type or channel, and searched (/). Replayed history sits under a "Heard before you opened this page" divider, and adverts and keyed group text are decoded in the browser and labeled as such. Each row's glyph chip carries its packet type's icon in the dashboard chart's color for that type; decoded messages get a stronger tint, and the bot's commands and replies are violet.

Server side, command rows carry trigger_packet_hash (from the message's routing info) and, once the transmission tracker matches a repeat, reply_packet_hash. Replayed rows carry stream_ts and replayed, and live rows stream_ts. Commands stored before this pair with their message only on an exact sender, channel and text match within 20 seconds.

Real-time is admin-only now: its socket already was, so anonymous visitors got three "Admin login required" badges over spinners that never filled. They're redirected to login and the nav link is hidden from them.

The byte breakdown sliced multibyte paths by hop count, so 2- and 3-byte hops spilled into the payload; it uses the path's byte count and shows the raw path-length byte. Route types 0 and 2 were swapped, and the channel key store was often built before the decoder had loaded, so it never decrypted anything. js-sha256 is vendored under static/vendor instead of loading from cdnjs.
2026-10-17 19:40:23 -07:00
agessaman 853f86d8a5 build(mypy): type-check the modules the refactor created, tracking included
Plan rule 3c said every module this refactor creates is type-checked from its first commit; web_viewer/tracking.py was on the ignore list because it moved out of app.py with app's existing errors, and mypy skipped the bodies of untyped helpers in all the new modules. tracking.py is off the ignore list, and the 30 new modules get check_untyped_defs. The 25 errors that surfaced were all missing annotations: container annotations (paths_by_key, tracking, server_stats, result, daily_by_role, feed params), casts for page/page_size where pagination guarantees ints, FeedSubscriptionsMixin's two host attributes, and an ignore for Flask-SocketIO's request.sid. No runtime change.
2026-10-03 22:45:42 -07:00
agessaman acbe6f3c34 refactor(web_viewer): move the Socket.IO client handlers into SocketClientsMixin
_setup_socketio_handlers, _mark_subscribed, _replay_packet_stream, _disconnect_login_sockets and _cleanup_stale_clients move verbatim to modules/web_viewer/socket_clients.py (AST-identical; the other 25 BotDataViewer methods are unchanged). app.py keeps importing disconnect and emit so modules.web_viewer.app.disconnect and .emit still resolve; as with the earlier mixins, patching those names on app no longer reaches the moved handlers. app.py is 4,868 lines.
2026-10-03 21:14:00 -07:00