Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor: Move logic to http-protocol and primitives packages #1180

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 9 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ http-body = "1"
hyper = "1"
hyper-util = { version = "0", features = ["http1", "http2", "tokio"] }
lazy_static = "1"
multimap = "0"
parking_lot = "0"
percent-encoding = "2"
pin-project-lite = "0"
Expand All @@ -79,7 +78,6 @@ thiserror = "2"
tokio = { version = "1", features = ["macros", "net", "rt-multi-thread", "signal", "sync"] }
torrust-tracker-clock = { version = "3.0.0-develop", path = "packages/clock" }
torrust-tracker-configuration = { version = "3.0.0-develop", path = "packages/configuration" }
torrust-tracker-contrib-bencode = { version = "3.0.0-develop", path = "contrib/bencode" }
torrust-tracker-located-error = { version = "3.0.0-develop", path = "packages/located-error" }
torrust-tracker-primitives = { version = "3.0.0-develop", path = "packages/primitives" }
torrust-tracker-torrent-repository = { version = "3.0.0-develop", path = "packages/torrent-repository" }
Expand Down
8 changes: 8 additions & 0 deletions packages/http-protocol/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,13 @@ version.workspace = true
[dependencies]
aquatic_udp_protocol = "0"
bittorrent-primitives = "0.1.0"
derive_more = { version = "1", features = ["as_ref", "constructor", "from"] }
multimap = "0"
percent-encoding = "2"
serde = { version = "1", features = ["derive"] }
serde_bencode = "0"
thiserror = "2"
torrust-tracker-configuration = { version = "3.0.0-develop", path = "../configuration" }
torrust-tracker-contrib-bencode = { version = "3.0.0-develop", path = "../../contrib/bencode" }
torrust-tracker-located-error = { version = "3.0.0-develop", path = "../located-error" }
torrust-tracker-primitives = { version = "3.0.0-develop", path = "../primitives" }
1 change: 1 addition & 0 deletions packages/http-protocol/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
//! Primitive types and function for `BitTorrent` HTTP trackers.
pub mod percent_encoding;
pub mod v1;
4 changes: 4 additions & 0 deletions packages/http-protocol/src/v1/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub mod query;
pub mod requests;
pub mod responses;
pub mod services;
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ impl Query {
/// It return `Some(value)` for a URL query param if the param with the
/// input `name` exists. For example:
///
/// ```text
/// use torrust_tracker_lib::servers::http::v1::query::Query;
/// ```rust
/// use bittorrent_http_protocol::v1::query::Query;
///
/// let raw_query = "param1=value1&param2=value2";
///
Expand All @@ -43,8 +43,8 @@ impl Query {
///
/// It returns only the first param value even if it has multiple values:
///
/// ```text
/// use torrust_tracker_lib::servers::http::v1::query::Query;
/// ```rust
/// use bittorrent_http_protocol::v1::query::Query;
///
/// let raw_query = "param1=value1&param1=value2";
///
Expand All @@ -59,8 +59,8 @@ impl Query {

/// Returns all the param values as a vector.
///
/// ```text
/// use torrust_tracker_lib::servers::http::v1::query::Query;
/// ```rust
/// use bittorrent_http_protocol::v1::query::Query;
///
/// let query = "param1=value1&param1=value2".parse::<Query>().unwrap();
///
Expand All @@ -72,8 +72,8 @@ impl Query {
///
/// Returns all the param values as a vector even if it has only one value.
///
/// ```text
/// use torrust_tracker_lib::servers::http::v1::query::Query;
/// ```rust
/// use bittorrent_http_protocol::v1::query::Query;
///
/// let query = "param1=value1".parse::<Query>().unwrap();
///
Expand Down Expand Up @@ -224,7 +224,7 @@ impl std::fmt::Display for FieldValuePairSet {
mod tests {

mod url_query {
use crate::servers::http::v1::query::Query;
use crate::v1::query::Query;

#[test]
fn should_parse_the_query_params_from_an_url_query_string() {
Expand Down Expand Up @@ -277,7 +277,7 @@ mod tests {
}

mod should_allow_more_than_one_value_for_the_same_param {
use crate::servers::http::v1::query::Query;
use crate::v1::query::Query;

#[test]
fn instantiated_from_a_vector() {
Expand All @@ -299,7 +299,7 @@ mod tests {
}

mod should_be_displayed {
use crate::servers::http::v1::query::Query;
use crate::v1::query::Query;

#[test]
fn with_one_param() {
Expand All @@ -320,7 +320,7 @@ mod tests {
}

mod param_name_value_pair {
use crate::servers::http::v1::query::NameValuePair;
use crate::v1::query::NameValuePair;

#[test]
fn should_parse_a_single_query_param() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ use std::panic::Location;
use std::str::FromStr;

use aquatic_udp_protocol::{NumberOfBytes, PeerId};
use bittorrent_http_protocol::percent_encoding::{percent_decode_info_hash, percent_decode_peer_id};
use bittorrent_primitives::info_hash::{self, InfoHash};
use thiserror::Error;
use torrust_tracker_located_error::{Located, LocatedError};
use torrust_tracker_primitives::peer;

use crate::servers::http::v1::query::{ParseQueryError, Query};
use crate::servers::http::v1::responses;
use crate::percent_encoding::{percent_decode_info_hash, percent_decode_peer_id};
use crate::v1::query::{ParseQueryError, Query};
use crate::v1::responses;

// Query param names
const INFO_HASH: &str = "info_hash";
Expand All @@ -29,9 +29,9 @@ const NUMWANT: &str = "numwant";
/// The `Announce` request. Fields use the domain types after parsing the
/// query params of the request.
///
/// ```text
/// ```rust
/// use aquatic_udp_protocol::{NumberOfBytes, PeerId};
/// use torrust_tracker_lib::servers::http::v1::requests::announce::{Announce, Compact, Event};
/// use bittorrent_http_protocol::v1::requests::announce::{Announce, Compact, Event};
/// use bittorrent_primitives::info_hash::InfoHash;
///
/// let request = Announce {
Expand Down Expand Up @@ -381,8 +381,8 @@ mod tests {
use aquatic_udp_protocol::{NumberOfBytes, PeerId};
use bittorrent_primitives::info_hash::InfoHash;

use crate::servers::http::v1::query::Query;
use crate::servers::http::v1::requests::announce::{
use crate::v1::query::Query;
use crate::v1::requests::announce::{
Announce, Compact, Event, COMPACT, DOWNLOADED, EVENT, INFO_HASH, LEFT, NUMWANT, PEER_ID, PORT, UPLOADED,
};

Expand Down Expand Up @@ -452,8 +452,8 @@ mod tests {

mod when_it_is_instantiated_from_the_url_query_params {

use crate::servers::http::v1::query::Query;
use crate::servers::http::v1::requests::announce::{
use crate::v1::query::Query;
use crate::v1::requests::announce::{
Announce, COMPACT, DOWNLOADED, EVENT, INFO_HASH, LEFT, NUMWANT, PEER_ID, PORT, UPLOADED,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@
//! Data structures and logic for parsing the `scrape` request.
use std::panic::Location;

use bittorrent_http_protocol::percent_encoding::percent_decode_info_hash;
use bittorrent_primitives::info_hash::{self, InfoHash};
use thiserror::Error;
use torrust_tracker_located_error::{Located, LocatedError};

use crate::servers::http::v1::query::Query;
use crate::servers::http::v1::responses;
use crate::percent_encoding::percent_decode_info_hash;
use crate::v1::query::Query;
use crate::v1::responses;

// Query param names
const INFO_HASH: &str = "info_hash";
Expand Down Expand Up @@ -86,8 +86,8 @@ mod tests {

use bittorrent_primitives::info_hash::InfoHash;

use crate::servers::http::v1::query::Query;
use crate::servers::http::v1::requests::scrape::{Scrape, INFO_HASH};
use crate::v1::query::Query;
use crate::v1::requests::scrape::{Scrape, INFO_HASH};

#[test]
fn should_be_instantiated_from_the_url_query_with_only_one_infohash() {
Expand All @@ -107,8 +107,8 @@ mod tests {

mod when_it_is_instantiated_from_the_url_query_params {

use crate::servers::http::v1::query::Query;
use crate::servers::http::v1::requests::scrape::{Scrape, INFO_HASH};
use crate::v1::query::Query;
use crate::v1::requests::scrape::{Scrape, INFO_HASH};

#[test]
fn it_should_fail_if_the_query_does_not_include_the_info_hash_param() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,14 @@
//! `Announce` response for the HTTP tracker [`announce`](crate::servers::http::v1::requests::announce::Announce) request.
//! `Announce` response for the HTTP tracker [`announce`](bittorrent_http_protocol::v1::requests::announce::Announce) request.
//!
//! Data structures and logic to build the `announce` response.
use std::io::Write;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};

use axum::http::StatusCode;
use derive_more::{AsRef, Constructor, From};
use torrust_tracker_contrib_bencode::{ben_bytes, ben_int, ben_list, ben_map, BMutAccess, BencodeMut};
use torrust_tracker_primitives::core::AnnounceData;
use torrust_tracker_primitives::peer;

use super::Response;
use crate::core::AnnounceData;
use crate::servers::http::v1::responses;

/// An [`Announce`] response, that can be anything that is convertible from [`AnnounceData`].
///
/// The [`Announce`] can built from any data that implements: [`From<AnnounceData>`] and [`Into<Vec<u8>>`].
Expand All @@ -35,7 +31,7 @@ pub struct Announce<E>
where
E: From<AnnounceData> + Into<Vec<u8>>,
{
data: E,
pub data: E,
}

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

/// Convert any Announce [`Announce`] into a [`axum::response::Response`]
impl<E: From<AnnounceData> + Into<Vec<u8>>> axum::response::IntoResponse for Announce<E>
where
Announce<E>: Response,
{
fn into_response(self) -> axum::response::Response {
axum::response::IntoResponse::into_response(self.body().map(|bytes| (StatusCode::OK, bytes)))
}
}

/// Implement the [`Response`] for the [`Announce`].
///
impl<E: From<AnnounceData> + Into<Vec<u8>>> Response for Announce<E> {
fn body(self) -> Result<Vec<u8>, responses::error::Error> {
Ok(self.data.into())
}
}

/// Format of the [`Normal`] (Non-Compact) Encoding
pub struct Normal {
complete: i64,
Expand Down Expand Up @@ -152,9 +130,9 @@ impl Into<Vec<u8>> for Compact {

/// A [`NormalPeer`], for the [`Normal`] form.
///
/// ```text
/// ```rust
/// use std::net::{IpAddr, Ipv4Addr};
/// use torrust_tracker_lib::servers::http::v1::responses::announce::{Normal, NormalPeer};
/// use bittorrent_http_protocol::v1::responses::announce::{Normal, NormalPeer};
///
/// let peer = NormalPeer {
/// peer_id: *b"-qB00000000000000001",
Expand Down Expand Up @@ -204,9 +182,9 @@ impl From<&NormalPeer> for BencodeMut<'_> {
/// A part from reducing the size of the response, this format does not contain
/// the peer's ID.
///
/// ```text
/// ```rust
/// use std::net::{IpAddr, Ipv4Addr};
/// use torrust_tracker_lib::servers::http::v1::responses::announce::{Compact, CompactPeer, CompactPeerData};
/// use bittorrent_http_protocol::v1::responses::announce::{Compact, CompactPeer, CompactPeerData};
///
/// let peer = CompactPeer::V4(CompactPeerData {
/// ip: Ipv4Addr::new(0x69, 0x69, 0x69, 0x69), // 105.105.105.105
Expand Down Expand Up @@ -302,11 +280,11 @@ mod tests {

use aquatic_udp_protocol::PeerId;
use torrust_tracker_configuration::AnnouncePolicy;
use torrust_tracker_primitives::core::AnnounceData;
use torrust_tracker_primitives::peer::fixture::PeerBuilder;
use torrust_tracker_primitives::swarm_metadata::SwarmMetadata;

use crate::core::AnnounceData;
use crate::servers::http::v1::responses::announce::{Announce, Compact, Normal, Response};
use crate::v1::responses::announce::{Announce, Compact, Normal};

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

// cspell:disable-next-line
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";
Expand All @@ -359,7 +337,7 @@ mod tests {
#[test]
fn compact_announce_response_can_be_bencoded() {
let response: Announce<Compact> = setup_announce_data().into();
let bytes = response.body().expect("it should encode the response");
let bytes = response.data.into();

let expected_bytes =
// cspell:disable-next-line
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
//! > **NOTICE**: error responses are bencoded and always have a `200 OK` status
//! > code. The official `BitTorrent` specification does not specify the status
//! > code.
use axum::http::StatusCode;
use axum::response::{IntoResponse, Response};
use serde::Serialize;

use crate::v1::services::peer_ip_resolver::PeerIpResolutionError;

/// `Error` response for the [`HTTP tracker`](crate::servers::http).
#[derive(Serialize, Debug, PartialEq)]
pub struct Error {
Expand All @@ -26,8 +26,8 @@ pub struct Error {
impl Error {
/// Returns the bencoded representation of the `Error` struct.
///
/// ```text
/// use torrust_tracker_lib::servers::http::v1::responses::error::Error;
/// ```rust
/// use bittorrent_http_protocol::v1::responses::error::Error;
///
/// let err = Error {
/// failure_reason: "error message".to_owned(),
Expand All @@ -47,9 +47,11 @@ impl Error {
}
}

impl IntoResponse for Error {
fn into_response(self) -> Response {
(StatusCode::OK, self.write()).into_response()
impl From<PeerIpResolutionError> for Error {
fn from(err: PeerIpResolutionError) -> Self {
Self {
failure_reason: format!("Error resolving peer IP: {err}"),
}
}
}

Expand Down
Loading
Loading