Skip to content

Bumping versions and other improvements#86

Merged
Power2All merged 4 commits into
masterfrom
v4.2.15
Jul 3, 2026
Merged

Bumping versions and other improvements#86
Power2All merged 4 commits into
masterfrom
v4.2.15

Conversation

@Power2All

@Power2All Power2All commented Jul 3, 2026

Copy link
Copy Markdown
Owner
  • Did some further performance tweaking
  • Bumped versions
  • Added full doc blocks

Summary by CodeRabbit

  • New Features

    • Added security utilities for validating API keys, file paths, peer messages/IDs, query length, and remote IPs; documented secure API key generation.
    • Improved whitelist batch endpoints so entries are validated up-front before any state changes.
  • Bug Fixes

    • Updated user APIs: GET /api/users includes all provided identifiers; DELETE operations now hash inputs consistently without enforcing hex formatting rules.
    • Persistence now propagates database transaction commit failures instead of silently succeeding.
    • Reduced allocations/improved peer list construction during announces and adjusted UDP announce handling.
  • Chores

    • Released v4.2.15, updated Docker/desktop version references, expanded API documentation, and refreshed RTC-related tests.

* Bumped versions
* Added full doc blocks
@Power2All Power2All self-assigned this Jul 3, 2026
@Power2All Power2All added documentation Improvements or additions to documentation enhancement New feature or request labels Jul 3, 2026
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 27 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: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7e9559fb-08a5-421c-93d3-e47e2e1b9e73

📥 Commits

Reviewing files that changed from the base of the PR and between 559c201 and 574e07d.

📒 Files selected for processing (1)
  • src/api/api_users.rs
📝 Walkthrough

Walkthrough

This PR bumps the project to 4.2.15, adds security validation helpers and API user/whitelist behavior changes, refactors tracker announce/peer/RTC/user-index handling, propagates several database commit failures, and adds rustdoc across the API, HTTP, UDP, WebSocket, SSL, cache, config, common, and tracker code.

Changes

v4.2.15 release

Layer / File(s) Summary
Version metadata
Cargo.toml, README.md, docker/Dockerfile, docker/build.bat, torrust-actix.desktop
Updates package, bundle, Docker, desktop, and changelog version references to 4.2.15.
Dependency updates
Cargo.toml
Bumps several dependency and dev-dependency version constraints.

Functional changes

