# openrtc-file-transfer
Optional native companion for the TypeScript `openrtc-file-transfer` package.
It implements the same version-1 named-channel wire format over any protected
bidirectional byte stream. The crate does not own OpenRTC lifecycle, peer
selection, filesystem policy, persistent queues, history, or UI.
Applications open an authenticated OpenRTC peer stream, then pass it to
`send_path` or `receive_to_directory`. Receivers enforce bounded headers and
file sizes, sanitize filenames, write with `create_new`, verify optional SHA-256
digests incrementally, and acknowledge only after the destination is flushed.
Resume is explicit and fail-closed: an offset is accepted only when the named
destination already exists at exactly that length; any declared digest includes
and verifies the existing prefix before appended bytes are acknowledged.
Incoming resume bytes are staged separately, so interruption or integrity
failure never deletes or modifies the receiver's existing destination.
For runtime-wide directional speed limits, clone one
`flow_control::BulkFlowController` across every bulk executor. Configure optional
upload/download bytes-per-second rates and pass a `BodyFlow` with an authenticated
peer scheduling key to `send_path_with_flow` or `receive_to_directory_with_flow`.
The stream helpers bound body and hashing buffers to 64 KiB even when callers
prefer larger chunks. Admission, headers and acknowledgements bypass body pacing.
Start transport I/O deadlines after each pacing wait, rather than wrapping the
whole transfer in a short timeout. Dropping an acquire future cancels its queued
slice; live rate updates wake waiting work. Applications still own durable byte
accounting, quota grants, cross-runtime execution ownership and delivery receipts.
The routed codec also understands negotiated OFT2 `Waiting` (kind `0x08`):
transfer ID, big-endian u64 checkpointed offset and u32 lease milliseconds
(1–60,000). `RECEIVER_WAIT_METADATA_KEY` is `openrtc.receive-wait`; an immutable
offer must contain value `1` before a receiver may issue waiting frames. A wait
is neither an offset ACK nor a completion receipt. Native protocol executors
must implement authenticated-peer/active-window matching, bounded deadline
renewal and cancellation before advertising this capability. Codec support by
itself does not enable receiver pacing or alter the legacy raw-stream helpers.
The shared routed codec supports `CapabilitiesRequest` (OFT2 `0x09`) and
`Capabilities` (`0x0a`). Requests carry an optional immutable header after a
big-endian u32 length; an empty request has zero length. Responses carry a
closed version-1 JSON document after a u32 length, bounded to4096 bytes, with
`version`, `durableResume`, `completionReceipt`, `extensions`,
`receiveAvailable`, and `maxFileBytes` (0..=9,007,199,254,740,991). A header probe
is bounded by the configured header-byte ceiling and the safe-integer size
ceiling, independently of current receive body limits. This permits protected
product receipt lookup after body admission changes.
`RequiredTransferCapabilities` and `FileTransferHeader::with_required_capabilities`
encode required features under immutable `openrtc.required-capabilities.v1`
metadata. `TransferCapabilities::require` checks receiver availability, size and
features before body acceptance. Extension names are bounded, sorted and distinct;
unknown fields, invalid flags/versions and malformed metadata fail closed.
The legacy stream helpers reject required-feature metadata before opening the
source or creating a destination. Their explicit bounded streaming limits remain
separate from routed negotiation.
Native routed executors must probe, bind replies to the authenticated peer and
transfer ID, enforce requirements before allocating a sink, and retrieve an
exact durable product receipt before applying current body limits. They must
verify required receipt persistence before success and require durable
checkpoints for advertised resume. The codec is not a queue, destination/ACL
owner or receipt store; support must not be advertised before the consumer
implements and qualifies those behaviors. See the TypeScript companion for the
shared wire contract and callback-based executor.