Bastion.PubSub
lib/pubsub.march — In-process publish/subscribe for Bastion.
PubSub provides topic-based broadcast within a single node. It is the delivery layer for Channel broadcasts and any other real-time fan-out the framework or user code needs.
Subscriptions are stored in a Vault table keyed by "topic:sub_id". The value is the send_fn callback. To iterate all subs for a topic, we use Vault.all() and filter by the topic prefix.
── Usage ─────────────────────────────────────────────────────────────────────
-- Subscribe to a topic (typically done inside a WebSocket loop):
let sub_id = "conn:" ++ conn_id ++ ":" ++ topic
Bastion.PubSub.subscribe(topic, sub_id, fn event -> fn payload_json ->
WebSocket.send_frame(ws, TextFrame(make_frame(topic, event, payload_json)))
)
-- Broadcast from a channel handler:
Bastion.PubSub.broadcast("room:42", "message:new", "{\"body\":\"hello\"}")
-- Broadcast excluding the sender:
Bastion.PubSub.broadcast_from(conn_id, "room:42", "typing", "{}")Functions
Broadcast an event to all subscribers of a topic.
Bastion.PubSub.broadcast("room:42", "message:new", "{\"body\":\"hi\"}")Broadcast an event to all subscribers of a topic, excluding one subscriber.
Bastion.PubSub.broadcast_from(sub_id, "room:42", "typing:start", "{}")Return true if any subscriber is registered for a topic.
Subscribe to a topic with a delivery callback.
sub_id — unique string identifying this subscription (e.g. "conn:abc123:room:42")
send_fn — fn(event)(payload_json) called on each broadcast to this topic
If sub_id is already subscribed, the old send_fn is replaced.Return the number of active subscribers for a topic.
Unsubscribe from a topic. No-op if sub_id is not registered.
Remove all subscriptions held by a connection across every topic. Call this when a WebSocket connection closes to avoid stale send_fns.