Layer / File(s) Summary
Security and API request handling
src/security/security.rs, src/api/api_whitelists.rs, src/api/api_users.rs
Adds new validation helpers, batches whitelist validation up front, and changes user lookup/removal to hash arbitrary IDs while updating batch responses.
Tracker announce, RTC, and user index
src/tracker/structs/torrent_tracker.rs, src/tracker/impls/torrent_tracker.rs, src/tracker/impls/torrent_tracker_peers.rs, src/tracker/impls/torrent_tracker_rtctorrent.rs, src/tracker/impls/torrent_tracker_users.rs, src/tracker/impls/torrent_tracker_handlers.rs, src/http/http.rs, src/udp/impls/udp_server.rs, src/websocket/websocket.rs, tests/tracker_tests.rs
Changes announce and peer-removal return shapes, borrows RTC SDP strings, adds a user key index, and updates tracker call sites and tests to the new flow.
Database connectors and commit handling
src/database/impls/database_connector_*, src/database/impls/database_connector.rs
Adds connector documentation and makes save/reset paths return commit failures instead of discarding them.
Other tracker and support behavior
src/tracker/impls/*, src/stats/impls/torrent_tracker.rs
Updates tracker helper docs, user/whitelist/blacklist/key queue docs, stats docs, and tracker construction docs.

Documentation sweep

Layer / File(s) Summary
API, cache, common, config, and database docs
src/api/*, src/cache/*, src/common/*, src/config/*, src/database/*
Adds rustdoc for existing API routes, cache helpers, common utilities, configuration defaults and validation, and SQL builder helpers.
HTTP, SSL, stats, and tracker docs
src/http/http.rs, src/ssl/*, src/stats/*, src/rtctorrent_bridge/*, src/tracker/*
Adds rustdoc for HTTP routing and parsing helpers, TLS certificate storage/resolution, tracker statistics, the rtctorrent bridge API, and tracker helper methods.
UDP, WebSocket, and sentry docs
src/udp/*, src/websocket/*, src/utils/sentry_tracing.rs
Adds rustdoc for UDP parsing/server code, WebSocket cluster/request helpers, and Sentry tracing behavior.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant UdpServer
  participant TorrentTracker
  participant TorrentSharding

  Client->>UdpServer: announce request
  UdpServer->>TorrentTracker: handle_announce(query, user_key)
  TorrentTracker->>TorrentSharding: add_torrent_peer / get_rtctorrent_peers
  TorrentSharding-->>TorrentTracker: AnnounceEntry snapshot
  TorrentTracker->>TorrentTracker: update_user_on_announce(user_id)
  TorrentTracker-->>UdpServer: AnnounceEntry
  UdpServer-->>Client: encoded response
Loading

Possibly related PRs

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Title check ❓ Inconclusive The title is related, but it is broad and doesn’t highlight the main documentation-heavy API, database, and tracker changes. Use a more specific title that names the primary change, such as version bump plus documentation and tracker/API updates.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch v4.2.15

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 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

Note

Due to the large number of review comments, Critical, Major severity comments were prioritized as inline comments.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (5)
src/api/api_whitelists.rs (2)

55-67: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Batch endpoints silently drop entries whose length isn't 40.

The single-hash handlers reject a bad-length info_hash with 400 "bad info_hash", but all three batch handlers (whitelists_get/_post/_delete) skip non-40-char entries with no output row and no error. Callers get a success response that silently omits those hashes. Consider returning an error or an explicit per-hash status for length mismatches to keep the contract consistent with the single-hash routes.

🤖 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 `@src/api/api_whitelists.rs` around lines 55 - 67, The batch whitelist handlers
in whitelists_get/whitelists_post/whitelists_delete are silently skipping
entries whose info_hash length is not 40, unlike the single-hash routes that
return a bad request. Update the loop in api_whitelists to validate every
whitelist entry before processing, and either return HttpResponse::BadRequest on
a length mismatch or include an explicit per-hash error status in the response
so callers do not get a misleading success. Use the existing
hex2bin/InfoHash/check_whitelist flow as the reference point when wiring the
validation.

111-131: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Validate batch whitelist entries before mutating The batch POST/DELETE handlers return 400 on a later invalid hash after earlier entries have already been applied and, when persistent, queued for update. Validate the full list up front or return per-item errors so the response matches the actual state.

🤖 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 `@src/api/api_whitelists.rs` around lines 111 - 131, The batch whitelist
handling in the whitelist loop currently mutates state as it goes, so a later
invalid entry can still leave earlier entries added and queued via
add_whitelist_update/add_whitelist before the 400 is returned. Update the
api_whitelists flow to validate all incoming whitelists up front in the handler
(before calling add_whitelist, add_whitelist_update, or building the response),
or otherwise return per-item results from the same loop so the response reflects
partial success accurately. Use the existing add_whitelist,
add_whitelist_update, and hex2bin path to locate the affected logic.
src/security/security.rs (1)

63-63: 🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

Use a boundary-safe slice here. path[1..] can panic on non-ASCII input because &str slicing must stay on UTF-8 boundaries. Prefer path.get(1..3) == Some(":\\" ) or equivalent.

🤖 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 `@src/security/security.rs` at line 63, The path check in security::security
uses an unsafe string slice that can panic on non-ASCII input; update the logic
around the path prefix test to avoid `path[1..]` and use a boundary-safe check
such as a bounded `get` slice or equivalent. Keep the existing intent in the
same conditional, and preserve the `starts_with('/')` and Windows drive-letter
detection behavior while making the slice UTF-8 safe.
src/http/http.rs (1)

467-546: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

Use each peer’s own port in compact replies
The compact branches append announce_unwrapped.port for every peer, so clients receive the announcer’s port instead of each peer’s peer_addr.port(). Use torrent_peer.peer_addr.port().to_be_bytes() in all compact branches.

🤖 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 `@src/http/http.rs` around lines 467 - 546, The compact peer response in the
HTTP announce handler is using the announcer’s port for every peer instead of
each peer’s own port. Update the compact reply logic in the `http` response
branches to use `torrent_peer.peer_addr.port().to_be_bytes()` when extending
`peers_list`, including both the IPv4 and IPv6 paths inside the announce
handling code.
src/tracker/impls/torrent_tracker_handlers.rs (1)

256-290: 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

Skip enqueuing the zeroed Stopped snapshot AnnounceEntry::default() here becomes an UpdatesAction::Add with zero counts, and the flush path writes those values to the DB/cache. Only queue the update when remove_torrent_peer returns a real snapshot.

🤖 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 `@src/tracker/impls/torrent_tracker_handlers.rs` around lines 256 - 290, The
AnnounceEvent::Stopped branch in torrent_tracker_handlers::handle_announce is
enqueueing a default AnnounceEntry when remove_torrent_peer does not return a
real snapshot, which later gets persisted as an Add update with zeroed counts.
Update the handling so add_torrent_update is only called when
remove_torrent_peer returns a valid new_torrent snapshot, and skip queuing any
update for the default case. Keep the fix localized to the Stopped match arm and
the existing remove_torrent_peer / add_torrent_update flow.
🟡 Minor comments (21)
src/security/security.rs-14-24 (1)

14-24: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Update the API key docs
BASE64_URL_SAFE_NO_PAD over 32 random bytes produces a 43-character URL-safe Base64 string, not a 32-character alphanumeric key. The strength check at line 22 also classifies any non-alphanumeric character as “special,” so the wording should describe the actual character-class check instead of “mixes letters and digits.”

🤖 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 `@src/security/security.rs` around lines 14 - 24, Update the documentation for
generate_secure_api_key so it accurately says the function returns a
43-character URL-safe Base64 string from 32 random bytes, not a 32-character
alphanumeric key. Also revise the startup warning comments/docs near the API key
strength check to match what the logic actually does in the security helpers: it
classifies characters by alphanumeric vs special, rather than checking that the
key “mixes letters and digits.” Refer to generate_secure_api_key and the API key
strength-check helper to keep the wording aligned with the implementation.
src/tracker/impls/torrent_tracker_handlers.rs-291-328 (1)

291-328: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Use needs_update for Completed announces
save_torrent_updates is what propagates peer-count changes to the cache, so skipping add_torrent_update here leaves cache-only deployments with stale Completed state. This branch should follow the same needs_update gate as Started/Stopped.

🤖 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 `@src/tracker/impls/torrent_tracker_handlers.rs` around lines 291 - 328, The
Completed announce branch in torrent_tracker_handlers.rs is bypassing the same
update flow used by Started/Stopped, which can leave cache-only deployments
stale. Update the AnnounceEvent::Completed handling in the announce handler to
use the existing needs_update gate before calling data.add_torrent_update,
following the same pattern already used for other announce events. Keep the
add_torrent_peer and data.get_rtctorrent_peers logic intact, but ensure the
Completed path only skips the cache update when needs_update is false.
src/api/api_certificate.rs-101-101 (1)

101-101: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Remove the expiry-data claim.

The shown response serializes cert_path, key_path, and loaded_at; it does not return expiry data here. Please align the doc with the payload or add the missing field.

🤖 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 `@src/api/api_certificate.rs` at line 101, The `GET /api/certificate/status`
doc comment in `api_certificate.rs` currently claims it reports expiry data, but
the actual status payload only includes `cert_path`, `key_path`, and
`loaded_at`. Update the documentation tied to the certificate status response to
remove the expiry-data claim, or if expiry is intended, add the missing field to
the response and the associated serializer in the certificate status handler.
src/api/api_certificate.rs-21-22 (1)

21-22: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Narrow the reload description.

This handler accepts optional server_type / bind_address filters, so it does not always reload “all SSL-enabled listeners.” Please update the doc to match the filtered behavior.

🤖 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 `@src/api/api_certificate.rs` around lines 21 - 22, The documentation for the
certificate reload handler is too broad because the reload endpoint supports
optional server_type and bind_address filters. Update the doc comment on the
reload handler in api_certificate so it describes reloading only the matching
TLS certificates/listeners rather than “all SSL-enabled listeners,” and make the
wording reflect the filtered behavior exposed by the handler.
src/api/api.rs-410-412 (1)

410-412: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

api_validation does not validate the API token.

This helper only resolves the client IP and records the IP-family stat; token authentication still happens in the callers. Please update the comment so the contract matches the implementation.

🤖 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 `@src/api/api.rs` around lines 410 - 412, The doc comment on api_validation
currently claims it validates both client IP and the API token, but the function
only resolves the client IP and records the IP-family stat. Update the comment
above api_validation in api.rs so it accurately describes the implementation and
caller contract, removing any mention of token validation and keeping the
“Returns Some(response) / None” behavior description aligned with what the
helper actually does.
src/udp/udp.rs-57-61 (1)

57-61: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix the parsing docs to match actual error handling.

These helpers currently do not return an error for trailing bytes; they only process full chunks and silently ignore the remainder. Please either update the docs or add an explicit length check so the contract is true.

Also applies to: 82-86, 107-111

🤖 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 `@src/udp/udp.rs` around lines 57 - 61, The parsing docs for the UDP peer entry
helpers are inconsistent with the actual behavior in the parsing functions that
handle packed 6-byte entries. Update the documentation on the affected helper(s)
to match the implementation, or add an explicit length validation in the
relevant parsing routine so it באמת returns an error on trailing bytes. Make
sure the contract is aligned for the peer parsing helpers referenced by the docs
in the UDP module.
src/api/api_users.rs-126-126 (1)

126-126: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Document the actual batch payload shape.

The handler deserializes Vec<(String, String, u64, u64, u64, u64, u8)>, so callers must send a JSON array of arrays/tuples here, not objects.

Suggested fix
-/// `POST /api/users` — creates or replaces multiple users from a JSON array of user objects.
+/// `POST /api/users` — creates or replaces multiple users from a JSON array of `[id, key, uploaded, downloaded, completed, updated, active]` tuples.
🤖 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 `@src/api/api_users.rs` at line 126, The `POST /api/users` doc comment in
`api_users.rs` currently says the endpoint accepts a JSON array of user objects,
but the `Vec<(String, String, u64, u64, u64, u64, u8)>` deserialization means
the actual payload is an array of tuples/arrays. Update the documentation near
the `POST /api/users` handler to explicitly describe the tuple-shaped batch body
and clarify the field order expected by `Vec<(String, String, u64, u64, u64,
u64, u8)>`.
src/cache/impls/cache_engine.rs-14-14 (1)

14-14: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document the full scheme strings.

url_scheme() returns redis:// and memcache://, so the current wording is slightly misleading.

♻️ Suggested fix
-    /// Returns the URL scheme used to connect to this cache engine (`redis` or `memcache`).
+    /// Returns the URL scheme used to connect to this cache engine (`redis://` or `memcache://`).
🤖 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 `@src/cache/impls/cache_engine.rs` at line 14, The documentation for
url_scheme() is misleading because it implies bare scheme names, but the method
returns full URL prefixes. Update the comment on cache_engine::url_scheme() to
state the complete scheme strings returned by the cache engines, using the
existing symbols url_scheme(), redis, and memcache as the reference point.
src/config/impls/configuration.rs-704-711 (1)

704-711: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Make the load contract explicit.

String::from_utf8_lossy rewrites malformed bytes before TOML parsing, so this does not actually reject invalid UTF-8 input. That can parse a corrupted file into a different config; either document the UTF-8 requirement or switch to a fallible decode.

🤖 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 `@src/config/impls/configuration.rs` around lines 704 - 711, The
Configuration::load contract is currently misleading because
String::from_utf8_lossy will silently rewrite invalid UTF-8 before
toml::from_str runs. Update load to either use a fallible UTF-8 decode and
return an error on malformed bytes, or explicitly document in the load docs that
invalid UTF-8 is accepted and transformed before parsing; keep the behavior and
documentation aligned for Configuration::load and toml::from_str.
src/udp/impls/response.rs-130-135 (1)

130-135: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Fix the from_bytes contract.

Unknown actions are not surfaced as io::Error here; they become an ErrorResponse with "Invalid action". Please align the doc with the implementation, or change the branch to return an error if that is the intended API.

🤖 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 `@src/udp/impls/response.rs` around lines 130 - 135, The from_bytes contract in
response parsing is inconsistent with the implementation: unknown actions are
currently converted into an ErrorResponse with "Invalid action" rather than an
io::Error. Update the documentation on Response::from_bytes and its surrounding
parse logic to match the actual behavior, or change the unknown-action branch in
from_bytes to return an error if that is the intended API; make sure the wording
stays aligned with the Response and ErrorResponse types.
src/database/impls/database_connector.rs-30-34 (1)

30-34: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document the Error::RowNotFound path too.

These wrappers don't only bubble sqlx errors; they also synthesize RowNotFound when the selected backend slot is missing or uninitialized. Please reflect that here and in the repeated load_*/save_* docs below.

