Skip to content

Commit 0e672e6

Browse files
committed
Merge #1865: refactor(primitives): move TrackerPolicy, TORRENT_PEERS_LIMIT, and PrivateMode from configuration to primitives
736a535 fix: update stale docs and EPIC follow-up notes after #1859 (Jose Celano) 0e9d18b docs(primitives): add follow-up issue spec #1864 for TORRENT_PEERS_LIMIT review (Jose Celano) d33c695 refactor(primitives): move TrackerPolicy, TORRENT_PEERS_LIMIT, and PrivateMode from configuration to primitives (Jose Celano) Pull request description: ## Summary Closes #1859. Sub-task of #1669. Moves three types out of `torrust-tracker-configuration` and into `torrust-tracker-primitives`: - `TrackerPolicy` struct - `TORRENT_PEERS_LIMIT` constant - `PrivateMode` struct This breaks the dependency that `swarm-coordination-registry` and `torrent-repository-benchmarking` had on the configuration crate purely for these domain types. ## Changes ### New files - `packages/primitives/src/policy.rs` — defines `TrackerPolicy` and `TORRENT_PEERS_LIMIT` - `packages/primitives/src/mode.rs` — defines `PrivateMode` ### Modified files - `packages/primitives/src/lib.rs` — exports new modules - `packages/configuration/src/lib.rs` — removes `TrackerPolicy` and `TORRENT_PEERS_LIMIT` - `packages/configuration/src/v2_0_0/core.rs` — removes `PrivateMode`, updates imports - `packages/tracker-core/src/announce_handler.rs` — updates imports - `packages/tracker-core/src/torrent/repository/in_memory.rs` — updates imports - `packages/tracker-core/src/authentication/mod.rs` — updates imports - `packages/tracker-core/src/authentication/service.rs` — updates imports - `packages/swarm-coordination-registry/src/swarm/coordinator.rs` — updates imports - `packages/swarm-coordination-registry/src/swarm/registry.rs` — updates imports - `packages/swarm-coordination-registry/Cargo.toml` — removes `torrust-tracker-configuration` dependency - `packages/torrent-repository-benchmarking/Cargo.toml` — removes `torrust-tracker-configuration` dependency - All `torrent-repository-benchmarking/src/` and `tests/` files — updates imports ### Follow-up Issue #1864 tracks a follow-up decision on whether `TORRENT_PEERS_LIMIT` should become a runtime config option rather than a compile-time constant. ## Testing - `cargo test --workspace` ✅ all pass - `cargo clippy --workspace -- -D warnings` ✅ no warnings - `linter all` ✅ pass - `cargo machete` ✅ pass ACKs for top commit: josecelano: ACK 736a535 Tree-SHA512: 855bbbd060e198276ecb6504dcbce160cb889bdfbf02bcbb0257756d26ec09e18195fa78428371c2b5b3b7221370b4e8a3396df4d9141dc4b168870d9f8b1e20
2 parents 3d4bf1f + 736a535 commit 0e672e6

38 files changed

Lines changed: 248 additions & 157 deletions

File tree

Cargo.lock

Lines changed: 0 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

docs/issues/open/1859-1669-move-tracker-policy-and-private-mode-to-primitives/ISSUE.md renamed to docs/issues/closed/1859-1669-move-tracker-policy-and-private-mode-to-primitives/ISSUE.md

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
---
22
doc-type: issue
33
issue-type: task
4-
status: open
4+
status: closed
55
priority: p2
66
github-issue: 1859
7-
spec-path: docs/issues/open/1859-1669-move-tracker-policy-and-private-mode-to-primitives/ISSUE.md
7+
spec-path: docs/issues/closed/1859-1669-move-tracker-policy-and-private-mode-to-primitives/ISSUE.md
88
branch: null
99
related-pr: null
1010
last-updated-utc: 2026-06-01 00:00
@@ -118,16 +118,16 @@ list `torrust-tracker-configuration` in their `[dependencies]`.
118118

119119
## Acceptance Criteria
120120

