- Tighten transport announce rate limit from 5/sec to 2/sec
- Reduce RNS loop frequency from 200Hz to 100Hz
- Throttle LVGL rendering to 30 FPS (was unthrottled)
- Time-box TCP frame loop to 3 frames / 8ms per client
- Add 12ms global TCP budget across all clients
- Replace blocking WiFi announce delay(1500) with deferred non-blocking check
- Rotate persistData() across 3 cycles to spread file I/O
- Reduce LvNodesScreen rebuild frequency (2s → 5s, skip small transient changes)
- Bump version to 1.5.9
Guard AnnounceManager::received_announce() against null Identity
objects — Identity::recall() can fail when known_destinations table
is full and cull removes the entry. Also removes dead-code
needs_transport_headers() override from TCPClientInterface.
- TCPClientInterface overrides needs_transport_headers() so hops==1
packets get HEADER_2 wrapping through the hub
- Track savedCounter in LXMFMessage and use direct filename lookup
for status updates, fixing LoRa uptime-timestamp precision loss
that caused SENT status to revert to QUEUED on reload
- Remove timestamp-based re-sort in loadConversation() which broke
chronological order when mixing LoRa (uptime) and TCP (epoch)
timestamps; counter-based filenames already provide correct order
4-layer defense against 100+ node announce storms from rns.ratspeak.org:
- Transport-level rate limiter (5/sec) via filter_packet callback, before Ed25519 verify
- TCP frame processing time-boxed to 15ms per loop iteration
- Global announce rate limit (3/sec) in AnnounceManager
- UI rebuild throttled to once per 2 seconds
Also fixes message status not persisting to disk on queue drain.