🤖 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 `@src/database/impls/database_connector.rs` around lines 30 - 34, The docs for
the database wrapper methods are incomplete because they only mention bubbling
`sqlx` errors and omit the synthesized `Error::RowNotFound` case. Update the
`DatabaseConnector` method docs for the affected `load_*` and `save_*` wrappers
to explicitly mention that they can return `Error::RowNotFound` when the
selected backend slot is missing or uninitialized, alongside the existing `sqlx`
error path. Keep the wording consistent across the repeated doc comments so the
behavior is described the same way in each wrapper.
src/tracker/impls/torrent_tracker_keys.rs-46-48 (1)

46-48: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

timeout = 0 is not permanent here.

add_key() stores now + timeout, and check_key() only accepts future timestamps, so 0 expires immediately. Please update the doc or add a real permanent-key path.

🤖 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 `@src/tracker/impls/torrent_tracker_keys.rs` around lines 46 - 48, The
add_key/check_key behavior in TorrentTrackerKeys does not make timeout = 0
permanent, since the stored expiry is based on now + timeout and check_key only
accepts future timestamps. Update the doc comment on add_key to describe the
actual expiration behavior, or change the TorrentTrackerKeys implementation to
support a true permanent-key path by handling zero-timeout entries distinctly in
add_key and check_key.
src/database/impls/database_connector_pgsql.rs-56-61 (1)

56-61: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

create() is only a connection opener.

This doc says the function creates the PG schema, but the body only builds PgConnectOptions and opens a pool. Please move the schema note to database_connector() or reword this comment.

🤖 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 `@src/database/impls/database_connector_pgsql.rs` around lines 56 - 61, The doc
comment on create() is inaccurate because this function only builds
PgConnectOptions and opens a pool, while the schema creation happens elsewhere.
Update the documentation on create() to describe only the connection-opening
behavior, and move the schema-creation note to database_connector() if that is
the function that actually creates the PostgreSQL schema.
src/tracker/impls/torrent_tracker_keys_updates.rs-59-63 (1)

59-63: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Describe the snapshot/remove-after-success flow.

This method clones the queue first, then removes entries only after a successful flush; it doesn't actually drain the queue up front. Please reword the doc to match the implemented failure semantics.

🤖 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 `@src/tracker/impls/torrent_tracker_keys_updates.rs` around lines 59 - 63, The
doc comment for TorrentTrackerKeysUpdates::flush_queue currently says it drains
the key-update queue up front, but the implementation actually clones the queue
and only removes entries after a successful flush. Reword the
snapshot/remove-after-success description to match the real behavior and make
the failure semantics explicit: on error, the original queued updates remain
intact, and only successful flushes clear them.
src/tracker/impls/torrent_tracker_users_updates.rs-61-66 (1)

61-66: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Describe the snapshot/remove-after-success flow.

This method clones the queue first, then removes entries only after a successful flush; it doesn't actually drain the queue up front. Please reword the doc to match the implemented failure semantics.

🤖 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 `@src/tracker/impls/torrent_tracker_users_updates.rs` around lines 61 - 66,
Update the doc comment for the queue-flush method in
torrent_tracker_users_updates.rs to match the actual
snapshot/remove-after-success behavior: describe that the method clones the
current user-update queue, attempts the flush, and only removes the queued
entries after a successful write. Make sure the error section reflects that on
failure the queue is preserved rather than drained and restored, and keep the
wording aligned with the method that performs the flush/dedup flow.
src/tracker/impls/torrent_tracker_torrents_whitelist_updates.rs-75-79 (1)

75-79: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Describe the snapshot/remove-after-success flow.

This method clones the queue first, then removes entries only after a successful flush; it doesn't actually drain the queue up front. Please reword the doc to match the implemented failure semantics.

