first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,115 @@
# DataChannelManager
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`DataChannelManager` opens, multiplexes, and gates writes on
`RTCDataChannel`s 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
```ts
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
```ts
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.