Files
skills/docs/networking/drive/drive-webrtc/src/data-channel/data-channel-manager/data-channel-manager.md
2026-05-29 08:20:56 +01:00

3.8 KiB

DataChannelManager

(no submodules)

Purpose

DataChannelManager opens, multiplexes, and gates writes on RTCDataChannels for the drive-webrtc mesh. It composes a WebRTCClient — pulling out the underlying RTCPeerConnection per peer — and exposes a uniform send/close/event surface so callers (chunk-source layer, plugin glue, debug tools) never touch raw RTCDataChannel event listeners. Backpressure-aware send waits for bufferedamountlow when the channel is buffering above the high-water mark, preventing the WebRTC stack from being saturated during burst transfers.

Features

  • Per-peer + per-label channel multiplexing.
  • Default channel label drive-chunks and ordered delivery (configurable).
  • High-water-mark backpressure (default 1 MiB) with AbortSignal cancellation.
  • Idempotent close and closeAll semantics.
  • Typed event surface: channel:open, channel:close, channel:message, channel:error.
  • All errors raised at the API boundary are DriveWebRtcError(PEER_NOT_FOUND | DATA_CHANNEL_CLOSED).

Usage: Basic Example

import { DataChannelManager, WebRTCClient } from "@suaveplan/drive-webrtc";

const manager = new DataChannelManager({ client });
const channel = manager.open("bob");
manager.on("channel:message", ({ peerId, data }) => {
    // route inbound payload
});
await manager.send("bob", "drive-chunks", "hello");

Usage: Advanced Example

import { DataChannelManager } from "@suaveplan/drive-webrtc";

const manager = new DataChannelManager({
    client,
    defaultLabel: "drive-chunks",
    defaultOrdered: true,
    highWaterMarkBytes: 256_000,
});

const ctrl = new AbortController();
setTimeout(() => ctrl.abort(), 5_000);
try {
    for (const part of parts) {
        await manager.send("bob", "drive-chunks", part, ctrl.signal);
    }
} catch (err) {
    if (err instanceof DriveWebRtcError && err.code === "DRIVE_WEBRTC.DATA_CHANNEL_CLOSED") {
        // either peer dropped or signal aborted
    }
}
manager.close("bob");

API Reference

new DataChannelManager(options)

  • client: WebRTCClient.
  • defaultLabel?: string (default "drive-chunks").
  • defaultOrdered?: boolean (default true).
  • highWaterMarkBytes?: number (default 1_048_576).

open(peerId, label?, init?): RTCDataChannel

Reuse an open channel for the label, or create a new one via pc.createDataChannel. Throws PEER_NOT_FOUND if the client has no peer connection for peerId.

send(peerId, label, payload, signal?): Promise<void>

Throws DATA_CHANNEL_CLOSED when the channel is missing or its readyState is not "open". When bufferedAmount is above the high-water mark, waits for one bufferedamountlow event before calling channel.send. AbortSignal aborts the wait and the resulting error has cause set to the signal's reason.

close(peerId, label?, reason?) / closeAll(reason?)

Idempotent. close(peerId) with no label closes every channel for the peer.

get(peerId, label?): RTCDataChannel | undefined

Lookup. Defaults to the manager's defaultLabel.

Implementation Notes

  • The manager listens to open, close, error, and message events on every channel it creates. It removes those listeners on detach to avoid leaking after close.
  • On register, if the channel is already "open" (an unusual race the test doubles can reproduce), channel:open is dispatched via queueMicrotask so callers awaiting the event still receive it.
  • error events surface as channel:error carrying a DriveWebRtcError(DATA_CHANNEL_CLOSED) with the underlying event.error as cause.
  • The internal storage is Map<peerId, Map<label, ChannelEntry>>; the outer map is pruned when its inner map becomes empty so a closeAll returns the manager to a fully-clean state.