libfw_core/constants.rs
1//! Protocol constants shared between server and client.
2
3/// Fixed chunk size for fragmented transfers (2 MiB).
4pub const CHUNK_SIZE: u64 = 2 * 1024 * 1024;
5
6/// Constant sliding-window size for streaming (64 KiB).
7pub const STREAM_BUF_SIZE: usize = 64 * 1024;
8
9/// Maximum default concurrent connections in the WASM engine.
10pub const DEFAULT_CONCURRENCY: usize = 4;
11
12/// Default in-flight chunk window for a single file's upload.
13///
14/// Kept independent of (and larger than) [`DEFAULT_CONCURRENCY`] so one file
15/// keeps many chunks in flight on high-latency links — enough to fill the
16/// bandwidth-delay product and avoid the "fill, drain, fill" stutter that a
17/// tiny window (== concurrency) causes. It also sets an upper bound that
18/// still works within browser per-origin connection limits (~6 for HTTP/1.1).
19pub const DEFAULT_UPLOAD_WINDOW: usize = 8;
20
21/// Default in-flight chunk window for a single file's **download**.
22///
23/// The tus-style parallel download fetches a large file as many concurrent
24/// byte-range GETs, so a single file's throughput is bounded by bandwidth
25/// instead of `chunk_size / RTT` (the same bandwidth-delay-product fill that
26/// [`DEFAULT_UPLOAD_WINDOW`] provides for uploads). Independent of
27/// `concurrency` (cross-file) and of the upload window. Kept modest because
28/// the WASM engine buffers in-flight chunks in a reorder map so it can emit
29/// them to the SDK strictly in order (append-mode writes); the buffer bound
30/// is `window * download_chunk_size`.
31pub const DEFAULT_DOWNLOAD_WINDOW: usize = 4;
32
33/// Default chunk size for parallel (byte-range) downloads — 256 KiB.
34///
35/// Deliberately smaller than the 2 MiB upload chunk: the WASM engine holds
36/// up to `download_window` of these in a reorder buffer while waiting for
37/// them to arrive in order, so `window * chunk_size` (4 × 256 KiB = 1 MiB by
38/// default) is the engine's worst-case extra allocation — comfortably under
39/// the ~2 MiB per-file memory budget.
40pub const DEFAULT_DOWNLOAD_CHUNK_SIZE: u64 = 256 * 1024;
41
42/// A file with fewer remaining bytes than this stays on the sequential
43/// single-connection download path; larger files use the parallel range-GET
44/// path (which has per-request overhead that only pays off at size).
45pub const MIN_PARALLEL_DOWNLOAD_BYTES: u64 = 512 * 1024;
46
47/// Server-side TTL after which an unfinished "session" upload temp (and its
48/// `.blocks` range sidecar) is considered stale and garbage-collected.
49///
50/// tus `Expiration`-style: a client that vanishes mid-upload would otherwise
51/// leave its shared temp behind forever; the server sweeps temps older than
52/// this. Uploads that are actively being written keep their temp fresh, so
53/// this never interrupts an in-flight transfer.
54pub const DEFAULT_SESSION_TTL: std::time::Duration = std::time::Duration::from_secs(24 * 3600);
55
56/// Default maximum retry count for a failed chunk before failing the task.
57pub const MAX_RETRIES: u32 = 3;
58
59/// Default cap for a single upload (100 GiB, configurable by the server).
60pub const DEFAULT_MAX_UPLOAD_SIZE: u64 = 100 * 1024 * 1024 * 1024;
61
62/// HTTP header advertising the compression algorithm on a body stream.
63///
64/// Value is a [`CompressionFormat`](crate::compress::CompressionFormat)
65/// name (e.g. `zrip`). Mirrored by `Content-Encoding` when applicable.
66pub const HEADER_COMPRESS: &str = "x-libfw-compress";
67
68/// HTTP header carrying JSON-encoded [`FileMeta`](crate::metadata::FileMeta)
69/// for an upload or download.
70pub const HEADER_FILE_META: &str = "x-libfw-file-meta";
71
72/// HTTP header carrying the byte offset to resume an interrupted upload.
73pub const HEADER_OFFSET: &str = "x-libfw-offset";
74
75/// HTTP header marking an upload request as the FINAL chunk of a file.
76///
77/// When present (value `1`/`true`), the server verifies that the resulting
78/// file size equals the declared `x-libfw-file-meta` size before committing,
79/// so a client cannot commit a truncated file. Absent (older clients) skips
80/// the check — the header is optional and backward compatible.
81pub const HEADER_FINAL: &str = "x-libfw-final";
82
83/// HTTP header carrying a per-upload **session id**.
84///
85/// When present, the upload uses the concurrent "session" protocol: each
86/// chunk carries its ABSOLUTE `x-libfw-offset` and is written into a shared
87/// per-session temp file (positional writes), and the final
88/// `x-libfw-final` request commits it. This lets a client pipeline many
89/// chunks in flight (hiding round-trip latency) instead of serializing one
90/// request per chunk. Absent → legacy per-request sequential upload.
91///
92/// A session id should be **stable for a given file version** (derived from
93/// the ETag) so an interrupted upload can be found again on resume: the
94/// shared temp file is keyed by this id, and the server persists which byte
95/// ranges have already been received (see [`HEADER_SESSION_STATUS`]).
96pub const HEADER_SESSION: &str = "x-libfw-session";
97
98/// HTTP header turning a session `POST` into a **status probe**.
99///
100/// When present (value `1`/`probe`) on a session request, the server does
101/// NOT write the body. Instead it opens (creating if needed) the shared
102/// per-session temp and replies with the JSON-encoded byte ranges already
103/// received for that session: `{"ranges": [[start,end], ...]}`. The client
104/// uses this to compute which blocks are still missing and re-send only
105/// those — a BitTorrent-style "only retransmit the broken parts" resume.
106///
107/// Absent (older clients) keeps the previous behavior; legacy servers that
108/// ignore this header simply write nothing for the empty probe body and
109/// return an empty range set, which degrades to a full re-send (idempotent
110/// positional writes make that correct too).
111pub const HEADER_SESSION_STATUS: &str = "x-libfw-session-status";
112
113/// HTTP header carrying the (optional) transfer version handshake.
114pub const HEADER_PROTOCOL: &str = "x-libfw-protocol";
115
116/// Protocol name used in the handshake header.
117pub const PROTOCOL_NAME: &str = "libfw";
118
119/// Protocol version used in the handshake header.
120pub const PROTOCOL_VERSION: &str = "1";
121
122/// The canonical `x-libfw-protocol` header value (e.g. `libfw/1`).
123///
124/// Both the server and the WASM client must agree on this exact value; the
125/// server rejects (426) requests that explicitly advertise a different one.
126/// Keep in sync with [`PROTOCOL_NAME`] / [`PROTOCOL_VERSION`].
127pub fn protocol_header_value() -> &'static str {
128 "libfw/1"
129}
130
131/// Whether a received `x-libfw-protocol` handshake value is compatible with
132/// this build of the library.
133pub fn protocol_compatible(value: &str) -> bool {
134 value.trim().eq_ignore_ascii_case(protocol_header_value())
135}