Files
skills/docs/networking/network/websocket-gateway/src/gateway/channel-manager.md
2026-05-29 08:20:56 +01:00

2.4 KiB
Raw Blame History

ChannelManager

Purpose

Owns the lifecycle of every Channel registered on a gateway instance. Clients never see a raw Channel — every channel call enters the gateway, which delegates here and translates the result into wire frames the daemon dispatches. Keeping the manager separate from the daemon keeps both files under the 300-line cap and lets channel behaviour be unit-tested independently.

Features

  • Lazy channel creation via getOrCreateChannel(name, allowPatterns?) — channels are stable across the gateway's lifetime once created.
  • publish returns the constructed Message + the deterministic recipient set; the daemon performs the actual socket fan-out so the manager has no WebSocket dependencies.
  • removeClient(clientId) is the disconnect hook — sweeps every channel and drops the client's subscriptions in one pass.
  • clear() for the daemon's shutdown path.

Usage: Basic Example

import { ChannelManager } from "@suaveplan/websocket-gateway";

const mgr = new ChannelManager();
mgr.subscribe("events", "alice", "user.*");
const result = mgr.publish("events", "bob", "user.created", { id: "u1" }, Date.now());

Usage: Advanced Example

import { ChannelManager } from "@suaveplan/websocket-gateway";

const mgr = new ChannelManager();
// Pattern channel
mgr.subscribe("events", "alice", "user.**");
// Exact-only channel
const exact = mgr.getOrCreateChannel("metrics", false);
mgr.publish("events", "bob", "user.signup", null, 1);
// On disconnect
mgr.removeClient("alice");

API Reference

  • getOrCreateChannel(name, allowPatterns = true): Channel
  • getChannel(name): Channel | undefined
  • subscribe(channelName, clientId, topic): { subscribed }
  • unsubscribe(channelName, clientId, topic): { unsubscribed }
  • publish(channelName, senderId, topic, payload, now): { message, recipients } | null
  • removeClient(clientId): void
  • clear(): void
  • size: number getter

Implementation Notes

The manager never constructs channels behind publish — only subscribe and getOrCreateChannel create them. This matches upstream behaviour: publishes to a channel nobody subscribed to are no-ops so observers do not pay for unregistered topics. removeClient iterates every channel because the per-client subscription map lives inside each channel — flattening that out into a global per-client index is the future job of a sharded backend; today the linear sweep is fine at the documented N×subscribers ceiling.