add docs, protocol, plugins, README, CHANGELOG
This commit is contained in:
parent
1d2209bfac
commit
f262da222b
44 changed files with 9269 additions and 0 deletions
217
docs/02-protocol/state-machine.md
Normal file
217
docs/02-protocol/state-machine.md
Normal file
|
|
@ -0,0 +1,217 @@
|
|||
# State Machine
|
||||
|
||||
> **Phase 1 note:** the gateway and voice-node do not share membership state.
|
||||
> The voice node registers a client on the first UDP packet and drops idle addresses
|
||||
> after 30 seconds. Diagrams that show `gateway notify voice node` describe the Phase 2 target.
|
||||
|
||||
Client and server maintain synchronized state machines over the LNEx connection.
|
||||
This document describes the states, transitions, and what triggers them.
|
||||
|
||||
---
|
||||
|
||||
## Client states
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ DISCONNECTED │ ◄─── initial state / after disconnect
|
||||
└────────┬────────┘
|
||||
│ connect(address)
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ CONNECTING │ TCP handshake in progress
|
||||
└────────┬────────┘
|
||||
│ TCP established
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ HANDSHAKING │ HELLO received, sending AUTH
|
||||
└────────┬────────┘
|
||||
│ SESSION received
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ CONNECTED │ ◄─── idle, no channel joined
|
||||
└────────┬────────┘
|
||||
│ join_channel()
|
||||
▼
|
||||
┌─────────────────┐
|
||||
┌────►│ IN_CHANNEL │ text + voice available
|
||||
│ └────────┬────────┘
|
||||
│ │ leave_channel() / switch channel
|
||||
└──────────────┘
|
||||
│ disconnect() / TCP drop
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ RECONNECTING │ exponential backoff (Phase 2)
|
||||
└────────┬────────┘
|
||||
│ max retries exceeded
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ DISCONNECTED │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
Any state can transition to `DISCONNECTED` on:
|
||||
- TCP connection drop
|
||||
- `DISCONNECT` packet received
|
||||
- auth failure (`ERR_AUTH_FAILED`)
|
||||
- version mismatch (`ERR_VERSION_MISMATCH`)
|
||||
|
||||
---
|
||||
|
||||
## Server session states
|
||||
|
||||
Per-client session on the gateway:
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ ACCEPTING │ TCP connection received, sending HELLO
|
||||
└────────┬────────┘
|
||||
│ AUTH received
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ AUTHENTICATING │ verifying Ed25519 signature
|
||||
└────────┬────────┘
|
||||
│ signature valid + not banned
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ ESTABLISHED │ SESSION sent, client is authenticated
|
||||
└────────┬────────┘
|
||||
│ JOIN_CHANNEL received
|
||||
▼
|
||||
┌─────────────────┐
|
||||
┌────►│ IN_CHANNEL │ forwarding messages + voice state
|
||||
│ └────────┬────────┘
|
||||
│ │ LEAVE_CHANNEL / JOIN different channel
|
||||
└──────────────┘
|
||||
│ TCP drop / DISCONNECT / idle timeout
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ TERMINATED │ session cleaned up, resources freed
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
### Auth failure paths
|
||||
|
||||
```
|
||||
AUTHENTICATING
|
||||
│ invalid signature → send ERR_AUTH_FAILED → TERMINATED
|
||||
│ banned pubkey → send ERR_AUTH_FAILED → TERMINATED
|
||||
│ unsupported version → send ERR_VERSION_MISMATCH → TERMINATED
|
||||
│ rate limit on auth → send ERR_RATE_LIMITED → TERMINATED
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Voice session states (per user, on voice-node)
|
||||
|
||||
> **Phase 1:** transition from `INACTIVE` to `JOINING` happens when the first UDP
|
||||
> packet arrives from a client address, not when the gateway sends a signal.
|
||||
|
||||
```
|
||||
┌─────────────────┐
|
||||
│ INACTIVE │ user not in a voice channel
|
||||
└────────┬────────┘
|
||||
│ first UDP packet from client (Phase 1)
|
||||
│ gateway signals join (Phase 2, not implemented)
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ JOINING │ UDP path being established
|
||||
└────────┬────────┘
|
||||
│ first UDP packet received from client
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ SILENT │ in channel, not transmitting
|
||||
└────────┬────────┘
|
||||
│ voice packets arriving
|
||||
▼
|
||||
┌─────────────────┐
|
||||
┌────►│ SPEAKING │ relaying to other channel members
|
||||
│ └────────┬────────┘
|
||||
│ │ DTX / push-to-talk released / silence
|
||||
└──────────────┘
|
||||
┌─────────────────┐
|
||||
│ MUTED │ server-side mute (moderator action)
|
||||
└────────┬────────┘
|
||||
│ unmuted by moderator
|
||||
▼
|
||||
┌─────────────────┐
|
||||
│ SILENT │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
Voice state is broadcast to all channel members as `VOICE_STATE` packets
|
||||
on every transition: `SILENT → SPEAKING`, `SPEAKING → SILENT`, `MUTED`, `DEAFENED`.
|
||||
|
||||
---
|
||||
|
||||
## Channel join sequence (detailed)
|
||||
|
||||
Full flow from `join_channel()` call to receiving audio:
|
||||
|
||||
```
|
||||
Client Gateway Voice Node
|
||||
│ │ │
|
||||
│── JOIN_CHANNEL ─────────►│ │
|
||||
│ │ check permissions │
|
||||
│ │ check channel exists │
|
||||
│◄─ CHANNEL_STATE ─────────│ │
|
||||
│ { members, │ │
|
||||
│ voice_endpoint, │ (Phase 2: gateway │
|
||||
│ channel_id } │ notifies voice node) │
|
||||
│ │ │
|
||||
│ [start UDP] │ │
|
||||
│── UDP VOICE_PACKET ──────────────────────────────── ►│
|
||||
│ │ │ relay to others
|
||||
│◄─ UDP VOICE_PACKET ───────────────────────────────── │
|
||||
│ │ │
|
||||
│◄─ USER_JOIN broadcast ───│ │
|
||||
│ (sent to all members) │ │
|
||||
```
|
||||
|
||||
If `ERR_PERMISSION_DENIED` is returned on `JOIN_CHANNEL`, the client
|
||||
stays in `CONNECTED` state and does not attempt UDP.
|
||||
|
||||
---
|
||||
|
||||
## Reconnect logic (Phase 2)
|
||||
|
||||
On unexpected TCP drop from `IN_CHANNEL` or `CONNECTED`:
|
||||
|
||||
```
|
||||
disconnect detected
|
||||
│
|
||||
▼
|
||||
RECONNECTING state
|
||||
│
|
||||
├── attempt 1: wait 1s
|
||||
├── attempt 2: wait 2s
|
||||
├── attempt 3: wait 4s
|
||||
├── attempt 4: wait 8s
|
||||
├── attempt 5: wait 16s
|
||||
└── attempt 6+: wait 30s (cap)
|
||||
```
|
||||
|
||||
On successful reconnect:
|
||||
- full auth exchange (new session token)
|
||||
- if user was `IN_CHANNEL` before disconnect: auto-rejoin same channel
|
||||
|
||||
On reconnect failure after N attempts (configurable, default 10):
|
||||
- transition to `DISCONNECTED`
|
||||
- notify user in UI
|
||||
|
||||
---
|
||||
|
||||
## Packet validity by state
|
||||
|
||||
Packets received in an unexpected state are dropped with `ERR_INVALID_PACKET`.
|
||||
|
||||
| Packet | Valid in states |
|
||||
|--------|----------------|
|
||||
| `HELLO` | server sends in `ACCEPTING` |
|
||||
| `AUTH` | client sends in `HANDSHAKING` |
|
||||
| `SESSION` | server sends in `AUTHENTICATING` |
|
||||
| `JOIN_CHANNEL` | `CONNECTED`, `IN_CHANNEL` |
|
||||
| `LEAVE_CHANNEL` | `IN_CHANNEL` |
|
||||
| `CHAT_MESSAGE` | `IN_CHANNEL` |
|
||||
| `VOICE_PACKET` | UDP, user in voice channel |
|
||||
| `PING` / `PONG` | any authenticated state |
|
||||
| `DISCONNECT` | any state |
|
||||
Loading…
Add table
Add a link
Reference in a new issue