Skip to content

feat: add typed torrent sources#250

Merged
artrixdotdev merged 8 commits into
mainfrom
feat/add-typed-torrent-sources
Jul 15, 2026
Merged

feat: add typed torrent sources#250
artrixdotdev merged 8 commits into
mainfrom
feat/add-typed-torrent-sources

Conversation

@artrixdotdev

@artrixdotdev artrixdotdev commented Jul 2, 2026

Copy link
Copy Markdown
Owner

Summary

  • Introduce explicit TorrentSource variants for magnet URIs, local torrent paths, loaded torrent bytes, and remote torrent URLs.
  • Update Engine::add_torrent to accept typed sources instead of guessing from arbitrary strings.
  • Add source-level and facade-level tests plus rustdoc examples for frontend/TUI input mapping.

Closes #224
Part of #221

Testing

  • cargo nextest run -p libtortillas torrent_source
  • cargo nextest run -p libtortillas engine_when_torrent_source
  • cargo nextest run --workspace
  • cargo test --doc -p libtortillas
  • cargo clippy --workspace --all-targets -- -D warnings

Ignored network tests were listed with cargo nextest list --workspace --run-ignored ignored-only; they were not run because this PR only changes typed source validation and local metainfo parsing, while the live tracker/peer behavior remains delegated to existing network code.

Summary by CodeRabbit

  • New Features

    • Added clearer, typed torrent input options for magnets, local torrent files, file bytes, and remote torrent URLs.
    • Torrent imports now use explicit source types for more predictable behavior.
  • Bug Fixes

    • Improved validation for torrent sources, including better handling of invalid magnet strings and unsupported remote URL schemes.
    • Added clearer error reporting when a torrent source doesn’t match its declared type.
  • Documentation

    • Updated usage examples to show the new typed torrent input flow.

@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@artrixdotdev, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 50 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3bc88bdd-0c13-4aeb-ae27-f313c9bc0b30

📥 Commits

Reviewing files that changed from the base of the PR and between 68988e0 and 96c9b45.

📒 Files selected for processing (2)
  • crates/libtortillas/src/engine/mod.rs
  • crates/libtortillas/src/engine/source.rs

Walkthrough

This PR introduces a typed TorrentSource enum (Magnet, TorrentFilePath, TorrentFileBytes, RemoteTorrentUrl) with constructors and an async into_metainfo conversion, adds an EngineError::InvalidTorrentSource variant, and refactors Engine::add_torrent to accept TorrentSource instead of a raw string, removing prior prefix-detection logic.

Changes

Typed torrent source

Layer / File(s) Summary
InvalidTorrentSource error variant
crates/libtortillas/src/errors.rs
Adds EngineError::InvalidTorrentSource { source_type, reason } with a formatted message.
TorrentSource enum, constructors, and loaders
crates/libtortillas/src/engine/source.rs
Defines TorrentSource variants, constructor helpers, and into_metainfo which loads magnet URIs, local files, in-memory bytes, and remote URLs (with HTTP/HTTPS validation) into MetaInfo, plus unit tests for each path and error case.
Engine::add_torrent typed API
crates/libtortillas/src/engine/mod.rs
Adds source submodule re-export, changes add_torrent signature from impl ToString to TorrentSource, replaces string-prefix detection with source.into_metainfo().await?, updates doc examples, and adds tests for success and invalid source type errors.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Caller
  participant Engine
  participant TorrentSource
  participant reqwest

  Caller->>Engine: add_torrent(TorrentSource::...)
  Engine->>TorrentSource: into_metainfo()
  alt Remote URL
    TorrentSource->>TorrentSource: validate http/https scheme
    TorrentSource->>reqwest: get(url)
    reqwest-->>TorrentSource: bytes
  end
  TorrentSource-->>Engine: MetaInfo or EngineError
  Engine-->>Caller: Torrent or EngineError
Loading

Possibly related PRs

