181 lines
12 KiB
Markdown
181 lines
12 KiB
Markdown
# @suaveplan/drive-transport-webrtc - WebRTC datachannel transport for the drive mesh. Implements DriveTransport over @suaveplan/drive-webrtc's WebRTCClient + DataChannelManager with a length-prefixed binary framing protocol.
|
|
|
|
## Summary
|
|
|
|
WebRTC datachannel transport for the drive mesh. Implements
|
|
the canonical `DriveTransport` interface from `@suaveplan/drive-mesh`
|
|
over a `@suaveplan/drive-webrtc` `WebRTCClient` + `DataChannelManager`
|
|
pair, multiplexing chunk requests, chunk responses, and presence
|
|
advertisements over a single named data-channel label per peer.
|
|
|
|
This package re-exports `DriveTransport` / `ChunkAdvertisement` /
|
|
`AdvertisementHandler` / `Unsubscribe` from `@suaveplan/drive-mesh` —
|
|
there is no local interface mirror. A drive-mesh `DriveMesh` instance
|
|
slots a `WebRTCDriveTransport` into its transport plane and consumes
|
|
this transport's `requestChunk` / `advertise` / `onAdvertisement` /
|
|
`peers` surface directly. For the HTTPS / server-fallback path, mesh
|
|
ships its own built-in `ServerFallback` (no separate transport
|
|
package).
|
|
|
|
<!-- begin:auto-docs -->
|
|
## Documentation tree
|
|
|
|
- [error-codes](./src/error-codes/error-codes.md) — Defines the typed error-code registry and `DriveTransportWebRtcError` class used by every public boundary of `@suavepla…
|
|
- [error-codes](./src/error-codes/error-codes.md) — Defines the typed error-code registry and `DriveTransportWebRtcError` class used by every public boundary of `@suavepla…
|
|
- [frame](./src/framing/frame/frame.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [frame](./src/framing/frame/frame.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [schemas](./src/schemas/frame.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [frame.schemas](./src/schemas/frame.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [webrtc-transport](./src/transport/webrtc-transport/webrtc-transport.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
- [bitset-codec](./src/transport/webrtc-transport/bitset-codec.md) — Provides the gzip codec used to compress advertisement bitsets before they hit the wire. Bitsets describing which chunk…
|
|
- [hex](./src/transport/webrtc-transport/hex.md) — Boundary helpers converting between the on-the-wire 32-byte file id representation and the hex-encoded form used by eve…
|
|
- [payload-codec](./src/transport/webrtc-transport/payload-codec.md) — Implements the byte-level encoder/decoder for the two structured frame bodies the WebRTC drive transport carries: chunk…
|
|
- [webrtc-transport](./src/transport/webrtc-transport/webrtc-transport.md) — <!-- begin:auto-docs --> _(no submodules)_ <!-- end:auto-docs -->
|
|
<!-- end:auto-docs --> - [frame](./src/framing/frame/frame.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/frame.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [frame.schemas](./src/schemas/frame.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [webrtc-transport](./src/transport/webrtc-transport/webrtc-transport.md) — <!-- begin:auto-docs --> _(no submodules)_- [bitset-codec](./src/transport/webrtc-transport/bitset-codec.md) — Provides the gzip codec used to compress advertisement bitsets before they hit the wire. Bitsets describing which chunk…
|
|
- [hex](./src/transport/webrtc-transport/hex.md) — Boundary helpers converting between the on-the-wire 32-byte file id representation and the hex-encoded form used by eve…
|
|
- [payload-codec](./src/transport/webrtc-transport/payload-codec.md) — Implements the byte-level encoder/decoder for the two structured frame bodies the WebRTC drive transport carries: chunk…
|
|
- [webrtc-transport](./src/transport/webrtc-transport/webrtc-transport.md) — <!-- begin:auto-docs --> _(no submodules)_- [error-codes](./src/error-codes.md) — Defines the typed error-code registry and `DriveTransportWebRtcError` class used by every public boundary of `@suavepla…
|
|
- [frame](./src/framing/frame/frame.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/frame.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [frame.schemas](./src/schemas/frame.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [webrtc-transport](./src/transport/webrtc-transport/webrtc-transport.md) — <!-- begin:auto-docs --> _(no submodules)_- [bitset-codec](./src/transport/webrtc-transport/bitset-codec.md) — Provides the gzip codec used to compress advertisement bitsets before they hit the wire. Bitsets describing which chunk…
|
|
- [hex](./src/transport/webrtc-transport/hex.md) — Boundary helpers converting between the on-the-wire 32-byte file id representation and the hex-encoded form used by eve…
|
|
- [payload-codec](./src/transport/webrtc-transport/payload-codec.md) — Implements the byte-level encoder/decoder for the two structured frame bodies the WebRTC drive transport carries: chunk…
|
|
- [webrtc-transport](./src/transport/webrtc-transport/webrtc-transport.md) — <!-- begin:auto-docs --> _(no submodules)_- [error-codes](./src/error-codes.md) — Defines the typed error-code registry and `DriveTransportWebRtcError` class used by every public boundary of `@suavepla…
|
|
- [frame](./src/framing/frame/frame.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/frame.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [frame.schemas](./src/schemas/frame.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [webrtc-transport](./src/transport/webrtc-transport/webrtc-transport.md) — <!-- begin:auto-docs --> _(no submodules)_- [bitset-codec](./src/transport/webrtc-transport/bitset-codec.md) — Provides the gzip codec used to compress advertisement bitsets before they hit the wire. Bitsets describing which chunk…
|
|
- [hex](./src/transport/webrtc-transport/hex.md) — Boundary helpers converting between the on-the-wire 32-byte file id representation and the hex-encoded form used by eve…
|
|
- [payload-codec](./src/transport/webrtc-transport/payload-codec.md) — Implements the byte-level encoder/decoder for the two structured frame bodies the WebRTC drive transport carries: chunk…
|
|
- [webrtc-transport](./src/transport/webrtc-transport/webrtc-transport.md) — <!-- begin:auto-docs --> _(no submodules)_- [error-codes](./src/error-codes.md) — Defines the typed error-code registry and `DriveTransportWebRtcError` class used by every public boundary of `@suavepla…
|
|
- [frame](./src/framing/frame/frame.md) — <!-- begin:auto-docs --> _(no submodules)_- [schemas](./src/schemas/frame.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_ - [frame.schemas](./src/schemas/frame.schemas.md) — <!-- begin:auto-docs --> _(no submodules)_- [webrtc-transport](./src/transport/webrtc-transport/webrtc-transport.md) — <!-- begin:auto-docs --> _(no submodules)_ - [bitset-codec](./src/transport/webrtc-transport/bitset-codec.md) — Provides the gzip codec used to compress advertisement bitsets before they hit the wire. Bitsets describing which chunk…
|
|
- [hex](./src/transport/webrtc-transport/hex.md) — Boundary helpers converting between the on-the-wire 32-byte file id representation and the hex-encoded form used by eve…
|
|
- [payload-codec](./src/transport/webrtc-transport/payload-codec.md) — Implements the byte-level encoder/decoder for the two structured frame bodies the WebRTC drive transport carries: chunk…
|
|
- [webrtc-transport](./src/transport/webrtc-transport/webrtc-transport.md) — <!-- begin:auto-docs --> _(no submodules)_- [error-codes](./src/error-codes.md) — Defines the typed error-code registry and `DriveTransportWebRtcError` class used by every public boundary of `@suavepla…
|
|
|
|
## Quick start
|
|
|
|
```ts
|
|
import {
|
|
DataChannelManager,
|
|
WebRTCClient,
|
|
} from "@suaveplan/drive-webrtc";
|
|
import { WebRTCDriveTransport } from "@suaveplan/drive-transport-webrtc";
|
|
|
|
const client = new WebRTCClient({
|
|
peerId: "self",
|
|
config: { signaling: { url: "wss://signal.example.com" } },
|
|
});
|
|
const channels = new DataChannelManager({ client });
|
|
|
|
// negotiate connection out of band via SignalingClient ...
|
|
|
|
const transport = new WebRTCDriveTransport({
|
|
client,
|
|
dataChannels: channels,
|
|
defaultLabel: "drive-chunks",
|
|
maxConcurrentRequests: 16,
|
|
requestTimeoutMs: 10_000,
|
|
});
|
|
|
|
// pull a chunk from a peer (fileId is the hex-encoded 32-byte digest)
|
|
const fileId = "ab".repeat(32);
|
|
const bytes = await transport.requestChunk("bob", fileId, 0);
|
|
|
|
// broadcast presence — single `ChunkAdvertisement` object
|
|
await transport.advertise("bob", {
|
|
fileId,
|
|
bitset: ourBitset,
|
|
totalChunks: 1024,
|
|
});
|
|
|
|
// subscribe to incoming advertisements (peerId + advert two-arg form)
|
|
const unsubscribe = transport.onAdvertisement((peerId, advert) => {
|
|
presenceIndex.update(peerId, advert.fileId, advert.bitset);
|
|
});
|
|
|
|
// teardown
|
|
await transport.dispose();
|
|
unsubscribe();
|
|
```
|
|
|
|
## Integration with `drive-mesh`
|
|
|
|
`WebRTCDriveTransport` implements the canonical `DriveTransport`
|
|
contract from `@suaveplan/drive-mesh`. A mesh instance accepts a
|
|
list of `DriveTransport` implementations:
|
|
|
|
```ts
|
|
import { DriveMesh } from "@suaveplan/drive-mesh";
|
|
import { WebRTCDriveTransport } from "@suaveplan/drive-transport-webrtc";
|
|
|
|
const mesh = new DriveMesh({
|
|
transports: [
|
|
new WebRTCDriveTransport({ client, dataChannels }),
|
|
],
|
|
// ...peer registry, signed-chunk source, optional ServerFallback
|
|
});
|
|
```
|
|
|
|
The HTTPS / server-fallback path lives inside drive-mesh itself
|
|
(`ServerFallback` — see `@suaveplan/drive-mesh`'s
|
|
`./server-fallback/server-fallback` module), so there is no
|
|
companion `drive-transport-https` package to plug in.
|
|
|
|
## Wire framing
|
|
|
|
Every datachannel message is a length-prefixed binary frame:
|
|
|
|
```text
|
|
+--------+--------+----------------------+
|
|
| 4 B | 1 B | frameLen - 1 B |
|
|
| length | type | payload |
|
|
+--------+--------+----------------------+
|
|
```
|
|
|
|
- `length` — big-endian uint32 byte count of `type + payload`.
|
|
- `type` — `0x01` chunk-request, `0x02` chunk-response, `0x03`
|
|
advertisement.
|
|
- `payload` shape varies by type:
|
|
- Chunk request: `fileId(32 raw bytes) ‖ chunkId(4 BE uint32)`.
|
|
- Chunk response: raw chunk bytes (length is already known from
|
|
the outer header).
|
|
- Advertisement: `fileId(32 raw bytes) ‖ totalChunks(4 BE uint32) ‖ gzip(bitset)`.
|
|
|
|
Public API takes / returns the hex-encoded form (`fileId: string`,
|
|
64 lowercase hex chars). The codec converts to / from raw bytes at
|
|
the boundary; on-the-wire bytes are unchanged from the pre-rewrite
|
|
representation except for the new 4-byte `totalChunks` field.
|
|
|
|
Frame bodies are capped at 16 MiB. Malformed frames are dropped on the
|
|
receive side and surface as `DriveTransportWebRtcError(FRAME_INVALID)`
|
|
on the send side.
|
|
|
|
## Backpressure
|
|
|
|
Outgoing sends route through `DataChannelManager.send`, which pauses
|
|
when `bufferedAmount` exceeds the data-channel high-water mark and
|
|
resumes on the `bufferedamountlow` event. No additional flow-control
|
|
state is held in this package.
|
|
|
|
## OTel surface
|
|
|
|
| Instrument | Kind | Attributes |
|
|
| --------------------------------------------------- | --------- | ------------------------------------- |
|
|
| `drive.transport.webrtc.requests_total` | counter | `outcome` ∈ ok / timeout / aborted / send_failed / rejected_overflow |
|
|
| `drive.transport.webrtc.advertisements_total` | counter | `direction` ∈ inbound / outbound |
|
|
| `drive.transport.webrtc.request_duration_ms` | histogram | `outcome` |
|
|
| `drive.transport.webrtc.frame_size_bytes` | histogram | `type` ∈ chunk-request / advertisement |
|
|
|
|
## Error codes
|
|
|
|
All errors are instances of `DriveTransportWebRtcError`:
|
|
|
|
- `FRAME_INVALID` — frame header or payload failed validation.
|
|
- `FRAME_TOO_LARGE` — frame body exceeded the 16 MiB cap.
|
|
- `REQUEST_TIMEOUT` — chunk request did not receive a response in time.
|
|
- `PEER_NOT_CONNECTED` — no data channel could be opened for the peer.
|
|
- `DATA_CHANNEL_CLOSED` — channel closed before / during send.
|
|
- `BITSET_COMPRESSION_FAILED` — gzip codec failed.
|
|
- `ABORTED` — `AbortSignal` fired or transport was disposed.
|
|
|
|
## License
|
|
|
|
MIT
|
|
|