🤖 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 `@src/tracker/impls/torrent_tracker_torrents_whitelist_updates.rs` around lines
75 - 79, The doc comment for the whitelist-update flush method currently says it
“drains” the queue, but the implementation actually snapshots the queue, flushes
that snapshot, and only removes entries after a successful flush. Reword the
documentation on the relevant queue-flush method in
torrent_tracker_torrents_whitelist_updates to describe the
snapshot/remove-after-success flow and the failure behavior where entries remain
queued if the flush returns Err(()).
src/tracker/impls/torrent_tracker_export.rs-12-13 (1)

12-13: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Export in-memory state, not the database.

The function serializes the tracker’s current in-memory maps/sets, not a fresh DB read. Please say “current tracker state” if that’s the intended source of truth.

✏️ Suggested wording
-    /// Handles the `--export` CLI command: dumps torrents, whitelist, blacklist, keys and users
-    /// from the database to JSON files.
+    /// Handles the `--export` CLI command: dumps the current tracker state (torrents,
+    /// whitelist, blacklist, keys and users) to JSON files.
🤖 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 `@src/tracker/impls/torrent_tracker_export.rs` around lines 12 - 13, The export
documentation in the torrent tracker export implementation is misleading because
it says the command dumps data from the database, but the source of truth is the
tracker’s current in-memory state. Update the doc comment in the export path
around the tracker export function so it says “current tracker state” and
reflects that it serializes the in-memory maps/sets rather than reading fresh
data from the DB.
src/database/impls/database_connector_sqlite.rs-56-61 (1)

56-61: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Don't claim schema creation here.

create() only opens the SQLite pool; the table bootstrap happens in database_connector() when create_database is enabled. Please narrow the doc to the function's actual responsibility.

✏️ Suggested wording
-    /// Creates the SQLite 3 database schema (tables for torrents, whitelist, blacklist,
-    /// keys and users) and returns a connection pool.
+    /// Opens the SQLite connection pool for the configured DSN.
+    /// Schema creation is handled separately when requested.
🤖 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 `@src/database/impls/database_connector_sqlite.rs` around lines 56 - 61, The
doc comment for `create()` is overstating its behavior by claiming it creates
the SQLite schema, but this function only opens the SQLite pool. Update the
documentation on `create()` in `DatabaseConnectorSqlite` to describe only pool
initialization and its error behavior, and leave schema/bootstrap creation to
`database_connector()` when `create_database` is enabled.
src/rtctorrent_bridge/impls/rtc_torrent_bridge.rs-12-16 (1)

12-16: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document the file-not-found error path.

create_torrent, seed_torrent, and the file-backed download_torrent branch also return FileNotFoundError before Node starts. Please mention that in the # Errors sections so the public contract matches the implementation.

Suggested wording
- /// Returns an [`RtcTorrentBridgeError`] when the script fails or its output cannot be parsed.
+ /// Returns an [`RtcTorrentBridgeError`] when the script fails, its output cannot be parsed,
+ /// or the input file/path does not exist.

Also applies to: 72-76, 127-131

🤖 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 `@src/rtctorrent_bridge/impls/rtc_torrent_bridge.rs` around lines 12 - 16,
Update the doc comments for create_torrent, seed_torrent, and the file-backed
download_torrent branch in RtcTorrentBridge so the # Errors sections explicitly
mention FileNotFoundError when the input file is missing before Node starts.
Keep the existing RtcTorrentBridgeError/script-failure and parse-error
descriptions, and expand the public contract wording near those method comments
to match the implementation.
src/ssl/impls/certificate_store.rs-63-69 (1)

63-69: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Use bundle terminology in the accessor docs.

get_certificate() and get_all_certificates() return Arc<CertificateBundle>, not a key-only value. The current wording is misleading, and callers already use bundle fields such as loaded_at.

Suggested wording
- /// Returns the currently loaded certified key for a server, if any.
+ /// Returns the currently loaded certificate bundle for a server, if any.

- /// Returns the loaded certified keys of all registered servers.
+ /// Returns the loaded certificate bundles of all registered servers.

Also applies to: 132-140

🤖 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 `@src/ssl/impls/certificate_store.rs` around lines 63 - 69, The accessor docs
for get_certificate() and get_all_certificates() use “certificate”/“key” wording
that is misleading because both methods return Arc<CertificateBundle> values.
Update the doc comments on these accessors in CertificateStore to refer to the
loaded bundle terminology, matching the returned type and the bundle fields
callers use such as loaded_at, while keeping the method names unchanged.
src/ssl/impls/dynamic_certificate_resolver.rs-19-23 (1)

19-23: 📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win

Document signing-key conversion failures here too.

new() and refresh_cache() can also return CertificateError::CertifiedKeyError when bundle_to_certified_key() can't build a usable rustls signing key, not just when the store is empty.

🤖 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 `@src/ssl/impls/dynamic_certificate_resolver.rs` around lines 19 - 23, The
documentation for DynamicCertificateResolver::new and refresh_cache currently
only mentions the empty-store case, but these methods can also fail with
CertificateError::CertifiedKeyError when bundle_to_certified_key() cannot
produce a usable rustls signing key. Update the doc comments on the relevant
methods in dynamic_certificate_resolver.rs to mention this signing-key
conversion failure alongside the existing no-certificate-loaded error, using the
bundle_to_certified_key and CertifiedKeyError symbols as the reference points.
🧹 Nitpick comments (1)
src/tracker/impls/torrent_tracker.rs (1)

121-121: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Prefer a plain AHashMap::default() for consistency.

Other structs in this cohort (e.g. TorrentEntry::default, AnnounceEntry::default) construct AHashMap::default() via a direct import rather than the fully-qualified crate::tracker::types::ahash_map::AHashMap::default() path used here. Purely cosmetic, but worth aligning for readability.

♻️ Optional cleanup
-            users_key_index: Arc::new(RwLock::new(crate::tracker::types::ahash_map::AHashMap::default())),
+            users_key_index: Arc::new(RwLock::new(AHashMap::default())),

(requires use crate::tracker::types::ahash_map::AHashMap; at the top of the file if not already imported)

🤖 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 `@src/tracker/impls/torrent_tracker.rs` at line 121, Use the plain
AHashMap::default() style for the users_key_index initialization in
TorrentTracker to match TorrentEntry::default and AnnounceEntry::default. Add
the direct AHashMap import at the top of torrent_tracker.rs if needed, then
replace the fully qualified
crate::tracker::types::ahash_map::AHashMap::default() reference in
TorrentTracker’s default/constructor path with AHashMap::default() for
consistency and readability.
🤖 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 `@src/api/api_users.rs`:
- Line 189: The delete endpoints are still using the internal hash instead of
the advertised id/UUID, so align them with the read/create flow. Update the
delete handlers in api_users (including the batch delete loop) to use hash_id on
the incoming user id/UUID, or else rename the exposed route/body field to
user_hash if you intend to keep deleting by hash. Make sure both the
single-delete and bulk-delete paths use the same identifier conversion as the
get path.
- Line 50: The `GET /api/users` handler is documented as accepting raw
ids/UUIDs, but the `len() == 40` check in the `api_users` path blocks those
inputs and `api_service_users_return_json` hashes them again. Remove the length
gate so the handler forwards raw ids/UUIDs to `api_service_users_return_json`,
or alternatively update the `api_users` docstring to state it only accepts
pre-hashed inputs.

