forked from torrust/torrust-tracker
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(http): [torrust#184] normal (non-compact) announce response in a…
…xum tracker Implemeneted the normal (non-compact) announce response in the new Axum implementation for the HTTP tracker. Only for the tracker public mode and with only the mandatory announce request params.
- Loading branch information
1 parent
42bd313
commit e85d115
Showing
5 changed files
with
154 additions
and
52 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,56 @@ | ||
use std::net::{IpAddr, SocketAddr}; | ||
use std::sync::Arc; | ||
|
||
use aquatic_udp_protocol::{AnnounceEvent, NumberOfBytes}; | ||
use axum::extract::State; | ||
use axum::response::Json; | ||
use axum_client_ip::{InsecureClientIp, SecureClientIp}; | ||
use log::debug; | ||
use axum::response::{IntoResponse, Response}; | ||
use axum_client_ip::SecureClientIp; | ||
|
||
use crate::http::axum_implementation::requests::announce::ExtractAnnounceRequest; | ||
use crate::http::axum_implementation::resources::ok::Ok; | ||
use crate::http::axum_implementation::responses::ok; | ||
use crate::tracker::Tracker; | ||
use crate::http::axum_implementation::requests::announce::{Announce, ExtractAnnounceRequest}; | ||
use crate::http::axum_implementation::responses; | ||
use crate::protocol::clock::{Current, Time}; | ||
use crate::tracker::peer::Peer; | ||
use crate::tracker::{statistics, Tracker}; | ||
|
||
/// WIP | ||
#[allow(clippy::unused_async)] | ||
pub async fn handle( | ||
State(_tracker): State<Arc<Tracker>>, | ||
State(tracker): State<Arc<Tracker>>, | ||
ExtractAnnounceRequest(announce_request): ExtractAnnounceRequest, | ||
insecure_ip: InsecureClientIp, | ||
secure_ip: SecureClientIp, | ||
) -> Json<Ok> { | ||
/* todo: | ||
- Extract remote client ip from request | ||
- Build the `Peer` | ||
- Call the `tracker.announce` method | ||
- Send event for stats | ||
- Move response from Warp to shared mod | ||
- Send response | ||
*/ | ||
|
||
// Sample announce URL used for debugging: | ||
// http://0.0.0.0:7070/announce?info_hash=%3B%24U%04%CF%5F%11%BB%DB%E1%20%1C%EAjk%F4Z%EE%1B%C0&peer_id=-qB00000000000000001&port=17548 | ||
) -> Response { | ||
// todo: compact response and optional params | ||
|
||
let info_hash = announce_request.info_hash; | ||
let remote_client_ip = secure_ip.0; | ||
|
||
debug!("http announce request: {:#?}", announce_request); | ||
debug!("info_hash: {:#?}", &info_hash); | ||
debug!("remote client ip, insecure_ip: {:#?}", &insecure_ip); | ||
debug!("remote client ip, secure_ip: {:#?}", &secure_ip); | ||
let mut peer = peer_from_request(&announce_request, &remote_client_ip); | ||
|
||
ok::response(&insecure_ip.0, &secure_ip.0) | ||
let response = tracker.announce(&info_hash, &mut peer, &remote_client_ip).await; | ||
|
||
match remote_client_ip { | ||
IpAddr::V4(_) => { | ||
tracker.send_stats_event(statistics::Event::Tcp4Announce).await; | ||
} | ||
IpAddr::V6(_) => { | ||
tracker.send_stats_event(statistics::Event::Tcp6Announce).await; | ||
} | ||
} | ||
|
||
responses::announce::Announce::from(response).into_response() | ||
} | ||
|
||
#[must_use] | ||
fn peer_from_request(announce_request: &Announce, peer_ip: &IpAddr) -> Peer { | ||
#[allow(clippy::cast_possible_truncation)] | ||
Peer { | ||
peer_id: announce_request.peer_id, | ||
peer_addr: SocketAddr::new(*peer_ip, announce_request.port), | ||
updated: Current::now(), | ||
// todo: optional parameters not included in the announce request yet | ||
uploaded: NumberOfBytes(i128::from(0) as i64), | ||
downloaded: NumberOfBytes(i128::from(0) as i64), | ||
left: NumberOfBytes(i128::from(0) as i64), | ||
event: AnnounceEvent::None, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
use std::net::IpAddr; | ||
|
||
use axum::http::StatusCode; | ||
use axum::response::{IntoResponse, Response}; | ||
use serde::{self, Deserialize, Serialize}; | ||
|
||
use crate::tracker::{self, AnnounceResponse}; | ||
|
||
#[derive(Serialize, Deserialize, Debug, PartialEq)] | ||
pub struct Announce { | ||
pub interval: u32, | ||
#[serde(rename = "min interval")] | ||
pub interval_min: u32, | ||
pub complete: u32, | ||
pub incomplete: u32, | ||
pub peers: Vec<Peer>, | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Debug, PartialEq)] | ||
pub struct Peer { | ||
pub peer_id: String, | ||
pub ip: IpAddr, | ||
pub port: u16, | ||
} | ||
|
||
impl From<tracker::peer::Peer> for Peer { | ||
fn from(peer: tracker::peer::Peer) -> Self { | ||
Peer { | ||
peer_id: peer.peer_id.to_string(), | ||
ip: peer.peer_addr.ip(), | ||
port: peer.peer_addr.port(), | ||
} | ||
} | ||
} | ||
|
||
impl Announce { | ||
/// # Panics | ||
/// | ||
/// It would panic if the `Announce` struct contained an inappropriate type. | ||
#[must_use] | ||
pub fn write(&self) -> String { | ||
serde_bencode::to_string(&self).unwrap() | ||
} | ||
} | ||
|
||
impl IntoResponse for Announce { | ||
fn into_response(self) -> Response { | ||
(StatusCode::OK, self.write()).into_response() | ||
} | ||
} | ||
|
||
impl From<AnnounceResponse> for Announce { | ||
fn from(domain_announce_response: AnnounceResponse) -> Self { | ||
let peers: Vec<Peer> = domain_announce_response.peers.iter().map(|peer| Peer::from(*peer)).collect(); | ||
|
||
Self { | ||
interval: domain_announce_response.interval, | ||
interval_min: domain_announce_response.interval_min, | ||
complete: domain_announce_response.swam_stats.seeders, | ||
incomplete: domain_announce_response.swam_stats.leechers, | ||
peers, | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
|
||
use std::net::IpAddr; | ||
use std::str::FromStr; | ||
|
||
use super::{Announce, Peer}; | ||
|
||
#[test] | ||
fn announce_response_can_be_bencoded() { | ||
let response = Announce { | ||
interval: 1, | ||
interval_min: 2, | ||
complete: 3, | ||
incomplete: 4, | ||
peers: vec![Peer { | ||
peer_id: "-qB00000000000000001".to_string(), | ||
ip: IpAddr::from_str("127.0.0.1").unwrap(), | ||
port: 8080, | ||
}], | ||
}; | ||
|
||
// cspell:disable-next-line | ||
assert_eq!(response.write(), "d8:completei3e10:incompletei4e8:intervali1e12:min intervali2e5:peersld2:ip9:127.0.0.17:peer_id20:-qB000000000000000014:porti8080eeee"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,2 +1,3 @@ | ||
pub mod error; | ||
pub mod ok; | ||
pub mod announce; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters