first commit
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
# `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
|
||||
|
||||
```ts
|
||||
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
|
||||
|
||||
```ts
|
||||
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.
|
||||
Reference in New Issue
Block a user