Skip to content

Subscriptions

Subscriptions link a WebSocket session to a channel. Each subscription tracks read/write activity and has an optional expiration.


The Subscription Struct

cpp
struct subscription {
    boost::uuids::uuid node_id_;                    // Node that owns this session
    boost::uuids::uuid websocket_connection_id_;    // Session UUID
    boost::uuids::uuid channel_id_;                 // Channel UUID
    std::chrono::system_clock::time_point joined_at_;   // When subscribed
    std::chrono::system_clock::time_point expires_at_;  // When it expires (max = no expiry)
    std::atomic<uint64_t> read_count_{0};           // Messages received
    std::atomic<uint64_t> write_count_{0};          // Messages sent
};

Each subscription is unique per (websocket_connection_id, channel_id) pair — a session cannot subscribe to the same channel twice.


Subscription API

All subscription operations go through clients::registry.

cpp
auto& clients = app.get_state()->of_clients();

Creating a Subscription

cpp
clients.add_subscription(
    node_id,                  // This node's UUID
    session_id,               // WebSocket session UUID
    "room-general",           // Channel name
    std::chrono::system_clock::time_point::max()   // Expiration (max = never)
);

Removing Subscriptions

cpp
// Remove a single subscription
clients.remove_subscription(session_id, "room-general");

// Remove all subscriptions for a session (called automatically on disconnect)
clients.remove_subscriptions_by_session_id(session_id);

// Remove all subscriptions for a node
clients.remove_subscriptions_by_node_id(node_id);

// Expire a specific subscription (marks as expired without removing)
clients.expire_subscription(session_id, "room-general");

Checking Subscription Status

cpp
// Check if a session is subscribed to a channel
bool is_subscribed = clients.has_subscription(session_id, "room-general");

// Get all members of a channel
auto members = clients.get_channel_members(channel_id);

Looking Up Subscribers

cpp
// Get all subscribers for a specific channel
auto subs = clients.get_subscriptions_by_channel_id(channel_id);
for (auto& sub : subs) {
    fmt::println("Session {} subscribed at {}", sub.websocket_connection_id_, sub.joined_at_);
}

// Get WebSocket connections for a node+channel combination
auto connections = clients.get_websocket_connections_by_node_id_and_channel(node_id, "room-general");

Subscription Lifecycle

  1. Subscribeadd_subscription() registers the subscription via the Opcode_ClientSubscribe handler.
  2. Deliverbroadcast_to_channel() sends messages to all subscribers.
  3. Expire — If expires_at_ is reached, the subscription is pruned automatically.
  4. Cleanup — On disconnect, remove_subscriptions_by_session_id() removes all subscriptions for that session.

The subscriptions are stored in a Boost.MultiIndex container with indexes for fast lookups by node, session, channel, and composite keys.