Suggested labels: enhancement, high prio

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: introducing typed torrent sources.
Linked Issues check ✅ Passed The PR implements typed TorrentSource inputs, removes string heuristics, adds typed invalid-source errors, preserves behavior tests, and updates docs.
Out of Scope Changes check ✅ Passed All changes support typed torrent sources, related errors, tests, or docs; no unrelated scope is evident.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/add-typed-torrent-sources

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot added enhancement New feature or request high prio GET DONE ASAP!! labels Jul 2, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (2)
crates/libtortillas/src/engine/mod.rs (2)

48-48: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Keep the stable facade export explicit.

pub use source::* makes future public items in source.rs part of the engine facade unintentionally. Re-export only the intended stable API item.

Proposed change
-pub use source::*;
+pub use source::TorrentSource;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/libtortillas/src/engine/mod.rs` at line 48, The engine facade is
re-exporting everything from source with pub use source::*, which can
accidentally expose future internals; update mod.rs to re-export only the
intended stable API item from the source module, using the relevant source
symbol explicitly so the public surface stays controlled.

295-332: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a facade-level magnet success test.

The engine facade tests cover file-path success and typed remote mismatch, but not the documented magnet path through Engine::add_torrent.

Proposed test addition
    use crate::{
       engine::{Engine, TorrentSource},
       errors::EngineError,
-      testing::{BIG_BUCK_BUNNY_INFO_HASH, BIG_BUCK_BUNNY_TORRENT_FILE, torrent_fixture_path},
+      testing::{
+         BIG_BUCK_BUNNY_INFO_HASH, BIG_BUCK_BUNNY_MAGNET, BIG_BUCK_BUNNY_TORRENT_FILE,
+         torrent_fixture_path,
+      },
    };
@@
    async fn engine_when_torrent_source_is_file_path_then_adds_torrent() {
       let engine = Engine::builder().autostart(false).build();
       let source =
          TorrentSource::torrent_file_path(torrent_fixture_path(BIG_BUCK_BUNNY_TORRENT_FILE));
@@
       assert_eq!(export.torrents.len(), 1);
    }
+
+   #[tokio::test]
+   async fn engine_when_torrent_source_is_magnet_uri_then_adds_torrent() {
+      let engine = Engine::builder().autostart(false).build();
+      let source = TorrentSource::magnet(BIG_BUCK_BUNNY_MAGNET);
+
+      let torrent = engine.add_torrent(source).await.unwrap();
+      let export = engine.export().await.unwrap();
+
+      assert_eq!(torrent.info_hash().to_hex(), BIG_BUCK_BUNNY_INFO_HASH);
+      assert_eq!(export.torrents.len(), 1);
+   }
 
    #[tokio::test]
    async fn engine_when_torrent_source_type_does_not_match_then_returns_typed_error() {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@crates/libtortillas/src/engine/mod.rs` around lines 295 - 332, Add a
