Skip to main content

Crate ryu_realtime

Crate ryu_realtime 

Source
Expand description

Room-keyed realtime primitive (Phase 1 of the multi-user collaboration epic).

This module is the transport-agnostic fan-out core that chat fan-out, CRDT doc-sync (Phase 3), and presence/awareness all consume. It is a sibling to Core’s identity_verify (the USER-identity layer) and intentionally knows nothing about WebSockets, JWTs, or access control — those live in the WS handler (stage 2/3) that drives this registry.

§Shape

  • A RoomRegistry maps room_id -> a RoomHandle. Each live room runs as ONE tokio actor task ([run_room]) that owns the room’s ephemeral state (presence map + idle clock) behind a command channel, plus a tokio::sync::broadcast sender for fan-out to every joined member.
  • Membership is reference-counted via an AtomicUsize shared between the handle and the actor. RoomHandle::join returns a RoomMembership RAII guard whose Drop decrements the count, evicts the member’s presence, and broadcasts a presence_leave delta — so a client that drops its socket without a clean leave is still reaped.
  • Hibernation is the single biggest scaling lever: a room that has had zero members for longer than RoomConfig::idle_window exits its actor and is removed from the registry (rehydrated on the next join). Evictions are logged.

§Race safety (membership vs eviction)

Concurrent callers MUST join via RoomRegistry::join, whose get-or-create and fetch_add both run while holding the registry Mutex. The actor’s eviction recheck ([try_evict]) takes that same lock, so the two serialize: either join wins (eviction then sees members > 0 and skips) or eviction wins (removes the entry and exits; join transparently re-creates a fresh room). There is no window in which a caller ends up holding a handle to a room the registry has dropped.

The lower-level RoomRegistry::get_or_create + RoomHandle::join two-step is NOT race-safe against eviction (the increment happens outside the lock) and exists only for single-threaded tests with controlled lifecycles.

§Channels

A Frame carries a RealtimeChannel tag. Events and Presence carry serde_json::Value (JSON text on the wire); DocSync carries opaque Vec<u8> that passes through untouched (reserved for Phase 3 — accept and relay binary without interpreting it).

Presence is NEVER persisted: it lives only in the actor’s in-memory map with a heartbeat TTL, and vanishes when the room hibernates.

Staging note: stage 1 builds the primitive with unit tests. Wiring into ServerState, the GET /api/realtime/ws route, and append_message fan-out happens in stages 2/3, so several items are intentionally unused for now.

Structs§

ConnId
Opaque, process-unique identity for one subscriber Connection. The address a targeted RoomHandle::send_event delivers to.
Connection
A typed subscriber to one room, addressable by its ConnId. It merges the room’s broadcast fan-out with events RoomHandle::send_event delivers to it privately, decoding each into a typed Event. Dropping it unregisters the targeted channel from the room actor — the RAII unsubscribe handle, the same pattern Rivet’s actor.on(...) teardown gives you.
Event
A decoded typed room event: a name plus its JSON payload. Produced by Connection::recv from an enveloped Frame::Event.
RoomConfig
Tunables for room lifecycle. RoomConfig::default uses production values; tests construct short windows via RoomRegistry::with_config.
RoomHandle
A cloneable handle to a live room: the broadcast sender for fan-out, the command channel to the actor, and the shared member counter. Obtained from RoomRegistry::get_or_create.
RoomMembership
RAII guard for one member’s presence in a room. Created by RoomHandle::join. On Drop (or explicit RoomMembership::leave) it decrements the member count, evicts this member’s presence, and broadcasts a presence_leave delta — so an abrupt disconnect is still reaped.
RoomRegistry
Process-shared registry of live rooms. Cheap to clone (it is an Arc bag) so it can live in ServerState and be reached from handlers and append_message.

Enums§

Frame
One fan-out frame. Event/Presence carry JSON; DocSync carries opaque bytes so binary CRDT updates pass through without interpretation. Clone is cheap-ish (Value/Vec share via the broadcast clone on each receiver).
RealtimeChannel
The logical channel a Frame travels on. DocSync is reserved for Phase 3 CRDT sync and is relayed opaquely for now.