Files
Firelink/TORRENT_FEATURES.md
T

12 KiB
Raw Blame History

Firelink Torrent feature matrix

This document is the source of truth for Firelink's BitTorrent scope, current implementation status, and next work. It compares Firelink with the BitTorrent-specific surface of the bundled Aria2 1.37.0 engine. Aria2's generic HTTP/FTP/SFTP/Metalink options, arbitrary shell hooks, and daemon administration RPCs are intentionally separate unless they affect Torrent ownership or safety.

Reference: Aria2 1.37.0 manual.

Audit basis

  • Audited on 2026-08-02 at Firelink b2c86a2 (main), with the cumulative Torrent work reviewed from edc76a7.
  • Source of truth: src-tauri/src/torrent.rs, torrent_probe.rs, queue.rs, lib.rs, settings.rs, download_ownership.rs, db.rs, the IPC bindings, frontend stores/components, and scripts/smoke-torrent.js.
  • Reliability claims require a source postcondition or a test/harness assertion. A passing local macOS check does not prove Windows/Linux native behavior, public tracker/DHT reachability, or packaged-app behavior.
  • The requested Agy and OpenCode review was bounded to the cumulative Torrent diff and relevant paths. Their advice was used only after this source audit and was verified against the live tree.

Implemented

Intake, metadata, and file selection

  • Local .torrent files, magnet links, and remote HTTP(S) .torrent metadata. Remote metadata is bounded, redirect/SSRF checked, credential-free, parsed, and cached before enqueue.
  • Strict bencode parsing, sorted-key validation, size/depth bounds, UTF-8 validation, canonical info-hash verification, safe output components, and managed metadata retention/rekeying.
  • Selected-file preview and validated select-file handling. Firelink derives the Torrent output contract with Aria2 index-out; it does not use the generic out option for Torrent files.
  • Torrent metadata probing uses Aria2 bt-metadata-only and bt-save-metadata internally, validates the returned hash, and conservatively cleans probe directories. It is not exposed as a separate metadata-only download mode.
  • addTorrent passes validated web-seed/mirror URIs when supplied through the existing download input. There is no separate Torrent web-seed manager.

Queue and lifecycle ownership

  • Torrents use the existing Firelink queue admission, global/per-queue permits, pause/resume, cancellation, retry/GID replacement, restart recovery, and terminal reconciliation.
  • A Torrent's Aria2 GID is paired with the Firelink download ID and lifecycle epoch. Late RPC results and stale terminal events cannot revive a removed or newer lifecycle.
  • Exactly one queue permit remains parked for the complete Aria2 lifecycle, including seeding, and release is idempotent.
  • Aria2 getFiles reconciliation establishes output ownership for Torrent files. Ownership and optional unselected-file removal reservations are canonicalized, persisted, collision-checked, and kept separate.
  • Generic addUri explicitly sets both follow-torrent=false and follow-metalink=false. This prevents an HTTP download from creating an unmanaged child GID outside Firelink's queue, ownership, cancellation, retry, and restart model.

Transfer, seeding, and integrity controls

  • Optional seed-time and/or seed-ratio policies, including ratio-only and unlimited-ratio semantics; upload progress and seeding status are reflected in the UI.
  • Per-Torrent upload limit through Aria2 max-upload-limit, with a live, lifecycle-fenced update path.
  • Global Aria2 aggregate upload limit through max-overall-upload-limit. It is persisted, validated, applied at daemon startup, and changeable through aria2.changeGlobalOption; in Firelink it primarily controls Torrent seeding traffic, and blank means Aria2's unlimited value (0).
  • Per-Torrent maximum peers (bt-max-peers) and low-speed peer expansion threshold (bt-request-peer-speed-limit), including live updates.
  • Optional piece-integrity verification through check-integrity and a safe bt-hash-check-seed/bt-seed-unverified=false policy. Firelink does not silently seed unverified data when the user requests verification.
  • Optional bt-stop-timeout stall policy, persisted per Torrent and reapplied on start/retry.
  • Optional bt-prioritize-piece head/tail preview policy, normalized and reapplied on start/retry.
  • Validated encryption policies mapped consistently to bt-force-encryption, bt-require-crypto, and bt-min-crypto-level.
  • Optional bt-remove-unselected-file cleanup after successful completion, only with an explicit partial selection and confirmation. Cancellation, failure, replacement, and cleanup races are conservative.

Trackers, peers, and network identity

  • Additional bt-tracker URLs and bt-exclude-tracker, including the explicit * wildcard. URLs are bounded, normalized, credential-free, and limited to HTTP(S)/UDP schemes.
  • bt-tracker-connect-timeout, bt-tracker-timeout, and bt-tracker-interval, persisted per Torrent and reapplied on start/retry.
  • Bounded read-only aria2.getPeers diagnostics. Firelink discards peer IPs, ports, IDs, and bitfields at the native boundary and exposes only bounded operational speeds and choking/seeder flags.
  • Global DHT, IPv6 DHT, PEX, and LPD toggles. Private-Torrent behavior remains Aria2-controlled.
  • Launch-scoped TCP/UDP listen-port ranges, external BitTorrent IP, IPv4/IPv6 DHT entry points, IPv6 DHT listen address, and LPD interface. Settings are validated, persisted, and applied only after Firelink restart.
  • Optional bounded peer-ID prefix and peer-agent overrides. They are disabled by default and carry identity/privacy/compatibility warnings.
  • Global bt-max-open-files, bounded to 14096, applied at startup and updateable for newly added Torrents through aria2.changeGlobalOption.

