Skip to content

Commit a7ceb0f

Browse files
committed
refactor: [#1140] move http tracker logic to http-protocol and primitives packages
- Generic logic for http tracker has bben moved to http-protocol package (bittorrent-http-protocol crate). - Generic tracker types like AnnounceData and ScrapeData have been moved to the primitives package (torrust-tracker-primitives crate). This has also a desiderable side effect: generic re-usable domain logic has been decoupled from Axum framework.
1 parent f508ef7 commit a7ceb0f

35 files changed

+235
-238
lines changed

Cargo.lock

+9-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

-2
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ http-body = "1"
5858
hyper = "1"
5959
hyper-util = { version = "0", features = ["http1", "http2", "tokio"] }
6060
lazy_static = "1"
61-
multimap = "0"
6261
parking_lot = "0"
6362
percent-encoding = "2"
6463
pin-project-lite = "0"
@@ -79,7 +78,6 @@ thiserror = "2"
7978
tokio = { version = "1", features = ["macros", "net", "rt-multi-thread", "signal", "sync"] }
8079
torrust-tracker-clock = { version = "3.0.0-develop", path = "packages/clock" }
8180
torrust-tracker-configuration = { version = "3.0.0-develop", path = "packages/configuration" }
82-
torrust-tracker-contrib-bencode = { version = "3.0.0-develop", path = "contrib/bencode" }
8381
torrust-tracker-located-error = { version = "3.0.0-develop", path = "packages/located-error" }
8482
torrust-tracker-primitives = { version = "3.0.0-develop", path = "packages/primitives" }
8583
torrust-tracker-torrent-repository = { version = "3.0.0-develop", path = "packages/torrent-repository" }

packages/http-protocol/Cargo.toml

+8
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,13 @@ version.workspace = true
1717
[dependencies]
1818
aquatic_udp_protocol = "0"
1919
bittorrent-primitives = "0.1.0"
20+
derive_more = { version = "1", features = ["as_ref", "constructor", "from"] }
21+
multimap = "0"
2022
percent-encoding = "2"
23+
serde = { version = "1", features = ["derive"] }
24+
serde_bencode = "0"
25+
thiserror = "2"
26+
torrust-tracker-configuration = { version = "3.0.0-develop", path = "../configuration" }
27+
torrust-tracker-contrib-bencode = { version = "3.0.0-develop", path = "../../contrib/bencode" }
28+
torrust-tracker-located-error = { version = "3.0.0-develop", path = "../located-error" }
2129
torrust-tracker-primitives = { version = "3.0.0-develop", path = "../primitives" }

packages/http-protocol/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
//! Primitive types and function for `BitTorrent` HTTP trackers.
22
pub mod percent_encoding;
3+
pub mod v1;

packages/http-protocol/src/v1/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
pub mod query;
2+
pub mod requests;
3+
pub mod responses;
4+
pub mod services;

src/servers/http/v1/query.rs packages/http-protocol/src/v1/query.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -224,7 +224,7 @@ impl std::fmt::Display for FieldValuePairSet {
224224
mod tests {
225225

226226
mod url_query {
227-
use crate::servers::http::v1::query::Query;
227+
use crate::v1::query::Query;
228228

229229
#[test]
230230
fn should_parse_the_query_params_from_an_url_query_string() {
@@ -277,7 +277,7 @@ mod tests {
277277
}
278278

279279
mod should_allow_more_than_one_value_for_the_same_param {
280-
use crate::servers::http::v1::query::Query;
280+
use crate::v1::query::Query;
281281

282282
#[test]
283283
fn instantiated_from_a_vector() {
@@ -299,7 +299,7 @@ mod tests {
299299
}
300300

301301
mod should_be_displayed {
302-
use crate::servers::http::v1::query::Query;
302+
use crate::v1::query::Query;
303303

304304
#[test]
305305
fn with_one_param() {
@@ -320,7 +320,7 @@ mod tests {
320320
}
321321

322322
mod param_name_value_pair {
323-
use crate::servers::http::v1::query::NameValuePair;
323+
use crate::v1::query::NameValuePair;
324324

325325
#[test]
326326
fn should_parse_a_single_query_param() {

src/servers/http/v1/requests/announce.rs packages/http-protocol/src/v1/requests/announce.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ use std::panic::Location;
66
use std::str::FromStr;
77

88
use aquatic_udp_protocol::{NumberOfBytes, PeerId};
9-
use bittorrent_http_protocol::percent_encoding::{percent_decode_info_hash, percent_decode_peer_id};
109
use bittorrent_primitives::info_hash::{self, InfoHash};
1110
use thiserror::Error;
1211
use torrust_tracker_located_error::{Located, LocatedError};
1312
use torrust_tracker_primitives::peer;
1413

15-
use crate::servers::http::v1::query::{ParseQueryError, Query};
16-
use crate::servers::http::v1::responses;
14+
use crate::percent_encoding::{percent_decode_info_hash, percent_decode_peer_id};
15+
use crate::v1::query::{ParseQueryError, Query};
16+
use crate::v1::responses;
1717

1818
// Query param names
1919
const INFO_HASH: &str = "info_hash";
@@ -381,8 +381,8 @@ mod tests {
381381
use aquatic_udp_protocol::{NumberOfBytes, PeerId};
382382
use bittorrent_primitives::info_hash::InfoHash;
383383

384-
use crate::servers::http::v1::query::Query;
385-
use crate::servers::http::v1::requests::announce::{
384+
use crate::v1::query::Query;
385+
use crate::v1::requests::announce::{
386386
Announce, Compact, Event, COMPACT, DOWNLOADED, EVENT, INFO_HASH, LEFT, NUMWANT, PEER_ID, PORT, UPLOADED,
387387
};
388388

@@ -452,8 +452,8 @@ mod tests {
452452

453453
mod when_it_is_instantiated_from_the_url_query_params {
454454

455-
use crate::servers::http::v1::query::Query;
456-
use crate::servers::http::v1::requests::announce::{
455+
use crate::v1::query::Query;
456+
use crate::v1::requests::announce::{
457457
Announce, COMPACT, DOWNLOADED, EVENT, INFO_HASH, LEFT, NUMWANT, PEER_ID, PORT, UPLOADED,
458458
};
459459

src/servers/http/v1/requests/scrape.rs packages/http-protocol/src/v1/requests/scrape.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,13 @@
33
//! Data structures and logic for parsing the `scrape` request.
44
use std::panic::Location;
55

6-
use bittorrent_http_protocol::percent_encoding::percent_decode_info_hash;
76
use bittorrent_primitives::info_hash::{self, InfoHash};
87
use thiserror::Error;
98
use torrust_tracker_located_error::{Located, LocatedError};
109

11-
use crate::servers::http::v1::query::Query;
12-
use crate::servers::http::v1::responses;
10+
use crate::percent_encoding::percent_decode_info_hash;
11+
use crate::v1::query::Query;
12+
use crate::v1::responses;
1313

1414
// Query param names
1515
const INFO_HASH: &str = "info_hash";
@@ -86,8 +86,8 @@ mod tests {
8686

8787
use bittorrent_primitives::info_hash::InfoHash;
8888

89-
use crate::servers::http::v1::query::Query;
90-
use crate::servers::http::v1::requests::scrape::{Scrape, INFO_HASH};
89+
use crate::v1::query::Query;
90+
use crate::v1::requests::scrape::{Scrape, INFO_HASH};
9191

9292
#[test]
9393
fn should_be_instantiated_from_the_url_query_with_only_one_infohash() {
@@ -107,8 +107,8 @@ mod tests {
107107

108108
mod when_it_is_instantiated_from_the_url_query_params {
109109

110-
use crate::servers::http::v1::query::Query;
111-
use crate::servers::http::v1::requests::scrape::{Scrape, INFO_HASH};
110+
use crate::v1::query::Query;
111+
use crate::v1::requests::scrape::{Scrape, INFO_HASH};
112112

113113
#[test]
114114
fn it_should_fail_if_the_query_does_not_include_the_info_hash_param() {

src/servers/http/v1/responses/announce.rs packages/http-protocol/src/v1/responses/announce.rs

+7-29
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
1-
//! `Announce` response for the HTTP tracker [`announce`](crate::servers::http::v1::requests::announce::Announce) request.
1+
//! `Announce` response for the HTTP tracker [`announce`](bittorrent_http_protocol::v1::requests::announce::Announce) request.
22
//!
33
//! Data structures and logic to build the `announce` response.
44
use std::io::Write;
55
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
66

7-
use axum::http::StatusCode;
87
use derive_more::{AsRef, Constructor, From};
98
use torrust_tracker_contrib_bencode::{ben_bytes, ben_int, ben_list, ben_map, BMutAccess, BencodeMut};
9+
use torrust_tracker_primitives::core::AnnounceData;
1010
use torrust_tracker_primitives::peer;
1111

12-
use super::Response;
13-
use crate::core::AnnounceData;
14-
use crate::servers::http::v1::responses;
15-
1612
/// An [`Announce`] response, that can be anything that is convertible from [`AnnounceData`].
1713
///
1814
/// The [`Announce`] can built from any data that implements: [`From<AnnounceData>`] and [`Into<Vec<u8>>`].
@@ -35,7 +31,7 @@ pub struct Announce<E>
3531
where
3632
E: From<AnnounceData> + Into<Vec<u8>>,
3733
{
38-
data: E,
34+
pub data: E,
3935
}
4036

4137
/// Build any [`Announce`] from an [`AnnounceData`].
@@ -45,24 +41,6 @@ impl<E: From<AnnounceData> + Into<Vec<u8>>> From<AnnounceData> for Announce<E> {
4541
}
4642
}
4743

48-
/// Convert any Announce [`Announce`] into a [`axum::response::Response`]
49-
impl<E: From<AnnounceData> + Into<Vec<u8>>> axum::response::IntoResponse for Announce<E>
50-
where
51-
Announce<E>: Response,
52-
{
53-
fn into_response(self) -> axum::response::Response {
54-
axum::response::IntoResponse::into_response(self.body().map(|bytes| (StatusCode::OK, bytes)))
55-
}
56-
}
57-
58-
/// Implement the [`Response`] for the [`Announce`].
59-
///
60-
impl<E: From<AnnounceData> + Into<Vec<u8>>> Response for Announce<E> {
61-
fn body(self) -> Result<Vec<u8>, responses::error::Error> {
62-
Ok(self.data.into())
63-
}
64-
}
65-
6644
/// Format of the [`Normal`] (Non-Compact) Encoding
6745
pub struct Normal {
6846
complete: i64,
@@ -302,11 +280,11 @@ mod tests {
302280

303281
use aquatic_udp_protocol::PeerId;
304282
use torrust_tracker_configuration::AnnouncePolicy;
283+
use torrust_tracker_primitives::core::AnnounceData;
305284
use torrust_tracker_primitives::peer::fixture::PeerBuilder;
306285
use torrust_tracker_primitives::swarm_metadata::SwarmMetadata;
307286

308-
use crate::core::AnnounceData;
309-
use crate::servers::http::v1::responses::announce::{Announce, Compact, Normal, Response};
287+
use crate::v1::responses::announce::{Announce, Compact, Normal};
310288

311289
// Some ascii values used in tests:
312290
//
@@ -345,7 +323,7 @@ mod tests {
345323
#[test]
346324
fn non_compact_announce_response_can_be_bencoded() {
347325
let response: Announce<Normal> = setup_announce_data().into();
348-
let bytes = response.body().expect("it should encode the response");
326+
let bytes = response.data.into();
349327

350328
// cspell:disable-next-line
351329
let expected_bytes = b"d8:completei333e10:incompletei444e8:intervali111e12:min intervali222e5:peersld2:ip15:105.105.105.1057:peer id20:-qB000000000000000014:porti28784eed2:ip39:6969:6969:6969:6969:6969:6969:6969:69697:peer id20:-qB000000000000000024:porti28784eeee";
@@ -359,7 +337,7 @@ mod tests {
359337
#[test]
360338
fn compact_announce_response_can_be_bencoded() {
361339
let response: Announce<Compact> = setup_announce_data().into();
362-
let bytes = response.body().expect("it should encode the response");
340+
let bytes = response.data.into();
363341

364342
let expected_bytes =
365343
// cspell:disable-next-line

src/servers/http/v1/responses/error.rs packages/http-protocol/src/v1/responses/error.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111
//! > **NOTICE**: error responses are bencoded and always have a `200 OK` status
1212
//! > code. The official `BitTorrent` specification does not specify the status
1313
//! > code.
14-
use axum::http::StatusCode;
15-
use axum::response::{IntoResponse, Response};
1614
use serde::Serialize;
1715

16+
use crate::v1::services::peer_ip_resolver::PeerIpResolutionError;
17+
1818
/// `Error` response for the [`HTTP tracker`](crate::servers::http).
1919
#[derive(Serialize, Debug, PartialEq)]
2020
pub struct Error {
@@ -47,9 +47,11 @@ impl Error {
4747
}
4848
}
4949

50-
impl IntoResponse for Error {
51-
fn into_response(self) -> Response {
52-
(StatusCode::OK, self.write()).into_response()
50+
impl From<PeerIpResolutionError> for Error {
51+
fn from(err: PeerIpResolutionError) -> Self {
52+
Self {
53+
failure_reason: format!("Error resolving peer IP: {err}"),
54+
}
5355
}
5456
}
5557

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
//! HTTP responses for the HTTP tracker.
2+
//!
3+
//! Refer to the generic [HTTP server documentation](crate::servers::http) for
4+
//! more information about the HTTP tracker.
5+
pub mod announce;
6+
pub mod error;
7+
pub mod scrape;
8+
9+
pub use announce::{Announce, Compact, Normal};

src/servers/http/v1/responses/scrape.rs packages/http-protocol/src/v1/responses/scrape.rs

+4-13
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,10 @@
1-
//! `Scrape` response for the HTTP tracker [`scrape`](crate::servers::http::v1::requests::scrape::Scrape) request.
1+
//! `Scrape` response for the HTTP tracker [`scrape`](bittorrent_http_protocol::v1::requests::scrape::Scrape) request.
22
//!
33
//! Data structures and logic to build the `scrape` response.
44
use std::borrow::Cow;
55

6-
use axum::http::StatusCode;
7-
use axum::response::{IntoResponse, Response};
86
use torrust_tracker_contrib_bencode::{ben_int, ben_map, BMutAccess};
9-
10-
use crate::core::ScrapeData;
7+
use torrust_tracker_primitives::core::ScrapeData;
118

129
/// The `Scrape` response for the HTTP tracker.
1310
///
@@ -82,21 +79,15 @@ impl From<ScrapeData> for Bencoded {
8279
}
8380
}
8481

85-
impl IntoResponse for Bencoded {
86-
fn into_response(self) -> Response {
87-
(StatusCode::OK, self.body()).into_response()
88-
}
89-
}
90-
9182
#[cfg(test)]
9283
mod tests {
9384

9485
mod scrape_response {
9586
use bittorrent_primitives::info_hash::InfoHash;
87+
use torrust_tracker_primitives::core::ScrapeData;
9688
use torrust_tracker_primitives::swarm_metadata::SwarmMetadata;
9789

98-
use crate::core::ScrapeData;
99-
use crate::servers::http::v1::responses::scrape::Bencoded;
90+
use crate::v1::responses::scrape::Bencoded;
10091

10192
fn sample_scrape_data() -> ScrapeData {
10293
let info_hash = InfoHash::from_bytes(&[0x69; 20]);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pub mod peer_ip_resolver;

src/servers/http/v1/services/peer_ip_resolver.rs packages/http-protocol/src/v1/services/peer_ip_resolver.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ mod tests {
142142
use std::str::FromStr;
143143

144144
use super::invoke;
145-
use crate::servers::http::v1::services::peer_ip_resolver::{ClientIpSources, PeerIpResolutionError};
145+
use crate::v1::services::peer_ip_resolver::{ClientIpSources, PeerIpResolutionError};
146146

147147
#[test]
148148
fn it_should_get_the_peer_ip_from_the_connection_info() {
@@ -181,7 +181,7 @@ mod tests {
181181
use std::net::IpAddr;
182182
use std::str::FromStr;
183183

184-
use crate::servers::http::v1::services::peer_ip_resolver::{invoke, ClientIpSources, PeerIpResolutionError};
184+
use crate::v1::services::peer_ip_resolver::{invoke, ClientIpSources, PeerIpResolutionError};
185185

186186
#[test]
187187
fn it_should_get_the_peer_ip_from_the_right_most_ip_in_the_x_forwarded_for_header() {

packages/primitives/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ serde = { version = "1", features = ["derive"] }
2323
tdyne-peer-id = "1"
2424
tdyne-peer-id-registry = "0"
2525
thiserror = "2"
26+
torrust-tracker-configuration = { version = "3.0.0-develop", path = "../configuration" }
2627
zerocopy = "0.7"

0 commit comments

Comments
 (0)