In `@src/database/impls/database_connector_pgsql.rs`:
- Around line 388-392: The transaction save helpers are reporting success
without checking the result of `self.commit(transaction).await`, so failures can
be silently dropped. Update `save_whitelist`, `save_blacklist`, `save_keys`,
`save_users`, and `reset_seeds_peers` to await and propagate the commit result,
then only return success after a successful commit. Make sure the affected
helper methods keep their `# Errors` docs and any queue-flush guarantees in sync
with the actual `DatabaseConnectorPgsql` behavior.

In `@src/database/impls/database_connector_sqlite.rs`:
- Around line 413-417: The transaction helpers in DatabaseConnectorSqlite are
swallowing failures from self.commit(...), so callers can see success even after
a rollback. Update the whitelist helper shown here and the matching blacklist,
key, and reset helpers to return the result of self.commit(...) instead of
discarding it, preserving any commit error in the function’s Result. This keeps
the documented sqlx error behavior accurate and ensures queue-flush callers
observe commit failures.

In `@src/tracker/impls/torrent_tracker_torrents_blacklist.rs`:
- Around line 12-18: The load_blacklist flow in TorrentTrackerTorrentsBlacklist
currently ignores errors from self.sqlx.load_blacklist(tracker).await, which can
let startup continue with an empty blacklist. Update load_blacklist to handle
the Err case explicitly by logging the failure with context or returning the
error so the caller can fail startup closed, and keep the success path for the
Loaded {blacklist} message.

In `@src/tracker/impls/torrent_tracker_torrents_whitelist.rs`:
- Around line 12-18: The whitelist startup path in load_whitelist currently
ignores errors from self.sqlx.load_whitelist(tracker), which lets the tracker
continue with an empty whitelist. Update load_whitelist in
TorrentTrackerTorrentsWhitelist so failures are not swallowed: either propagate
the error to the caller or log it and return a failure so startup can fail
closed. Keep the success path unchanged, but make sure the error case is handled
explicitly instead of using if let Ok(...).

---

Outside diff comments:
In `@src/api/api_whitelists.rs`:
- Around line 55-67: The batch whitelist handlers in
whitelists_get/whitelists_post/whitelists_delete are silently skipping entries
whose info_hash length is not 40, unlike the single-hash routes that return a
bad request. Update the loop in api_whitelists to validate every whitelist entry
before processing, and either return HttpResponse::BadRequest on a length
mismatch or include an explicit per-hash error status in the response so callers
do not get a misleading success. Use the existing
hex2bin/InfoHash/check_whitelist flow as the reference point when wiring the
validation.
- Around line 111-131: The batch whitelist handling in the whitelist loop
currently mutates state as it goes, so a later invalid entry can still leave
earlier entries added and queued via add_whitelist_update/add_whitelist before
the 400 is returned. Update the api_whitelists flow to validate all incoming
whitelists up front in the handler (before calling add_whitelist,
add_whitelist_update, or building the response), or otherwise return per-item
results from the same loop so the response reflects partial success accurately.
Use the existing add_whitelist, add_whitelist_update, and hex2bin path to locate
the affected logic.

In `@src/http/http.rs`:
- Around line 467-546: The compact peer response in the HTTP announce handler is
using the announcer’s port for every peer instead of each peer’s own port.
Update the compact reply logic in the `http` response branches to use
`torrent_peer.peer_addr.port().to_be_bytes()` when extending `peers_list`,
including both the IPv4 and IPv6 paths inside the announce handling code.

In `@src/security/security.rs`:
- Line 63: The path check in security::security uses an unsafe string slice that
can panic on non-ASCII input; update the logic around the path prefix test to
avoid `path[1..]` and use a boundary-safe check such as a bounded `get` slice or
equivalent. Keep the existing intent in the same conditional, and preserve the
`starts_with('/')` and Windows drive-letter detection behavior while making the
slice UTF-8 safe.

In `@src/tracker/impls/torrent_tracker_handlers.rs`:
- Around line 256-290: The AnnounceEvent::Stopped branch in
torrent_tracker_handlers::handle_announce is enqueueing a default AnnounceEntry
when remove_torrent_peer does not return a real snapshot, which later gets
persisted as an Add update with zeroed counts. Update the handling so
add_torrent_update is only called when remove_torrent_peer returns a valid
new_torrent snapshot, and skip queuing any update for the default case. Keep the
fix localized to the Stopped match arm and the existing remove_torrent_peer /
add_torrent_update flow.

---

Minor comments:
In `@src/api/api_certificate.rs`:
- Line 101: The `GET /api/certificate/status` doc comment in
`api_certificate.rs` currently claims it reports expiry data, but the actual
status payload only includes `cert_path`, `key_path`, and `loaded_at`. Update
the documentation tied to the certificate status response to remove the
expiry-data claim, or if expiry is intended, add the missing field to the
response and the associated serializer in the certificate status handler.
- Around line 21-22: The documentation for the certificate reload handler is too
broad because the reload endpoint supports optional server_type and bind_address
filters. Update the doc comment on the reload handler in api_certificate so it
describes reloading only the matching TLS certificates/listeners rather than
“all SSL-enabled listeners,” and make the wording reflect the filtered behavior
exposed by the handler.

In `@src/api/api_users.rs`:
- Line 126: The `POST /api/users` doc comment in `api_users.rs` currently says
the endpoint accepts a JSON array of user objects, but the `Vec<(String, String,
u64, u64, u64, u64, u8)>` deserialization means the actual payload is an array
of tuples/arrays. Update the documentation near the `POST /api/users` handler to
explicitly describe the tuple-shaped batch body and clarify the field order
expected by `Vec<(String, String, u64, u64, u64, u64, u8)>`.

In `@src/api/api.rs`:
- Around line 410-412: The doc comment on api_validation currently claims it
validates both client IP and the API token, but the function only resolves the
client IP and records the IP-family stat. Update the comment above
api_validation in api.rs so it accurately describes the implementation and
caller contract, removing any mention of token validation and keeping the
“Returns Some(response) / None” behavior description aligned with what the
helper actually does.

In `@src/cache/impls/cache_engine.rs`:
- Line 14: The documentation for url_scheme() is misleading because it implies
bare scheme names, but the method returns full URL prefixes. Update the comment
on cache_engine::url_scheme() to state the complete scheme strings returned by
the cache engines, using the existing symbols url_scheme(), redis, and memcache
as the reference point.

In `@src/config/impls/configuration.rs`:
- Around line 704-711: The Configuration::load contract is currently misleading
because String::from_utf8_lossy will silently rewrite invalid UTF-8 before
toml::from_str runs. Update load to either use a fallible UTF-8 decode and
return an error on malformed bytes, or explicitly document in the load docs that
invalid UTF-8 is accepted and transformed before parsing; keep the behavior and
documentation aligned for Configuration::load and toml::from_str.