Evidence already present in the tree

  • Rust unit coverage for bencode/hash/path validation, option normalization, queue ownership, lifecycle fencing, persistence sanitization, and native startup argument construction.
  • src-tauri/tests/torrent_rpc.rs covers the production authenticated JSON-RPC HTTP boundary in a Windows-compatible integration-test target.
  • npm run smoke:torrent and npm run smoke:torrent:failure-paths cover deterministic local seeding, magnet metadata resolution, selected output, pause/resume, ownership, cancellation/removal, unavailable trackers, daemon failure, integrity, encryption, tracker/piece policies, open-file and aggregate-upload limits, and stall-timeout behavior.

Aria2 comparison: available but not exposed or only partially represented

Aria2 capability Firelink status Reason / next step
bt-load-saved-metadata Not exposed Firelink has managed metadata files, but a new magnet currently probes metadata instead of reusing an info-hash-keyed cache. Add hash-keyed reuse with validation and stale-cache invalidation.
dht-message-timeout Not exposed Global DHT/UDP timeout tuning is not yet represented in settings. Add only with bounded validation and a runtime/startup contract.
dht-file-path, dht-file-path6 Not explicitly controlled Aria2 can persist DHT routing tables, but Firelink does not choose app-managed paths or report their health. Decide whether portable-mode and privacy behavior justify exposing this.
bt-detach-seed-only Not used Aria2's concurrent-download accounting does not replace Firelink's permit ownership. Enabling it blindly would create two competing concurrency models. Revisit only with an explicit seed-slot policy.
follow-torrent=true/mem Intentionally disabled for generic URLs The child GID has no durable Firelink identity, permit, output ownership, or restart recovery record. Implement only after a parent/child lifecycle model exists and remote metadata validation is preserved.
bt-metadata-only / bt-save-metadata as user actions Internal probe only The Add window resolves metadata before enqueue; a separate user-visible metadata-only job is not currently a product need.
on-bt-download-complete and other hooks Out of scope Aria2 executes arbitrary commands. Firelink does not expose a shell-command injection surface; any future automation should be a bounded, app-owned event system.
bt-enable-hook-after-hash-check Out of scope with hooks It has no useful standalone meaning while arbitrary hooks are excluded.
rpc-save-upload-metadata, save-session, and other daemon-admin RPC policy Out of scope / replaced Firelink owns metadata retention and durable download state; enabling Aria2's uploaded-metadata persistence would create a second storage contract.
Aria2 CLI-only show-files / torrent-file controls Product-equivalent path exists Firelink provides a validated Add-window preview and managed addTorrent path rather than exposing CLI flags.

The comparison intentionally does not treat Aria2 defaults as Firelink features. For example, Aria2 defaults follow-torrent to true, but Firelink must override it to false on every generic addUri path until child ownership is durable.

Priority tiers for future work

Tier 0 — correctness and safety gates

No unstarted Tier 0 feature is approved. The global aggregate upload ceiling was the highest-impact missing control and is now implemented as a persisted, startup, and live-RPC contract.

Before any new Torrent feature is promoted, keep these gates mandatory:

  1. Every Aria2 GID must remain attached to one Firelink identity, lifecycle epoch, permit, and owned-path contract.
  2. Every awaited RPC must re-check lifecycle ownership before mutating UI, persistence, or queue state.
  3. Any cleanup that can delete files must prove ownership and remain conservative after cancellation, daemon loss, restart, and missed events.
  4. Generic followed child GIDs remain disabled until their full lifecycle is modeled and tested.

Tier 1 — high-value user behavior

  1. Info-hash-keyed magnet metadata reuse. Reuse a previously validated managed .torrent by info hash before probing DHT/trackers. Revalidate the bencode and exact hash, bind the result to the current draft/download identity, and delete only invalid or unretained cache entries.
  2. Unselected-file removal crash/restart audit. Add post-crash tests around the persisted removal reservation, Aria2 completion cleanup, path reuse, and case-insensitive path equality. Do not change cleanup ordering until the ownership postconditions are proven.
  3. DHT routing-table persistence policy. Decide and implement app-managed dht-file-path/dht-file-path6 behavior, especially for portable mode, permissions, reset, and privacy. This should be opt-in if it expands data retention beyond the current download metadata contract.

Tier 2 — advanced tuning and ownership expansion

  1. Expose bounded dht-message-timeout if real tracker/DHT diagnostics show a user-visible need; validate it at startup and document that it affects DHT and UDP tracker waits, not HTTP metadata fetches.
  2. Add an explicit seed-slot policy only if Firelink wants seeding to stop consuming a queue permit. Aria2 bt-detach-seed-only alone is insufficient; Firelink's queue and power-management semantics must agree first.
  3. Model generic followed Torrent children (true or mem) with durable parent/child IDs, admission accounting, output ownership, cancellation, retry/GID replacement, restart discovery, and bounded metadata validation. This remains a substantial architecture change, not a one-line option.

Deliberately not planned

  • Arbitrary shell hooks from Aria2.
  • Direct daemon-admin/session-management controls that duplicate Firelink's persistence and ownership system.
  • Claims of public tracker/DHT readiness from local deterministic fixtures.
  • A second Torrent engine. Firelink's existing Aria2 queue, permit, GID, and recovery contracts are the intended transfer architecture.

Validation commands

Run focused checks first, then the relevant broader gates:

npm test -- --run
npm run check:i18n
npm run bindings
cd src-tauri
cargo test --test torrent_rpc -- --nocapture
cargo test --all-targets
cd ..
npm run smoke:torrent
npm run smoke:torrent:failure-paths
git diff --check

Native Windows/Linux behavior, packaged-app startup, public magnets, and router/firewall port forwarding remain separate evidence slices and must not be implied by these local checks.