121-
- [ ] `TrackerPolicy` is defined in `torrust-tracker-primitives`
122-
- [ ] `TORRENT_PEERS_LIMIT` is defined in `torrust-tracker-primitives`
123-
- [ ] `PrivateMode` is defined in `torrust-tracker-primitives`
124-
- [ ] All import sites across the workspace import from `torrust-tracker-primitives`
125-
- [ ] `swarm-coordination-registry` no longer lists `torrust-tracker-configuration` as a
121+
- [x] `TrackerPolicy` is defined in `torrust-tracker-primitives`
122+
- [x] `TORRENT_PEERS_LIMIT` is defined in `torrust-tracker-primitives`
123+
- [x] `PrivateMode` is defined in `torrust-tracker-primitives`
124+
- [x] All import sites across the workspace import from `torrust-tracker-primitives`
125+
- [x] `swarm-coordination-registry` no longer lists `torrust-tracker-configuration` as a
126126
direct (non-dev) dependency
127-
- [ ] `torrent-repository-benchmarking` no longer lists `torrust-tracker-configuration`
127+
- [x] `torrent-repository-benchmarking` no longer lists `torrust-tracker-configuration`
128128
as a direct (non-dev) dependency
129-
- [ ] All tests pass (`cargo test --workspace --all-features`)
130-
- [ ] No new clippy warnings
129+
- [x] All tests pass (`cargo test --workspace --all-features`)
130+
- [x] No new clippy warnings
131131

132132
## Out of Scope
133133

docs/issues/open/1669-overhaul-packages/DECISIONS.md

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ and separately move the three domain primitives that are misplaced in it to
7777

7878
### Trade-offs acknowledged
7979

