-
Notifications
You must be signed in to change notification settings - Fork 0
Architecture
┌──────────── Tauri v2 WebView (Next.js static export) ─────────────┐
│ Themeable React/Tailwind SPA ⇄ @tauri-apps/api: invoke/listen │
└───────────────────┬──────────────────────────▲────────────────────┘
│ commands (JSON only) │ events (JSON, ~1 Hz)
▼ │
┌───────────────────┴──────────────────────────┴────────────────────┐
│ Rust core (tokio runtime) │
│ │
│ src-tauri/src/engine/ thin librqbit::Session wrapper. │
│ No Tauri types. Unit testable. │
│ src-tauri/src/commands/ #[tauri::command] handlers. Thin. │
│ src-tauri/src/state/ app state and persistence. │
└───────────────────┬───────────────────────────────────────────────┘
│ pieces written directly
▼
┌───────────┐
│ Disk │
└───────────┘
These are structural guarantees, not conventions.
librqbit writes pieces straight to disk. The UI receives only small JSON payloads: progress percentages, transfer rates, peer counts, file listings.
This is what keeps memory bounded on a multi-gigabyte ISO. Routing piece data through IPC would mean serialising it, copying it into the WebView heap, and holding it there — which is how torrent clients end up consuming gigabytes of RAM on a large download.
src-tauri/src/engine/ compiles and runs under plain cargo test. It is the
layer most exposed to librqbit churn, so it must be testable without spawning a
WebView. See src-tauri/tests/engine.rs, which drives a real Session with no
Tauri runtime present.
Handlers unwrap shared state, call the engine, and map errors. Anything worth testing lives in the engine, where it can be tested.
Status updates run at approximately 1 Hz. Per-piece events would flood the IPC channel on a fast download and jank the UI for no informational gain.
The types crossing the boundary are defined in src-tauri/src/engine/status.rs
— they are not re-exports of librqbit's internal stats structs. A librqbit
upgrade therefore cannot silently change the contract the frontend depends on;
the compiler forces a look at the mapping instead.
Rust serde structs use #[serde(rename_all = "camelCase")]. Their TypeScript
mirrors live in src/lib/ipc/types.ts and must change in the same commit.
Returns CoreStatus.
| Field | Type | Meaning |
|---|---|---|
clientVersion |
string |
Client string, e.g. "Flume 0.1.0"
|
listenPort |
number | null |
Bound peer port, null if not listening |
announcePort |
number | null |
Port announced to trackers |
dht |
DhtStatus |
DHT subsystem health |
downloadDir |
string |
Absolute download path |
uptimeSeconds |
number |
Seconds since session start |
downloadBps |
number |
Aggregate download rate, bytes/sec |
uploadBps |
number |
Aggregate upload rate, bytes/sec |
livePeers |
number |
Connected peers across all torrents |
health |
EngineHealth |
Derived readiness indicator |
DhtStatus: { enabled, nodesV4, nodesV6, outstandingRequests }.
EngineHealth: "starting" | "connecting" | "ready" | "degraded".
-
starting— the peer listener has not bound a port yet -
connecting— listening, DHT enabled, routing table below 8 nodes -
ready— listening with a usable DHT routing table -
degraded— listening, but DHT is disabled, so magnet links cannot resolve
Commands reject with CommandError:
{
kind: string;
message: string;
}kind is a stable machine-readable identifier so the frontend can branch
without matching on message text. Currently: engineNotReady.
- Tauri builds the app and registers
AppStateand the command handlers. - The window opens immediately — first paint is never blocked.
- A background task derives
EngineConfigfrom OS conventions and starts the session (DHT bootstrap, listener bind, persistence restore). - Until the engine is ready,
get_core_statusreturnsengineNotReadyand the UI shows astartingstate. - On
RunEvent::Exit, session shutdown is awaited so fast-resume state is flushed and a restart resumes rather than re-hashing.
| What | Where |
|---|---|
| Downloads | User's Downloads folder by default (configurable) |
| Session state, fast-resume | OS app-data dir, e.g. ~/Library/Application Support/io.github.adamgreenwell.Flume
|
| DHT routing table |
dht.json inside the session directory |
The DHT path is set explicitly. librqbit's default is a global OS path shared across instances, which both leaks state and causes port collisions between two running copies — see issue #19.
Flume — Apache-2.0. This wiki is generated from docs/ by wiki-sync.yml; edits made here are overwritten on the next sync, so change the source instead and it gets reviewed with the code. The same pages, laid out for reading, are at flume.adamgreenwell.com/docs.
Using Flume
Developing
- Development-Setup
- Architecture
- Design-System
- Torrent-Engine-Notes
- CI-CD-and-Releases
- Signing-and-Distribution
Project