Skip to content

merge develop into developmod - #2

Merged
ReuschelCGN merged 9 commits into
developmodfrom
develop
Jun 29, 2026
Merged

merge develop into developmod#2
ReuschelCGN merged 9 commits into
developmodfrom
develop

Conversation

@ReuschelCGN

Copy link
Copy Markdown
Owner

No description provided.

comstud and others added 9 commits June 27, 2026 07:35
Adds a read-timeout-by-ping mechanism to all of the websocket
connections, with configurable ping interval and pong timeout.

- Add 'ping_interval' and 'pong_wait' to device_listener and controller_listener
  config sections, with defaults (30s/30s) and validation. These are
  reloadable. Ping interval is how often to send a ping and pong_wait
  is the grace period added to interval for waiting for a pong. Read timeout is
  effectively ping interval + grace period.
- Add 'registration_timeout' (duration, default 1m) to controller listener
  config section. This is reloadable.  Used as the read deadline bounding the
  controller registration handshake, then reset to the normal ping-based
  timeout before the ping loop starts. Covers both v1 and v2 registration paths.
- Expose device_listener/controller_listener ping settings (ping_interval,
  pong_wait, registration_timeout) via GET /api/config.
- Update example config and API docs.
It's rotom-ng.toml, not rotom.toml
Global stats weren't accurate because they just added worker stats
and workers come and go.
A CLI that connects simulated devices, workers, and controllers to a
running RotomNG instance over the real WebSocket wire protocol, so the
API and UI populate with live data instead of mocks.

- Devices answer control commands; workers send a welcome message and
  echo SUCCESS responses; controllers register (v2), log in on their
  assigned worker, and send periodic RPC requests, forming the full
  controller -> rotom -> worker -> rotom -> controller pipeline.
- CLI flags for device/worker/controller counts, endpoints, secrets,
  RPC interval, weight, etc. Validates controllers <= devices*workers
  when this connector supplies the workers.
- Connections self-heal/reconnect; graceful shutdown on SIGINT/SIGTERM.
- "gen-compose" subcommand writes a docker-compose.yml (rotom-ng built
  with DEV_MODE, a Vite dev-server sidecar for live UI from source, and
  the fleet) plus a matching dev config.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The device and controller handlers got ping-based read timeouts in
d268b27, but the worker handler was missed, so a silent or hung MITM
worker would hold its connection open indefinitely.

Apply the same managed-ping-loop pattern to the worker handler:

- Add WorkerHandlerSettings (ping_interval, pong_wait) with validation
  and a settings container, sourced from the device listener config
  since workers connect on the device listener. These are reloadable.
- Install the read deadline and pong handler synchronously before the
  welcome handshake, then start the managed ping loop once registration
  succeeds (restarts on settings reload, exits on context cancel).
- Wire worker handler settings through app Init and reload.
- Note in docs/example config that the device_listener ping settings
  also govern worker connections.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Previously LastSeenAt only advanced on data messages (or sends), so a
connection kept alive purely by ping/pong showed a stale last-seen
timestamp. And even where the backend had it, the API only exposed
last_seen_at_ms on devices/workers, while the UI ignored it entirely and
recomputed "Last Seen" client-side from message timestamps. This affected
all websocket connection types (devices, controllers, workers).

ws stats:
- Add ConnStats.LastPongAt, recorded by a new setPongReceived helper, and
  factor it into LastSeenAt(). Tracked separately from LastReceivedAt so
  pongs do not inflate the data-message counters.
- Have the pong handler installed by EnableReadTimeout record the pong
  under statsMu. The handler runs on the read goroutine inside NextReader,
  which does not hold statsMu, so locking there is safe and keeps GetStats
  consistent.
- ConnStats.Add now keeps the latest of each timestamp (via After) for all
  time fields rather than blindly overwriting, so a merge can never move a
  timestamp backward. A zero other still never clobbers an existing value.

api:
- Move LastSeenAtMs into CommonStats, populated from ws LastSeenAt(), so
  every connection type that embeds CommonStats (device, worker,
  controller, and the device/worker sessions) returns last_seen_at_ms.
  Remove the now-redundant per-struct LastSeenAtMs from Device and Worker.

base-ui:
- Use the API's last_seen_at_ms for the "Last Seen" column in the workers,
  controllers, and devices tables and in device-details, and sort by it
  directly. Drop the synthetic per-row last_seen fields and the now-unused
  getLastSeenTimestamp helper.
- Mirror the type change (last_seen_at_ms on CommonStats) in the runtime
  and mock types, and populate it in controller and session mock data.

Tests:
- Unit tests for setPongReceived/Add/LastSeenAt and an end-to-end test that
  a received pong advances LastSeenAt without changing message counts.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@ReuschelCGN
ReuschelCGN merged commit 42964c3 into developmod Jun 29, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants