WebSocket Bus

Cloudillo’s WebSocket Bus provides real-time notifications for connected clients. It is a general-purpose broadcast channel — separate from the RTDB and CRDT WebSocket protocols.

WebSocket Endpoints Overview

Cloudillo provides three WebSocket endpoints for different real-time use cases:

Endpoint Purpose Protocol Documentation
/ws/bus Notifications and action forwarding JSON messages This page
/ws/rtdb/{file_id} Real-time database subscriptions Binary protocol RTDB Protocol
/ws/crdt/{doc_id} Collaborative document editing (Yjs) Binary sync protocol CRDT Protocol

Connection

URL: wss://cl-o.{domain}/ws/bus

Authentication: Required — the client is authenticated at connection time via the Axum auth middleware. Once connected, the connection is registered in the BroadcastManager per (tenant, user), so broadcasts can target a whole tenant or a single user.

The server sends a WebSocket Ping frame every 30 seconds to keep the connection alive; the connection is cleaned up when either side closes.

Message Protocol

All messages use JSON format. The bus uses a generic, flexible message structure rather than strict typed enums.

BusMessage (Client ↔ Server)

{
  "id": "msg_001",
  "cmd": "ping",
  "data": {}
}
Field Type Description
id string Unique message ID (for matching responses)
cmd string Command type
data object JSON payload (command-specific)

Client → Server Messages

ping

Keep connection alive:

{ "id": "1", "cmd": "ping", "data": {} }

Server responds with:

{ "id": "1", "cmd": "ack", "data": { "status": "pong" } }

Other Commands

Any other cmd value is accepted and acknowledged:

{ "id": "2", "cmd": "ack", "data": { "status": "ok" } }

The bus is designed as a generic transport — application-specific command handling can be added without changing the protocol.

Server → Client Messages (Broadcasts)

The server pushes broadcast messages to connected clients via the BroadcastManager. Messages are delivered to all connections for a tenant (send_to_tenant) or to a specific user (send_to_user).

ACTION

Sent when an action is created locally or received via federation:

{ "id": "evt_001", "cmd": "ACTION", "data": { "actionId": "a1~xyz789...", "type": "POST", "issuer": "alice.example.com" } }

This is the primary real-time event — it notifies connected clients about new posts, comments, reactions, messages, connection requests, and all other action types.

notification

Sent by the action DSL hook system for targeted notifications:

{ "id": "evt_002", "cmd": "notification", "data": { ... } }

FILE_ID_GENERATED

Sent when a file upload completes and the content-addressed file ID is computed:

{ "id": "evt_003", "cmd": "FILE_ID_GENERATED", "data": { "fileId": "f1~Qo2E3G8TJZ..." } }

Architecture

BroadcastManager

The BroadcastManager maintains a registry of connected users per tenant, using tokio::broadcast channels for message distribution:

  • Multi-tenant isolation — each tenant’s broadcasts are separate
  • Per-user targetingsend_to_tenant reaches all of a tenant’s connections; send_to_user reaches one user’s connections
  • Bounded buffer — 128 messages per channel; a slow receiver that lags is skipped forward (warned), not disconnected
  • Automatic cleanup — connections are removed when the WebSocket closes

Action Forwarding

The bus integrates with the action processing pipeline:

Outbound (local action creation):

  1. User creates action via POST /api/actions
  2. ActionCreatorTask completes
  3. Action broadcast to all connected sessions for the user’s tenant

Inbound (federated action reception):

  1. Remote action arrives at POST /api/inbox
  2. ActionVerifierTask verifies and stores the action
  3. Action broadcast to all connected sessions for the target tenant

See Also