Add UDP discovery and heartbeat-miss notices to remchild

This commit is contained in:
Fisto
2026-09-22 19:31:19 +02:00
parent a7ab2a22f7
commit e38d7d07a2
4 changed files with 278 additions and 22 deletions
+23 -3
View File
@@ -51,6 +51,11 @@ The client sends `heartbeat` on this schedule after boot:
The server keeps three states from `lastSeen`:
If the server misses a heartbeat during the fast phases (10 s or 30 s; roughly the first six
minutes), it sends the client a `notice` with the miss count. The client prints it as a warning.
Nothing else changes: it is information for the user, not a reconnect trigger. The steady 5 minute
phase relies on the stale and gone states instead.
| State | Age | Effect |
| --- | --- | --- |
| `active` | under 12 min | Jobs and commands may be sent |
@@ -59,10 +64,22 @@ The server keeps three states from `lastSeen`:
First and last seen are kept in memory and written to `clients.jsonl`. `SIGINT` prints the table.
## Discovery
The server answers probes and beacons on UDP 8798 (`--discovery-port`, `--beacon-ms`, 0 disables
the beacon). Probes go to the subnet broadcast and to loopback; the server replies unicast, so the
client reads the address from the reply. Beacons carry `{type, name, port, id}` and go to every
interface's broadcast address, for passive listeners.
`remchild` with no `--server` spends five seconds probing. One server connects automatically,
several show a pick list, none falls back to the typed `host:port` prompt. `--server` always wins
and skips discovery. Discovery only crosses one subnet: WiFi client isolation, VLANs, and VPNs
block it, and the Web UI cannot use it at all.
## Transport
Newline-delimited JSON over TCP on a dedicated port (PoC: 8799). No Discord connection, no HTTP
framework.
Newline-delimited JSON over TCP on a dedicated port (PoC: 8799), plus the UDP discovery above. No
Discord connection, no HTTP framework.
| Direction | Message | Meaning |
| --- | --- | --- |
@@ -70,6 +87,9 @@ framework.
| server → client | `welcome` | Assigned name, heartbeat interval, server name |
| client → server | `heartbeat` | `ts` |
| both | `ping` / `pong` | `seq` echo, for the test button and latency |
| client → server | `probe` | UDP discovery ask (`veskslop-remchild-probe`) |
| server → client | `beacon` | UDP discovery answer and broadcast (`veskslop-remchild`) |
| server → client | `notice` | Information, e.g. `heartbeat-missed` with a count |
| server → client | `job` | Later: a unit of work with an ID and a payload |
| client → server | `job-result` | Later: `id`, `ok`, `data` or `error` |
@@ -91,7 +111,7 @@ The PoC server moves into the daemon as `poc/src/remchild-server.ts`:
| Phase | Work |
| --- | --- |
| M1 (done) | PoC: naming, listen, allowlist, heartbeat, ping test, history |
| M1 (done) | PoC: naming, listen, allowlist, heartbeat, ping test, history, UDP discovery, heartbeat-miss notices |
| M2 | Move the server into the daemon, add settings, the launch-arg unlock, and tests. Add `job` dispatch and `job-result` with retry and dedupe. |
| M3 | Audio: the daemon sends call audio to the client, the client runs VAD and STT (SAM/VOX or an AI model), and returns annotated text and voice commands. The same path carries TTS back. |
| M4 | Video: stream a window or play a file with MPV, and return frames or a stream URL. |