In `@src/database/impls/database_connector_pgsql.rs`:
- Around line 56-61: The doc comment on create() is inaccurate because this
function only builds PgConnectOptions and opens a pool, while the schema
creation happens elsewhere. Update the documentation on create() to describe
only the connection-opening behavior, and move the schema-creation note to
database_connector() if that is the function that actually creates the
PostgreSQL schema.

In `@src/database/impls/database_connector_sqlite.rs`:
- Around line 56-61: The doc comment for `create()` is overstating its behavior
by claiming it creates the SQLite schema, but this function only opens the
SQLite pool. Update the documentation on `create()` in `DatabaseConnectorSqlite`
to describe only pool initialization and its error behavior, and leave
schema/bootstrap creation to `database_connector()` when `create_database` is
enabled.

In `@src/database/impls/database_connector.rs`:
- Around line 30-34: The docs for the database wrapper methods are incomplete
because they only mention bubbling `sqlx` errors and omit the synthesized
`Error::RowNotFound` case. Update the `DatabaseConnector` method docs for the
affected `load_*` and `save_*` wrappers to explicitly mention that they can
return `Error::RowNotFound` when the selected backend slot is missing or
uninitialized, alongside the existing `sqlx` error path. Keep the wording
consistent across the repeated doc comments so the behavior is described the
same way in each wrapper.

In `@src/rtctorrent_bridge/impls/rtc_torrent_bridge.rs`:
- Around line 12-16: Update the doc comments for create_torrent, seed_torrent,
and the file-backed download_torrent branch in RtcTorrentBridge so the # Errors
sections explicitly mention FileNotFoundError when the input file is missing
before Node starts. Keep the existing RtcTorrentBridgeError/script-failure and
parse-error descriptions, and expand the public contract wording near those
method comments to match the implementation.

In `@src/security/security.rs`:
- Around line 14-24: Update the documentation for generate_secure_api_key so it
accurately says the function returns a 43-character URL-safe Base64 string from
32 random bytes, not a 32-character alphanumeric key. Also revise the startup
warning comments/docs near the API key strength check to match what the logic
actually does in the security helpers: it classifies characters by alphanumeric
vs special, rather than checking that the key “mixes letters and digits.” Refer
to generate_secure_api_key and the API key strength-check helper to keep the
wording aligned with the implementation.

In `@src/ssl/impls/certificate_store.rs`:
- Around line 63-69: The accessor docs for get_certificate() and
get_all_certificates() use “certificate”/“key” wording that is misleading
because both methods return Arc<CertificateBundle> values. Update the doc
comments on these accessors in CertificateStore to refer to the loaded bundle
terminology, matching the returned type and the bundle fields callers use such
as loaded_at, while keeping the method names unchanged.

In `@src/ssl/impls/dynamic_certificate_resolver.rs`:
- Around line 19-23: The documentation for DynamicCertificateResolver::new and
refresh_cache currently only mentions the empty-store case, but these methods
can also fail with CertificateError::CertifiedKeyError when
bundle_to_certified_key() cannot produce a usable rustls signing key. Update the
doc comments on the relevant methods in dynamic_certificate_resolver.rs to
mention this signing-key conversion failure alongside the existing
no-certificate-loaded error, using the bundle_to_certified_key and
CertifiedKeyError symbols as the reference points.

In `@src/tracker/impls/torrent_tracker_export.rs`:
- Around line 12-13: The export documentation in the torrent tracker export
implementation is misleading because it says the command dumps data from the
database, but the source of truth is the tracker’s current in-memory state.
Update the doc comment in the export path around the tracker export function so
it says “current tracker state” and reflects that it serializes the in-memory
maps/sets rather than reading fresh data from the DB.

In `@src/tracker/impls/torrent_tracker_handlers.rs`:
- Around line 291-328: The Completed announce branch in
torrent_tracker_handlers.rs is bypassing the same update flow used by
Started/Stopped, which can leave cache-only deployments stale. Update the
AnnounceEvent::Completed handling in the announce handler to use the existing
needs_update gate before calling data.add_torrent_update, following the same
pattern already used for other announce events. Keep the add_torrent_peer and
data.get_rtctorrent_peers logic intact, but ensure the Completed path only skips
the cache update when needs_update is false.

In `@src/tracker/impls/torrent_tracker_keys_updates.rs`:
- Around line 59-63: The doc comment for TorrentTrackerKeysUpdates::flush_queue
currently says it drains the key-update queue up front, but the implementation
actually clones the queue and only removes entries after a successful flush.
Reword the snapshot/remove-after-success description to match the real behavior
and make the failure semantics explicit: on error, the original queued updates
remain intact, and only successful flushes clear them.

In `@src/tracker/impls/torrent_tracker_keys.rs`:
- Around line 46-48: The add_key/check_key behavior in TorrentTrackerKeys does
not make timeout = 0 permanent, since the stored expiry is based on now +
timeout and check_key only accepts future timestamps. Update the doc comment on
add_key to describe the actual expiration behavior, or change the
TorrentTrackerKeys implementation to support a true permanent-key path by
handling zero-timeout entries distinctly in add_key and check_key.

In `@src/tracker/impls/torrent_tracker_torrents_whitelist_updates.rs`:
- Around line 75-79: The doc comment for the whitelist-update flush method
currently says it “drains” the queue, but the implementation actually snapshots
the queue, flushes that snapshot, and only removes entries after a successful
flush. Reword the documentation on the relevant queue-flush method in
torrent_tracker_torrents_whitelist_updates to describe the
snapshot/remove-after-success flow and the failure behavior where entries remain
queued if the flush returns Err(()).

In `@src/tracker/impls/torrent_tracker_users_updates.rs`:
- Around line 61-66: Update the doc comment for the queue-flush method in
torrent_tracker_users_updates.rs to match the actual
snapshot/remove-after-success behavior: describe that the method clones the
current user-update queue, attempts the flush, and only removes the queued
entries after a successful write. Make sure the error section reflects that on
failure the queue is preserved rather than drained and restored, and keep the
wording aligned with the method that performs the flush/dedup flow.

In `@src/udp/impls/response.rs`:
- Around line 130-135: The from_bytes contract in response parsing is
inconsistent with the implementation: unknown actions are currently converted
into an ErrorResponse with "Invalid action" rather than an io::Error. Update the
documentation on Response::from_bytes and its surrounding parse logic to match
the actual behavior, or change the unknown-action branch in from_bytes to return
an error if that is the intended API; make sure the wording stays aligned with
the Response and ErrorResponse types.

In `@src/udp/udp.rs`:
- Around line 57-61: The parsing docs for the UDP peer entry helpers are
inconsistent with the actual behavior in the parsing functions that handle
packed 6-byte entries. Update the documentation on the affected helper(s) to
match the implementation, or add an explicit length validation in the relevant
parsing routine so it באמת returns an error on trailing bytes. Make sure the
contract is aligned for the peer parsing helpers referenced by the docs in the
UDP module.

---

