Subissue of EPIC #1669 — Overhaul: Packages
Note: this is a production code decoupling (unlike the server environment.rs relocations which only move test infrastructure). It changes rest-api-core containers/services and axum-rest-api-server handlers/routes to use trait abstractions instead of concrete UDP types.
Implemented after the environment.rs relocations (subissues SI-23/SI-24/SI-25) — those were test infrastructure moves, while this is a production dependency decoupling.
Problem
Two packages import concrete UDP types, forcing runtime dependencies on udp-server and udp-core:
rest-api-core
Production imports in src/container.rs and src/statistics/services.rs:
| Import |
Location |
BanService |
container.rs |
UdpTrackerCoreContainer |
container.rs |
UdpTrackerServerContainer |
container.rs |
udp_stats_repository types (Repository) |
container.rs |
BanService |
statistics/services |
udp_server::statistics |
statistics/services |
Test-only imports (follow from production deps):
| Import |
Concern |
MAX_CONNECTION_ID_ERRORS_PER_IP |
Test ban init constant |
BanService (concrete) |
Test BanService constructor |
axum-rest-api-server
Production imports in src/v1/context/stats/handlers.rs:
| Import |
Concern |
BanService |
Handler state type |
torrust_tracker_udp_server::statistics::repository::Repository |
Handler state type (get_stats) |
torrust_tracker_udp_core::statistics::repository::Repository |
Handler state type (get_metrics) |
Production references in src/v1/context/stats/routes.rs:
| Reference |
Concern |
http_api_container.ban_service |
Passed into handler state |
http_api_container.udp_server_stats_repository |
Passed into handler state |
http_api_container.udp_core_stats_repository |
Passed into handler state |
Consequence
Both rest-api-core/Cargo.toml and axum-rest-api-server/Cargo.toml list udp-server and udp-core as runtime dependencies. After the decoupling, they can be demoted to dev-dependencies (or removed entirely) in both files.
Scope
1. Add decisions to DECISIONS.md
Record the next DEC number with the chosen approaches.
2. Trait extraction
Define shared trait abstractions for the three concrete UDP types that leak into REST code:
| Trait |
Extracted from |
Host location (suggested) |
BanningService (or similar) |
BanService (concrete struct) |
tracker-core or new primitives submodule |
UdpCoreStatsRepository |
udp_tracker_core::statistics::repository::Repository |
tracker-core or new primitives submodule |
UdpServerStatsRepository |
udp_server::statistics::repository::Repository |
tracker-core or new primitives submodule |
Each trait exposes only the methods the REST layer actually calls. This keeps the interface minimal and avoids leaking UDP internals.
3. Turn MAX_CONNECTION_ID_ERRORS_PER_IP into a configuration option
Move MAX_CONNECTION_ID_ERRORS_PER_IP from a hardcoded pub const in udp_core to a new config field in the UdpTracker configuration struct (packages/configuration/src/v2_0_0/udp_tracker.rs):
- Add field
pub max_connection_id_errors_per_ip: u32 with default 10 via #[serde(default)].
UdpTrackerCoreContainer already holds Arc<UdpTracker>, so container.rs reads udp_tracker_config.max_connection_id_errors_per_ip instead of the constant.
- Tests in
rest-api-core use a literal 10 (or a local test constant) instead of importing MAX_CONNECTION_ID_ERRORS_PER_IP from udp_core.
4. Update rest-api-core
src/container.rs: TrackerHttpApiCoreContainer stores Arc<dyn BanningService> instead of Arc<RwLock<BanService>>, and Arc<dyn UdpStatsRepository> for stats repos. UdpTrackerCoreContainer and UdpTrackerServerContainer are no longer imported.
src/statistics/services.rs: function signatures use trait references instead of concrete udp_server_statistics::repository::Repository.
- Test code: instantiate concrete types via
udp_core / udp_server (dev-deps).
Cargo.toml: demote udp-server and udp-core to [dev-dependencies].
5. Update udp-server and udp-core
- Implement the new traits on their existing concrete types.
- The
BanService struct gets impl BanningService for BanService.
6. Update axum-rest-api-server handlers and routes
src/v1/context/stats/handlers.rs: State tuples use Arc<dyn BanningService> and Arc<dyn UdpStatsRepository> instead of concrete types. The use imports for UDP concrete types are removed.
src/v1/context/stats/routes.rs: Routes pass trait objects from TrackerHttpApiCoreContainer fields (already trait objects after step 4).
Cargo.toml: demote udp-server and udp-core to [dev-dependencies].
7. Clean up
- Run
cargo machete to verify unused deps are gone from both Cargo.tomls.
- Verify
linter all and cargo test --workspace.
Acceptance Criteria
rest-api-core/Cargo.toml has no udp-server or udp-core runtime dependency.
axum-rest-api-server/Cargo.toml has no udp-server or udp-core runtime dependency.
rest-api-core/src/ imports only trait abstractions from UDP packages, not concrete types.
axum-rest-api-server/src/v1/context/stats/ uses trait objects in handler state tuples and routes, not concrete UDP types.
cargo test --workspace passes.
cargo machete passes.
linter all passes.
Out of Scope
- Extracting any UDP package to a standalone repository.
- Changing the HTTP tracker side of the REST layer.
- Relocating test environments (already done in SI-23/SI-24/SI-25).
Subissue of EPIC #1669 — Overhaul: Packages
Note: this is a production code decoupling (unlike the server
environment.rsrelocations which only move test infrastructure). It changesrest-api-corecontainers/services andaxum-rest-api-serverhandlers/routes to use trait abstractions instead of concrete UDP types.Implemented after the
environment.rsrelocations (subissues SI-23/SI-24/SI-25) — those were test infrastructure moves, while this is a production dependency decoupling.Problem
Two packages import concrete UDP types, forcing runtime dependencies on
udp-serverandudp-core:rest-api-coreProduction imports in
src/container.rsandsrc/statistics/services.rs:BanServicecontainer.rsUdpTrackerCoreContainercontainer.rsUdpTrackerServerContainercontainer.rsudp_stats_repositorytypes (Repository)container.rsBanServicestatistics/servicesudp_server::statisticsstatistics/servicesTest-only imports (follow from production deps):
MAX_CONNECTION_ID_ERRORS_PER_IPBanService(concrete)axum-rest-api-serverProduction imports in
src/v1/context/stats/handlers.rs:BanServicetorrust_tracker_udp_server::statistics::repository::Repositorytorrust_tracker_udp_core::statistics::repository::RepositoryProduction references in
src/v1/context/stats/routes.rs:http_api_container.ban_servicehttp_api_container.udp_server_stats_repositoryhttp_api_container.udp_core_stats_repositoryConsequence
Both
rest-api-core/Cargo.tomlandaxum-rest-api-server/Cargo.tomllistudp-serverandudp-coreas runtime dependencies. After the decoupling, they can be demoted to dev-dependencies (or removed entirely) in both files.Scope
1. Add decisions to DECISIONS.md
Record the next DEC number with the chosen approaches.
2. Trait extraction
Define shared trait abstractions for the three concrete UDP types that leak into REST code:
BanningService(or similar)BanService(concrete struct)tracker-coreor newprimitivessubmoduleUdpCoreStatsRepositoryudp_tracker_core::statistics::repository::Repositorytracker-coreor newprimitivessubmoduleUdpServerStatsRepositoryudp_server::statistics::repository::Repositorytracker-coreor newprimitivessubmoduleEach trait exposes only the methods the REST layer actually calls. This keeps the interface minimal and avoids leaking UDP internals.
3. Turn
MAX_CONNECTION_ID_ERRORS_PER_IPinto a configuration optionMove
MAX_CONNECTION_ID_ERRORS_PER_IPfrom a hardcodedpub constinudp_coreto a new config field in theUdpTrackerconfiguration struct (packages/configuration/src/v2_0_0/udp_tracker.rs):pub max_connection_id_errors_per_ip: u32with default10via#[serde(default)].UdpTrackerCoreContaineralready holdsArc<UdpTracker>, socontainer.rsreadsudp_tracker_config.max_connection_id_errors_per_ipinstead of the constant.rest-api-coreuse a literal10(or a local test constant) instead of importingMAX_CONNECTION_ID_ERRORS_PER_IPfromudp_core.4. Update
rest-api-coresrc/container.rs:TrackerHttpApiCoreContainerstoresArc<dyn BanningService>instead ofArc<RwLock<BanService>>, andArc<dyn UdpStatsRepository>for stats repos.UdpTrackerCoreContainerandUdpTrackerServerContainerare no longer imported.src/statistics/services.rs: function signatures use trait references instead of concreteudp_server_statistics::repository::Repository.udp_core/udp_server(dev-deps).Cargo.toml: demoteudp-serverandudp-coreto[dev-dependencies].5. Update
udp-serverandudp-coreBanServicestruct getsimpl BanningService for BanService.6. Update
axum-rest-api-serverhandlers and routessrc/v1/context/stats/handlers.rs: State tuples useArc<dyn BanningService>andArc<dyn UdpStatsRepository>instead of concrete types. Theuseimports for UDP concrete types are removed.src/v1/context/stats/routes.rs: Routes pass trait objects fromTrackerHttpApiCoreContainerfields (already trait objects after step 4).Cargo.toml: demoteudp-serverandudp-coreto[dev-dependencies].7. Clean up
cargo macheteto verify unused deps are gone from bothCargo.tomls.linter allandcargo test --workspace.Acceptance Criteria
rest-api-core/Cargo.tomlhas noudp-serverorudp-coreruntime dependency.axum-rest-api-server/Cargo.tomlhas noudp-serverorudp-coreruntime dependency.rest-api-core/src/imports only trait abstractions from UDP packages, not concrete types.axum-rest-api-server/src/v1/context/stats/uses trait objects in handler state tuples and routes, not concrete UDP types.cargo test --workspacepasses.cargo machetepasses.linter allpasses.Out of Scope