runsync_transfer/lib.rs
1//! # runsync-transfer
2//!
3//! A peer-to-peer file transfer engine: the sender compresses and seals chunks,
4//! the receiver opens and decompresses them, and both ends run the work across
5//! all available cores while the network stays saturated.
6//!
7//! ## What it does
8//!
9//! - **Parallel everywhere.** Chunks are compressed, encrypted, and written
10//! concurrently across N streams and N CPU workers. Nothing is serialised on
11//! a file cursor or a reassembly buffer.
12//! - **Adaptive compression.** Per-chunk entropy probing plus an extension
13//! table, so `.flac` and `.mp4` are shipped raw while `.wav` and text get
14//! compressed. Incompressible data is never inflated.
15//! - **End-to-end encryption.** X25519 + HKDF + AES-256-GCM or
16//! ChaCha20-Poly1305, layered inside the transport's own TLS so a relay
17//! cannot read payloads.
18//! - **Large files.** 64-bit offsets throughout, positional I/O, constant
19//! memory. A 100 GB file costs the same resident bytes as a 100 MB one.
20//! - **Many files at once.** One manifest, one connection, chunks from
21//! different files interleaved across streams.
22//! - **Resume.** A crashed or cancelled transfer restarts from the chunks
23//! already on disk.
24//! - **Verification.** BLAKE3 over every chunk, folded into a per-file root.
25//!
26//! ## Transport
27//!
28//! The engine talks to a [`Transport`], not to a socket. The bundled QUIC
29//! adapter wraps a `quinn::Connection`, so an application that already has a
30//! QUIC endpoint hands over its live connection rather than dialling a second
31//! one:
32//!
33//! ```no_run
34//! # #[cfg(feature = "quic")]
35//! # async fn f(conn: quinn::Connection) -> Result<(), runsync_transfer::Error> {
36//! use runsync_transfer::{send, Config, Source, QuicTransport};
37//! use std::sync::Arc;
38//!
39//! let transport = Arc::new(QuicTransport::from_connection(conn));
40//! let stats = send(transport, &[Source::new("/data/album")], &Config::default(), None).await?;
41//! println!("{stats}");
42//! # Ok(()) }
43//! ```
44//!
45//! The receiving side:
46//!
47//! ```no_run
48//! # #[cfg(feature = "quic")]
49//! # async fn f(conn: quinn::Connection) -> Result<(), runsync_transfer::Error> {
50//! use runsync_transfer::{receive, Config, QuicTransport};
51//! use std::sync::Arc;
52//!
53//! let transport = Arc::new(QuicTransport::from_connection(conn));
54//! let stats = receive(transport, "/dest", &Config::default(), None).await?;
55//! # Ok(()) }
56//! ```
57//!
58//! ## Encryption
59//!
60//! [`Secrecy::TransportOnly`] is the default and relies on QUIC/TLS. For
61//! payload confidentiality that survives a relay, give both ends the same
62//! pre-shared key or pin each other's static X25519 identities:
63//!
64//! ```
65//! use runsync_transfer::{Config, Secrecy, crypto};
66//!
67//! let psk = crypto::random_key(); // share this out of band
68//! let cfg = Config::default().with_secrecy(Secrecy::Psk(psk));
69//! ```
70//!
71//! ## Tuning
72//!
73//! [`Config::default`] is a reasonable middle. [`Config::throughput`] favours a
74//! fast link (4 MiB chunks, LZ4); [`Config::bandwidth_saving`] favours a slow
75//! one (zstd level 9). The knob that matters most on a long fat path is
76//! `streams`, and the one that bounds memory is
77//! `streams × queue_depth × chunk_size` — see [`Config::memory_budget`].
78
79pub mod codec;
80pub mod config;
81pub mod error;
82pub mod index;
83pub mod io;
84pub mod manifest;
85pub mod metrics;
86pub mod pool;
87pub mod recv;
88pub mod resume;
89pub mod send;
90pub mod transport;
91pub mod wire;
92
93pub use codec::compress::Algorithm;
94pub use codec::crypto;
95pub use config::{Cipher, CompressionConfig, CompressionMode, Config, Secrecy};
96pub use error::{Error, Result};
97pub use manifest::Source;
98pub use metrics::{human_bytes, Metrics, Progress, ProgressFn};
99pub use recv::receive;
100pub use resume::ChunkBitmap;
101pub use send::send;
102pub use transport::{mem::MemTransport, Transport};
103pub use wire::{EntryKind, FileEntry};
104
105#[cfg(feature = "quic")]
106pub use transport::quic::{bulk_transport_config, QuicTransport};