facade-level success test for the magnet path in the tests module under Engine.
The current Engine::add_torrent coverage only verifies file-path success and a
remote-source type mismatch, so add a new async tokio test that builds Engine
with autostart(false), creates a TorrentSource via the magnet constructor, calls
add_torrent, and asserts the returned torrent has the expected info hash and
appears in Engine::export. Use the existing Engine, TorrentSource, and
BIG_BUCK_BUNNY_INFO_HASH symbols to keep the new test aligned with the current
facade-level coverage.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@crates/libtortillas/src/engine/mod.rs`:
- Line 248: The remote metainfo fetch path used by add_torrent is unbounded
because source.into_metainfo() can reach metainfo_from_remote_url, which still
relies on an un-timed reqwest::get call. Update the metainfo fetch flow in the
engine/mod.rs path so the request is executed with the existing client timeout
configuration, and make metainfo_from_remote_url use a timeout-aware client or
request builder instead of bare reqwest::get. Keep the fix localized around
source.into_metainfo(), metainfo_from_remote_url, and the add_torrent call chain
so stalled endpoints fail promptly instead of hanging indefinitely.

In `@crates/libtortillas/src/engine/source.rs`:
- Around line 95-98: The MagnetUri parsing in source handling is still mapping
parse failures to MetaInfoDeserializeError, which loses the typed magnet error
path. Update the error mapping in the MagnetUri::parse branch inside the source
parsing flow to return the dedicated typed magnet error variant instead of
MetaInfoDeserializeError, while keeping the existing logging of the malformed
URI and parse error. Make sure the fix is applied in the code path around
MagnetUri::parse and the EngineError handling used by the source parser.
- Around line 201-214: The current test only covers the invalid-scheme failure
path for TorrentSource::remote_torrent_url and does not verify the happy path.
Add a new async test alongside
torrent_source_when_remote_url_is_not_http_then_returns_typed_error that spins
up a local HTTP/HTTPS server serving a real .torrent file, constructs a
remote_torrent_url from that URL, and asserts into_metainfo() returns success.
Keep the existing invalid-scheme test intact and reuse the TorrentSource and
into_metainfo symbols so the new coverage clearly validates the remote download
path.
- Around line 118-123: The remote torrent fetch in `Source::download` currently
uses `reqwest::get(...).bytes()`, which buffers the entire response without
enforcing status checks, timeouts, or a maximum size. Update this path to use a
`reqwest::Client`-based request with a timeout, verify the response is
successful before reading, and stream/read the body with a hard size cap before
converting it into `torrent_file_bytes`. Keep the fix localized around the
existing `reqwest::get`, `EngineError::MetaInfoFetchError`, and
`torrent_file_bytes` handling.

---

Nitpick comments:
In `@crates/libtortillas/src/engine/mod.rs`:
- Line 48: The engine facade is re-exporting everything from source with pub use
source::*, which can accidentally expose future internals; update mod.rs to
re-export only the intended stable API item from the source module, using the
relevant source symbol explicitly so the public surface stays controlled.
- Around line 295-332: Add a facade-level success test for the magnet path in
the tests module under Engine. The current Engine::add_torrent coverage only
verifies file-path success and a remote-source type mismatch, so add a new async
tokio test that builds Engine with autostart(false), creates a TorrentSource via
the magnet constructor, calls add_torrent, and asserts the returned torrent has
the expected info hash and appears in Engine::export. Use the existing Engine,
TorrentSource, and BIG_BUCK_BUNNY_INFO_HASH symbols to keep the new test aligned
with the current facade-level coverage.
🪄 Autofix (Beta)

✅ Autofix completed


ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 691e3510-a7c0-4055-8536-1b42f76565e7

📥 Commits

Reviewing files that changed from the base of the PR and between 7797155 and 68988e0.

📒 Files selected for processing (3)
  • crates/libtortillas/src/engine/mod.rs
  • crates/libtortillas/src/engine/source.rs
  • crates/libtortillas/src/errors.rs

Comment thread crates/libtortillas/src/engine/mod.rs
Comment thread crates/libtortillas/src/engine/source.rs
Comment thread crates/libtortillas/src/engine/source.rs Outdated
Comment thread crates/libtortillas/src/engine/source.rs
@coderabbitai

coderabbitai Bot commented Jul 2, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Fixes Applied Successfully

Fixed 1 file(s) based on 4 unresolved review comments.

Files modified:

  • crates/libtortillas/src/engine/source.rs

Commit: 2b0d206edf135b9ffd576ca5a2b8a57a599bd2c3

The changes have been pushed to the feat/add-typed-torrent-sources branch.

Time taken: 8m 57s

@artrixdotdev artrixdotdev merged commit d63d260 into main Jul 15, 2026
3 checks passed
@artrixdotdev artrixdotdev deleted the feat/add-typed-torrent-sources branch July 15, 2026 06:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request high prio GET DONE ASAP!!

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Introduce typed TorrentSource for adding torrents

1 participant