80-
- `swarm-coordination-registry` and `torrent-repository-benchmarking` continue to
81-
depend on `torrust-tracker-configuration` until the domain primitive move is done
82-
in a follow-up task.
80+
- `swarm-coordination-registry` and `torrent-repository-benchmarking` no longer
81+
depend on `torrust-tracker-configuration` after FU-1 (#1859, PR #1865) moved the
82+
domain primitives to `torrust-tracker-primitives`.
8383
- The "build-your-own tracker" use case remains blocked not by the config package
8484
boundary but by the structural design of `tracker-core` (always needing `Core` config)
8585
and the cross-layer coupling in `rest-api-core`. Enabling true service-level
@@ -88,9 +88,12 @@ and separately move the three domain primitives that are misplaced in it to
8888

8989
### Follow-up tasks
9090

91-
- **FU-1**: Move `TrackerPolicy`, `TORRENT_PEERS_LIMIT`, and `PrivateMode` from
92-
`torrust-tracker-configuration` to `torrust-tracker-primitives`. Update all import
93-
sites. Track as a new subissue of EPIC #1669.
91+
- **FU-1** ✅ (#1859, PR #1865): Moved `TrackerPolicy`, `TORRENT_PEERS_LIMIT`, and
92+
`PrivateMode` from `torrust-tracker-configuration` to `torrust-tracker-primitives`.
93+
All import sites updated; `swarm-coordination-registry` and
94+
`torrent-repository-benchmarking` no longer depend on the configuration crate.
95+
Follow-up issue #1864 tracks whether `TORRENT_PEERS_LIMIT` should become a
96+
runtime config option.
9497
- **FU-2**: Evaluate moving `TslConfig` into `axum-server` (already flagged in EPIC.md
9598
as a temporary coupling).
9699
- **FU-3**: Evaluate whether `EnvContainer::initialize` should accept narrower config

docs/issues/open/1669-overhaul-packages/EPIC.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ These packages will remain in the `torrust-tracker` workspace long-term.
207207

208208
> **Note on `torrust-tracker-axum-server`**: This package is classified as `torrust-tracker-` because `tsl.rs` imports `TslConfig` from `torrust-tracker-configuration` and `LocatedError`/`DynError` from `torrust-located-error` (renamed in SI-10, #1823). `TslConfig` remains the temporary tracker-specific dependency: it is a small two-field struct with no tracker-specific logic and could be moved to a generic package. Once that change lands, the package could move to the `torrust-` group as a generic `torrust-axum-server` reusable across the Torrust organisation. A near-identical module already exists in [torrust-index](https://github.com/torrust/torrust-index/blob/develop/src/web/api/server/custom_axum.rs).
209209
210-
[^fu1]: FU-1 (#1859): `TrackerPolicy`, `TORRENT_PEERS_LIMIT`, and `PrivateMode` will be moved here from `torrust-tracker-configuration`. See [DECISIONS.md](./DECISIONS.md) DEC-07.
210+
[^fu1]: FU-1 (#1859): `TrackerPolicy`, `TORRENT_PEERS_LIMIT`, and `PrivateMode` were moved here from `torrust-tracker-configuration` (completed in #1859, PR #1865). See [DECISIONS.md](./DECISIONS.md) DEC-07.
211211

212212
### `torrust/torrust-bittorrent` workspace
213213

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
---
2+
doc-type: issue
3+
issue-type: task
4+
status: open
5+
priority: p3
6+
github-issue: 1864
7+
spec-path: docs/issues/open/1864-1669-review-torrent-peers-limit/ISSUE.md
8+
branch: null
9+
related-pr: null
10+
last-updated-utc: 2026-06-01 00:00
11+
semantic-links:
12+
skill-links:
13+
- create-issue
14+
related-artifacts:
15+
- packages/primitives/src/policy.rs
16+
- packages/tracker-core/src/announce_handler.rs
17+
- packages/tracker-core/src/torrent/repository/in_memory.rs
18+
- packages/swarm-coordination-registry/src/swarm/registry.rs
19+
- packages/axum-http-server/src/lib.rs
20+
- docs/issues/open/1669-overhaul-packages/EPIC.md
21+
- docs/issues/open/1669-overhaul-packages/DECISIONS.md
22+
---
23+
24+
<!-- skill-link: create-issue -->
25+
26+
# Issue #1864 — Review and refactor `TORRENT_PEERS_LIMIT`: hardcoded constant vs. config option
27+
28+
## Goal
29+
30+
Decide whether `TORRENT_PEERS_LIMIT` should remain a global compile-time constant,
31+
be localized to each consuming package, or become a runtime configuration field.
32+
Record the decision and implement it.
33+
34+
This is a follow-up to issue [#1859](../closed/1859-1669-move-tracker-policy-and-private-mode-to-primitives/ISSUE.md)
35+
and a sub-task of EPIC [#1669](../open/1669-overhaul-packages/EPIC.md).
36+
37+
## Background
38+
39+
Issue #1859 moved `TORRENT_PEERS_LIMIT` (`74`) and `TrackerPolicy` from
40+
`torrust-tracker-configuration` into `torrust-tracker-primitives`. That was the
41+
right first step to break the configuration coupling, but the constant is still a
42+
global value shared across multiple packages.
43+
44+
### Current usages
45+
46+
`TORRENT_PEERS_LIMIT` is used in three distinct roles:
47+
48+
1. **Parse-time cap in `From<i32/u32> for PeersWanted`** (announce handler):
49+
50+
```rust
51+
// packages/tracker-core/src/announce_handler.rs
52+
impl From<i32> for PeersWanted {
53+
fn from(value: i32) -> Self {
54+
...
55+
PeersWanted::Only { amount: amount.min(TORRENT_PEERS_LIMIT) }
56+
}
57+
}
58+
```
59+
60+
Because this is a `From` impl, runtime injection is not possible — the limit is
61+
baked in at the trait boundary.
62+
63+
2. **Default return count in `PeersWanted::limit()`** — returned when the client
64+
requested `AsManyAsPossible`.
65+
66+
3. **Query cap in repository methods**`in_memory.rs` and `swarm/registry.rs`
67+
call `get_peers` / `get_swarm_peers` with `TORRENT_PEERS_LIMIT` as the hard
68+
ceiling.
69+
70+
## Questions to Resolve
71+
72+
- Should `TORRENT_PEERS_LIMIT` remain a single global constant, or should each
73+
package define its own local default?
74+
- Should the cap become a runtime configuration option (e.g., a field on
75+
`TrackerPolicy`) so it can be tuned per deployment without recompilation?
76+
- For the `From<i32/u32> for PeersWanted` trait impls, which cannot accept injected
77+
state, is a package-local constant the right answer, or should the impls be
78+
replaced by explicit constructors / free functions that accept the limit?
79+
- If it becomes a config option, where does it sit in the configuration hierarchy
80+
and how is it threaded through to the repository query methods?
81+
82+
## Possible Approaches
83+
84+
| Approach | Pros | Cons |
85+
| ----------------------------------------------------- | ---------------------------------- | ----------------------------------------------------------- |
86+
| Keep global constant in `primitives` (current state) | Simple, no API churn | Magic number, not tunable, couples packages |
87+
| Move constant into each consuming package | Removes cross-package coupling | Duplication, values can drift |
88+
| Add `max_peers_per_announce` field to `TrackerPolicy` | Runtime-tunable, operator-visible | Requires plumbing through announce handler and repositories |
89+
| Replace `From` impls with explicit constructors | Removes implicit global dependency | API change for callers |
90+
91+
## Acceptance Criteria
92+
93+
- [ ] A decision (ADR or `DECISIONS.md` entry under EPIC #1669) recording the chosen
94+
approach and the rationale.
95+
- [ ] If the decision is to change the current design: implementation is complete,
96+
all tests pass, and the doc reference in `axum-http-server/src/lib.rs` is updated.
97+
- [ ] `cargo test --workspace` passes.
98+
- [ ] `linter all` passes.

packages/axum-http-server/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@
7171
//! > is behind a reverse proxy.
7272
//!
7373
//! > **NOTICE**: the maximum number of peers that the tracker can return is
74-
//! > `74`. Defined with a hardcoded const [`TORRENT_PEERS_LIMIT`](torrust_tracker_configuration::TORRENT_PEERS_LIMIT).
74+
//! > `74`. Defined with a hardcoded const [`TORRENT_PEERS_LIMIT`](torrust_tracker_primitives::TORRENT_PEERS_LIMIT).
7575
//! > Refer to [issue 262](https://github.com/torrust/torrust-tracker/issues/262)
7676
//! > for more information about this limitation.
7777
//!

packages/configuration/src/lib.rs

Lines changed: 1 addition & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,12 @@ use std::env;
1313
use std::sync::Arc;
1414

1515
use camino::Utf8PathBuf;
16-
use derive_more::{Constructor, Display};
16+
use derive_more::Display;
1717
use serde::{Deserialize, Serialize};
1818
use serde_with::serde_as;
1919
use thiserror::Error;
2020
use torrust_located_error::{DynError, LocatedError};
2121

22-
/// The maximum number of returned peers for a torrent.
23-
pub const TORRENT_PEERS_LIMIT: usize = 74;
24-
2522
// Environment variables
2623

2724
/// The whole `tracker.toml` file content. It has priority over the config file.
@@ -134,53 +131,6 @@ impl Version {
134131
}
135132
}
136133

137-
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Constructor)]
138-
pub struct TrackerPolicy {
139-
// Cleanup job configuration
140-
/// Maximum time in seconds that a peer can be inactive before being
141-
/// considered an inactive peer. If a peer is inactive for more than this
142-
/// time, it will be removed from the torrent peer list.
143-
#[serde(default = "TrackerPolicy::default_max_peer_timeout")]
144-
pub max_peer_timeout: u32,
145-
146-
/// If enabled the tracker will persist the number of completed downloads.
147-
/// That's how many times a torrent has been downloaded completely.
148-
#[serde(default = "TrackerPolicy::default_persistent_torrent_completed_stat")]
149-
pub persistent_torrent_completed_stat: bool,
150-
151-
/// If enabled, the tracker will remove torrents that have no peers.
152-
/// The clean up torrent job runs every `inactive_peer_cleanup_interval`
153-
/// seconds and it removes inactive peers. Eventually, the peer list of a
154-
/// torrent could be empty and the torrent will be removed if this option is
155-
/// enabled.
156-
#[serde(default = "TrackerPolicy::default_remove_peerless_torrents")]
157-
pub remove_peerless_torrents: bool,
158-
}
159-
160-
impl Default for TrackerPolicy {
161-
fn default() -> Self {
162-
Self {
163-
max_peer_timeout: Self::default_max_peer_timeout(),
164-
persistent_torrent_completed_stat: Self::default_persistent_torrent_completed_stat(),
165-
remove_peerless_torrents: Self::default_remove_peerless_torrents(),
166-
}
167-
}
168-
}
169-
170-
impl TrackerPolicy {
171-
fn default_max_peer_timeout() -> u32 {
172-
900
173-
}
174-
175-
fn default_persistent_torrent_completed_stat() -> bool {
176-
false
177-
}
178-
179-
fn default_remove_peerless_torrents() -> bool {
180-
true
181-
}
182-
}
183-
184134
/// Information required for loading config
185135
#[derive(Debug, Default, Clone)]
186136
pub struct Info {

packages/configuration/src/v2_0_0/core.rs

Lines changed: 2 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
1-
use derive_more::{Constructor, Display};
21
use serde::{Deserialize, Serialize};
3-
use torrust_tracker_primitives::AnnouncePolicy;
2+
use torrust_tracker_primitives::announce::AnnouncePolicy;
3+
use torrust_tracker_primitives::{PrivateMode, TrackerPolicy};
44

55
use super::network::Network;
6-
use crate::TrackerPolicy;
76
use crate::v2_0_0::database::Database;
87
use crate::validator::{SemanticValidationError, Validator};
98

@@ -110,31 +109,6 @@ impl Core {
110109
}
111110
}
112111

113-
/// Configuration specific when the tracker is running in private mode.
114-
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Copy, Constructor, Display)]
115-
pub struct PrivateMode {
116-
/// A flag to disable expiration date for peer keys.
117-
///
118-
/// When true, if the keys is not permanent the expiration date will be
119-
/// ignored. The key will be accepted even if it has expired.
120-
#[serde(default = "PrivateMode::default_check_keys_expiration")]
121-
pub check_keys_expiration: bool,
122-
}
123-
124-
impl Default for PrivateMode {
125-
fn default() -> Self {
126-
Self {
127-
check_keys_expiration: Self::default_check_keys_expiration(),
128-
}
129-
}
130-
}
131-
132-
impl PrivateMode {
133-
fn default_check_keys_expiration() -> bool {
134-
true
135-
}
136-
}
137-
138112
impl Validator for Core {
139113
fn validate(&self) -> Result<(), SemanticValidationError> {
140114
if self.private_mode.is_some() && !self.private {

packages/primitives/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,23 @@
55
//! by the tracker server crate, but also by other crates in the Torrust
66
//! ecosystem.
77
pub mod announce;
8+
pub mod mode;
89
pub mod number_of_bytes;
910
pub mod pagination;
1011
pub mod peer;
1112
pub mod peer_id;
13+
pub mod policy;
1214
pub mod scrape;
1315
pub mod swarm_metadata;
1416

1517
use std::collections::BTreeMap;
1618

1719
pub use announce::{AnnounceData, AnnounceEvent, AnnouncePolicy};
1820
use bittorrent_primitives::info_hash::InfoHash;
21+
pub use mode::PrivateMode;
1922
pub use number_of_bytes::NumberOfBytes;
2023
pub use peer_id::{PeerClient, PeerId};
24+
pub use policy::{TORRENT_PEERS_LIMIT, TrackerPolicy};
2125
pub use scrape::ScrapeData;
2226
/// Duration since the Unix Epoch.
2327
///

packages/primitives/src/mode.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//! Tracker operation mode types.
2+
//!
3+
//! This module contains the [`PrivateMode`] struct, which holds
4+
//! configuration options that apply when the tracker operates in private mode.
5+
use derive_more::{Constructor, Display};
6+
use serde::{Deserialize, Serialize};
7+
8+
/// Configuration that applies when the tracker is operating in private mode.
9+
#[derive(Serialize, Deserialize, PartialEq, Eq, Debug, Clone, Copy, Constructor, Display)]
10+
pub struct PrivateMode {
11+
/// A flag to disable expiration date for peer keys.
12+
///
13+
/// When true, if the keys is not permanent the expiration date will be
14+
/// ignored. The key will be accepted even if it has expired.
15+
#[serde(default = "PrivateMode::default_check_keys_expiration")]
16+
pub check_keys_expiration: bool,
17+
}
18+
19+
impl Default for PrivateMode {
20+
fn default() -> Self {
21+
Self {
22+
check_keys_expiration: Self::default_check_keys_expiration(),
23+
}
24+
}
25+
}
26+
27+
impl PrivateMode {
28+
fn default_check_keys_expiration() -> bool {
29+
true
30+
}
31+
}

0 commit comments

Comments
 (0)