Nitpick comments:
In `@src/tracker/impls/torrent_tracker.rs`:
- Line 121: Use the plain AHashMap::default() style for the users_key_index
initialization in TorrentTracker to match TorrentEntry::default and
AnnounceEntry::default. Add the direct AHashMap import at the top of
torrent_tracker.rs if needed, then replace the fully qualified
crate::tracker::types::ahash_map::AHashMap::default() reference in
TorrentTracker’s default/constructor path with AHashMap::default() for
consistency and readability.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: e44e9985-196f-4a3a-a61a-e73169cb38ec

📥 Commits

Reviewing files that changed from the base of the PR and between e1ce34e and 85b9c15.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (84)
  • Cargo.toml
  • README.md
  • docker/Dockerfile
  • docker/build.bat
  • src/api/api.rs
  • src/api/api_blacklists.rs
  • src/api/api_certificate.rs
  • src/api/api_keys.rs
  • src/api/api_stats.rs
  • src/api/api_torrents.rs
  • src/api/api_users.rs
  • src/api/api_whitelists.rs
  • src/cache/impls/cache_connector_connect.rs
  • src/cache/impls/cache_connector_memcache_connect.rs
  • src/cache/impls/cache_connector_redis_connect.rs
  • src/cache/impls/cache_engine.rs
  • src/cache/impls/torrent_peer_counts.rs
  • src/common/common.rs
  • src/common/impls/compressed_bytes.rs
  • src/common/impls/custom_error.rs
  • src/common/structs/compressed_bytes.rs
  • src/config/config.rs
  • src/config/impls/cluster_mode.rs
  • src/config/impls/configuration.rs
  • src/database/database.rs
  • src/database/impls/database_connector.rs
  • src/database/impls/database_connector_mysql.rs
  • src/database/impls/database_connector_pgsql.rs
  • src/database/impls/database_connector_sqlite.rs
  • src/database/impls/query_builder.rs
  • src/http/http.rs
  • src/rtctorrent_bridge/impls/rtc_torrent_bridge.rs
  • src/security/security.rs
  • src/ssl/impls/certificate_store.rs
  • src/ssl/impls/dynamic_certificate_resolver.rs
  • src/ssl/impls/server_identifier.rs
  • src/ssl/ssl.rs
  • src/stats/impls/torrent_tracker.rs
  • src/tracker/impls/announce_entry.rs
  • src/tracker/impls/cleanup_stats.rs
  • src/tracker/impls/peer_id.rs
  • src/tracker/impls/rtc_data.rs
  • src/tracker/impls/torrent_counts.rs
  • src/tracker/impls/torrent_entry.rs
  • src/tracker/impls/torrent_peer.rs
  • src/tracker/impls/torrent_sharding.rs
  • src/tracker/impls/torrent_tracker.rs
  • src/tracker/impls/torrent_tracker_cert_gen.rs
  • src/tracker/impls/torrent_tracker_export.rs
  • src/tracker/impls/torrent_tracker_handlers.rs
  • src/tracker/impls/torrent_tracker_import.rs
  • src/tracker/impls/torrent_tracker_keys.rs
  • src/tracker/impls/torrent_tracker_keys_updates.rs
  • src/tracker/impls/torrent_tracker_peers.rs
  • src/tracker/impls/torrent_tracker_rtctorrent.rs
  • src/tracker/impls/torrent_tracker_torrents.rs
  • src/tracker/impls/torrent_tracker_torrents_blacklist.rs
  • src/tracker/impls/torrent_tracker_torrents_blacklist_updates.rs
  • src/tracker/impls/torrent_tracker_torrents_updates.rs
  • src/tracker/impls/torrent_tracker_torrents_whitelist.rs
  • src/tracker/impls/torrent_tracker_torrents_whitelist_updates.rs
  • src/tracker/impls/torrent_tracker_users.rs
  • src/tracker/impls/torrent_tracker_users_updates.rs
  • src/tracker/structs/torrent_tracker.rs
  • src/udp/impls/batch_recv.rs
  • src/udp/impls/io_uring_recv.rs
  • src/udp/impls/parse_pool.rs
  • src/udp/impls/request.rs
  • src/udp/impls/request_parse_error.rs
  • src/udp/impls/response.rs
  • src/udp/impls/rio_recv.rs
  • src/udp/impls/simple_proxy_protocol.rs
  • src/udp/impls/udp_server.rs
  • src/udp/udp.rs
  • src/utils/sentry_tracing.rs
  • src/websocket/impls/cluster_connection.rs
  • src/websocket/impls/cluster_request.rs
  • src/websocket/impls/cluster_response.rs
  • src/websocket/impls/handshake_request.rs
  • src/websocket/impls/handshake_response.rs
  • src/websocket/impls/slave_client_state.rs
  • src/websocket/websocket.rs
  • tests/tracker_tests.rs
  • torrust-actix.desktop

Comment thread src/api/api_users.rs
Comment thread src/api/api_users.rs Outdated
Comment thread src/database/impls/database_connector_pgsql.rs
Comment thread src/database/impls/database_connector_sqlite.rs
Comment thread src/tracker/impls/torrent_tracker_torrents_blacklist.rs
Comment thread src/tracker/impls/torrent_tracker_torrents_whitelist.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

♻️ Duplicate comments (2)
src/tracker/impls/torrent_tracker_torrents_whitelist.rs (1)

12-25: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win

Load failure is now logged but startup still doesn't fail closed.

This addresses half of the earlier request (logging), but the tracker still proceeds with an empty in-memory whitelist on DB failure — as the new doc comment itself states. With whitelist_enabled, check_whitelist will then reject every legitimate announce, silently degrading the tracker into rejecting all traffic instead of failing fast at boot. The original ask was to make startup fail closed on this error.

🩺 Proposed fix to fail closed on load failure
     pub async fn load_whitelist(&self, tracker: Arc<TorrentTracker>)
     {
         match self.sqlx.load_whitelist(tracker).await {
             Ok(whitelist) => {
                 info!("Loaded {whitelist} whitelists");
             }
             Err(e) => {
                 error!("Unable to load the whitelist from the database: {e}");
+                std::process::exit(1);
             }
         }
     }

Please verify how load_whitelist is invoked at startup (likely in main.rs, not in this file set) to confirm whether an exit(1) here or a propagated Result is the preferred fail-closed mechanism.

🤖 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 `@src/tracker/impls/torrent_tracker_torrents_whitelist.rs` around lines 12 -
25, load_whitelist currently logs database errors but lets startup continue with
an empty whitelist, which causes whitelist_enabled to reject valid announces
instead of failing closed. Update
TorrentTrackerTorrentsWhitelist::load_whitelist so the database load failure is
propagated or otherwise causes startup to abort, and adjust the startup caller
that invokes load_whitelist to stop the process on error rather than proceeding
with an empty in-memory whitelist. Keep the existing logging, but ensure the
failure path is fatal instead of silently continuing.
src/api/api_users.rs (1)

188-189: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

DELETE endpoints still diverge from GET/POST identifier semantics.

