Module map
| Module | Owns |
|---|---|
| lib | The Engine, the dotted command surface, Transmission-shaped torrent rows, engine events |
| model · store | Persisted torrents, queue order, labels, per-torrent limits and seeding rules, per-file flags; atomic JSON writes |
| settings | Transmission’s session keys under their wire names, partial-merge semantics, effective speed limits |
| queue | Which torrents may run: download/seed slots, stalled detection, bandwidth-priority ordering, queue moves |
| seeding | Ratio and idle stop rules across the three Transmission modes (global / per torrent / unlimited) |
| scheduler | Turtle-mode time windows, including overnight windows and the weekday bitfield |
| forecast | The horizon simulated slot by slot — the schedule resolved for each wall-clock moment, then queue::plan, allocation::split and seeding::should_stop called against a simulated snapshot, so a finish time accounts for the turtle window, the queue and the ratio limit that a bytes-left / current-speed ETA cannot see |
| category · rss | Categories with save paths and their own limits, subcategory inheritance and auto-TMM (qBittorrent); RSS feeds with the auto-download rule engine, episode filters and a one-release-per-episode guard (qBittorrent / µTorrent / Deluge) |
| blocklist · watchdir · groups | P2P-plaintext / CIDR rules as merged sorted ranges; watch-dir polling that waits for a file’s size to settle; coloured auto-assign groups |
| verify · tracker | The engine’s own payload re-hash, and HTTP/UDP tracker announces with per-tracker seeders, leechers, interval and failure text |
| log · power · natpmp | The capped message log; the wake lock held while a torrent transfers (IOKit on macOS, SetThreadExecutionState on Windows); and NAT-PMP port mapping (RFC 6886) beside the wire layer's UPnP |
| bencode · metainfo · create · magnet | Span-preserving bencode, .torrent read/write, piece hashing, magnet parse/build |
| session | The wire boundary (a vendored librqbit fork): session options, add/pause/resume/remove, stats, peers, piece map, file order |
| rpc · rpcserver | Transmission RPC method translation, and the HTTP listener that serves it: CSRF session id, Basic auth, wildcard whitelist, optional web root, optional TLS from a .p12 bundle or a PEM pair, and partial-file streaming over HTTP ranges so a player can start on a torrent that is still downloading |
| ffi · tauri_plugin | The C ABI (ztr_invoke) and the Tauri command/event bridge |
| views | Saved views — named condition sets with and/or and their own sort order (rTorrent’s custom views) |
| prealloc · allocation | Space reserved before a download starts at Transmission’s three levels (off / fast-sparse / full via F_PREALLOCATE or fallocate); the weighted split of the global cap, where a torrent’s own limit caps its share and the remainder is redistributed (Tixati) |
An SMTP client (RFC 5321/4954/3207) — STARTTLS, implicit TLS or cleartext, AUTH PLAIN, dot-stuffing — that emails on download completion, with a test-message command | |
| deadline · obligation | Completion-deadline admission control over forecast — feasible / repaired / infeasible with the settings changes that make a set of due dates hold; and seeding-obligation discharge, which projects each torrent’s ratio-or-time debt to a tracker forward to the moment it is paid |
| commands · error | The sorted command list the GUI palette enumerates, drift-guarded by a test against Engine::invoke’s match arms; the error envelope every surface returns |
Dependency footprint
| Crate | Why |
|---|---|
| serde · serde_json | The JSON command surface and every persisted file |
| thiserror · dirs | The error envelope; platform data directories |
| sha1 · hex | Info-hashes and piece hashing (format layer, present in the pure build) |
| librqbit · tokio · url · anyhow | The wire half, behind the net feature: peers, HTTP/UDP trackers, DHT, magnet metadata, UPnP |
| tauri | Optional, for hosts that mount the engine as app commands |
Bencode, the metainfo reader/writer, magnet handling and the whole policy layer are written here rather than pulled in, which is why --no-default-features builds and tests with no sockets, no TLS and no async runtime.
FFI surface
| Export | Contract |
|---|---|
| ztr_init | Initialize the process-global engine and wire its event sink; returns {"ok":true} or an error envelope |
| ztr_invoke | One command + JSON args → JSON result or {"error":{"tag","message"}} |
| ztr_commands | The command list as JSON, so a host builds its menu from the ABI rather than a hardcoded copy |
| ztr_set_event_callback | Install a C callback for engine events; the JSON pointer is valid for the call only |
| ztr_string_free | Release any string this ABI returned |
Test status
301 Rust tests pass on the default (net) build and 288 on --no-default-features — the difference is the wire modules’ own unit tests, including a listener that answers over a real loopback socket. The webui carries 42 headless tests (a DOM shim plus a recording engine bridge) that assert the scaffold, the boot command sequence, that every call goes through the ztr_invoke bridge, and that the view feeds the host shell without binding a global key. A drift guard reads Engine::invoke’s own source and fails if the published command list and the accepted commands disagree.
Known gaps
Nothing is missing outright any more. Six rows are partial, each for a stated reason: peer-connection encryption (MSE/PE) and BitTorrent v2 transfers are protocol work the wire layer has not done; a global peer cap does not exist there (it caps per torrent); the .part suffix needs a storage-layer rename the trait has no hook for; the disk-cache setting lost its home when the wire layer dropped its deferred-write buffer — the audit caught that stale claim and downgraded it; and sleep prevention on Linux needs a session-bus inhibitor. Every row is generated from a hand-assessed manifest and audited against the source, which is how that stale claim surfaced.