This only documents the existing behavior — GET/POST accept a raw id/UUID and hash it internally, while DELETE still expects the caller to supply the pre-computed 40-character hex hash. That asymmetry (and the underlying implementation) was flagged previously as confusing/inconsistent API design; documenting it doesn't resolve the underlying mismatch, it only records it.

Also applies to: 222-223

🤖 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 `@src/api/api_users.rs` around lines 188 - 189, The DELETE user route still
uses a different identifier contract than the GET/POST paths, so align the
DELETE handler’s lookup logic with the same raw id/UUID handling used elsewhere
instead of requiring callers to pass a precomputed 40-character hash. Update the
DELETE route implementation and any related docs/comments around the user delete
endpoint so the identifier semantics are consistent across the API, using the
same hashing behavior already applied in the GET/POST flow.
🤖 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.

Duplicate comments:
In `@src/api/api_users.rs`:
- Around line 188-189: The DELETE user route still uses a different identifier
contract than the GET/POST paths, so align the DELETE handler’s lookup logic
with the same raw id/UUID handling used elsewhere instead of requiring callers
to pass a precomputed 40-character hash. Update the DELETE route implementation
and any related docs/comments around the user delete endpoint so the identifier
semantics are consistent across the API, using the same hashing behavior already
applied in the GET/POST flow.

In `@src/tracker/impls/torrent_tracker_torrents_whitelist.rs`:
- Around line 12-25: load_whitelist currently logs database errors but lets
startup continue with an empty whitelist, which causes whitelist_enabled to
reject valid announces instead of failing closed. Update
TorrentTrackerTorrentsWhitelist::load_whitelist so the database load failure is
propagated or otherwise causes startup to abort, and adjust the startup caller
that invokes load_whitelist to stop the process on error rather than proceeding
with an empty in-memory whitelist. Keep the existing logging, but ensure the
failure path is fatal instead of silently continuing.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 2138cacd-33f2-489b-8f49-21052af80355

📥 Commits

Reviewing files that changed from the base of the PR and between 85b9c15 and 0f520e7.

📒 Files selected for processing (27)
  • src/api/api.rs
  • src/api/api_certificate.rs
  • src/api/api_users.rs
  • src/api/api_whitelists.rs
  • src/cache/impls/cache_engine.rs
  • src/config/impls/configuration.rs
  • src/database/impls/database_connector.rs
  • src/database/impls/database_connector_mysql.rs
  • src/database/impls/database_connector_pgsql.rs
  • src/database/impls/database_connector_sqlite.rs
  • src/http/http.rs
  • src/rtctorrent_bridge/impls/rtc_torrent_bridge.rs
  • src/security/security.rs
  • src/ssl/impls/certificate_store.rs
  • src/ssl/impls/dynamic_certificate_resolver.rs
  • src/tracker/impls/torrent_tracker.rs
  • src/tracker/impls/torrent_tracker_export.rs
  • src/tracker/impls/torrent_tracker_handlers.rs
  • src/tracker/impls/torrent_tracker_keys.rs
  • src/tracker/impls/torrent_tracker_keys_updates.rs
  • src/tracker/impls/torrent_tracker_torrents_blacklist.rs
  • src/tracker/impls/torrent_tracker_torrents_blacklist_updates.rs
  • src/tracker/impls/torrent_tracker_torrents_whitelist.rs
  • src/tracker/impls/torrent_tracker_torrents_whitelist_updates.rs
  • src/tracker/impls/torrent_tracker_users_updates.rs
  • src/udp/impls/response.rs
  • src/udp/udp.rs
✅ Files skipped from review due to trivial changes (17)
  • src/api/api_certificate.rs
  • src/cache/impls/cache_engine.rs
  • src/udp/impls/response.rs
  • src/ssl/impls/dynamic_certificate_resolver.rs
  • src/rtctorrent_bridge/impls/rtc_torrent_bridge.rs
  • src/ssl/impls/certificate_store.rs
  • src/udp/udp.rs
  • src/tracker/impls/torrent_tracker_torrents_blacklist_updates.rs
  • src/tracker/impls/torrent_tracker_export.rs
  • src/tracker/impls/torrent_tracker_torrents_blacklist.rs
  • src/tracker/impls/torrent_tracker_torrents_whitelist_updates.rs
  • src/tracker/impls/torrent_tracker_users_updates.rs
  • src/api/api.rs
  • src/tracker/impls/torrent_tracker_keys.rs
  • src/config/impls/configuration.rs
  • src/tracker/impls/torrent_tracker_keys_updates.rs
  • src/database/impls/database_connector.rs
🚧 Files skipped from review as they are similar to previous changes (5)
  • src/tracker/impls/torrent_tracker.rs
  • src/tracker/impls/torrent_tracker_handlers.rs
  • src/security/security.rs
  • src/http/http.rs
  • src/api/api_whitelists.rs

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/api/api_users.rs (1)

231-246: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Hoist loop-invariant work out of the per-id loop.

The persistent-mode boolean on Line 233 and the empty_user template (Lines 234-244) are identical for every id, yet they are recomputed on each iteration. Evaluating the flag once before the loop and building the template with .clone() inside keeps the batch path cheaper and clearer.

♻️ Suggested hoist
     let mut users_output = HashMap::with_capacity(ids.len());
+    let persistent = data.torrent_tracker.config.database_structure.users.persistent
+        .unwrap_or(data.torrent_tracker.config.database.persistent);
     for id in ids {
         let id_hash = UserId(hash_id(&id));
-        if data.torrent_tracker.config.database_structure.users.persistent.unwrap_or(data.torrent_tracker.config.database.persistent) {
+        if persistent {
             let empty_user = UserEntryItem {
🤖 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 `@src/api/api_users.rs` around lines 231 - 246, Hoist the loop-invariant
persistent-mode check and the empty user template out of the per-id loop in the
user deletion path. In the loop that iterates over ids in api_users.rs, compute
the config boolean once before entering the loop, build the UserEntryItem
template once, and then reuse it inside the loop with a clone when calling
data.torrent_tracker.add_user_update with UpdatesAction::Remove. Keep the
existing behavior in the add_user_update flow, but avoid recomputing the same
values for every id.
🤖 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.

Nitpick comments:
In `@src/api/api_users.rs`:
- Around line 231-246: Hoist the loop-invariant persistent-mode check and the
empty user template out of the per-id loop in the user deletion path. In the
loop that iterates over ids in api_users.rs, compute the config boolean once
before entering the loop, build the UserEntryItem template once, and then reuse
it inside the loop with a clone when calling
data.torrent_tracker.add_user_update with UpdatesAction::Remove. Keep the
existing behavior in the add_user_update flow, but avoid recomputing the same
values for every id.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ffb644c4-a613-4097-8bc0-847bca9eb190

📥 Commits

Reviewing files that changed from the base of the PR and between 0f520e7 and 559c201.

📒 Files selected for processing (2)
  • src/api/api_users.rs
  • src/tracker/impls/torrent_tracker_torrents_whitelist.rs

@Power2All Power2All merged commit cc1b55e into master Jul 3, 2026
2 checks passed
@Power2All Power2All deleted the v4.2.15 branch July 3, 2026 14:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant