diff --git a/Cargo.lock b/Cargo.lock index 399cb3a..9189991 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -171,6 +171,7 @@ name = "aquatic_http_protocol" version = "0.2.0" dependencies = [ "anyhow", + "axum", "bendy", "criterion", "hex", diff --git a/TODO.md b/TODO.md index bb4135b..5b6f9b6 100644 --- a/TODO.md +++ b/TODO.md @@ -11,7 +11,6 @@ * site will likely want num_seeders and num_leechers for all torrents.. * aquatic_http_protocol - * Implement axum IntoResponse behind feature gate * don't require compact=1? ## Medium priority diff --git a/aquatic_http_private/Cargo.toml b/aquatic_http_private/Cargo.toml index bad6901..2970534 100644 --- a/aquatic_http_private/Cargo.toml +++ b/aquatic_http_private/Cargo.toml @@ -12,7 +12,7 @@ name = "aquatic_http_private" [dependencies] aquatic_cli_helpers = "0.2.0" aquatic_common = { version = "0.2.0", features = ["rustls-config"] } -aquatic_http_protocol = "0.2.0" +aquatic_http_protocol = { version = "0.2.0", features = ["with-axum"] } aquatic_toml_config = "0.2.0" anyhow = "1" diff --git a/aquatic_http_private/src/workers/socket/routes.rs b/aquatic_http_private/src/workers/socket/routes.rs index 481728a..8fd139b 100644 --- a/aquatic_http_private/src/workers/socket/routes.rs +++ b/aquatic_http_private/src/workers/socket/routes.rs @@ -2,12 +2,10 @@ use aquatic_common::CanonicalSocketAddr; use axum::{ extract::{ConnectInfo, Path, RawQuery}, headers::UserAgent, - http::StatusCode, - response::IntoResponse, Extension, TypedHeader, }; use sqlx::mysql::MySqlPool; -use std::{borrow::Cow, net::SocketAddr, sync::Arc}; +use std::{net::SocketAddr, sync::Arc}; use aquatic_http_protocol::{ request::AnnounceRequest, @@ -29,11 +27,11 @@ pub async fn announce( opt_user_agent: Option>, Path(user_token): Path, RawQuery(query): RawQuery, -) -> Result { - let query = query.ok_or_else(|| create_failure_response("Empty query string"))?; +) -> Result { + let query = query.ok_or_else(|| FailureResponse::new("Empty query string"))?; let request = AnnounceRequest::from_query_string(&query) - .map_err(|_| create_failure_response("Malformed request"))?; + .map_err(|_| FailureResponse::new("Malformed request"))?; let request_worker_index = RequestWorkerIndex::from_info_hash(&config, request.info_hash); let opt_user_agent = opt_user_agent.map(|header| header.as_str().to_owned()); @@ -42,8 +40,7 @@ pub async fn announce( let (validated_request, opt_warning_message) = db::validate_announce_request(&pool, source_addr, opt_user_agent, user_token, request) - .await - .map_err(|r| create_response(Response::Failure(r)))?; + .await?; let response_receiver = request_sender .send_to(request_worker_index, validated_request, source_addr) @@ -58,39 +55,11 @@ pub async fn announce( r.warning_message = opt_warning_message; } - Ok(create_response(response)) + Ok(response) } -fn create_response(response: Response) -> axum::response::Response { - let mut response_bytes = Vec::with_capacity(128); - - response.write(&mut response_bytes).unwrap(); - - ( - StatusCode::OK, - [("Content-type", "text/plain; charset=utf-8")], - response_bytes, - ) - .into_response() -} - -fn create_failure_response>>(reason: R) -> axum::response::Response { - let mut response_bytes = Vec::with_capacity(64); - - FailureResponse::new(reason) - .write(&mut response_bytes) - .unwrap(); - - ( - StatusCode::OK, - [("Content-type", "text/plain; charset=utf-8")], - response_bytes, - ) - .into_response() -} - -fn internal_error(error: String) -> axum::response::Response { +fn internal_error(error: String) -> FailureResponse { ::log::error!("{}", error); - create_failure_response("Internal error") + FailureResponse::new("Internal error") } diff --git a/aquatic_http_protocol/Cargo.toml b/aquatic_http_protocol/Cargo.toml index 440ea54..0b31222 100644 --- a/aquatic_http_protocol/Cargo.toml +++ b/aquatic_http_protocol/Cargo.toml @@ -22,8 +22,12 @@ name = "bench_announce_response_to_bytes" path = "benches/bench_announce_response_to_bytes.rs" harness = false +[features] +with-axum = ["axum"] + [dependencies] anyhow = "1" +axum = { version = "0.5", optional = true, default-features = false } hex = { version = "0.4", default-features = false } httparse = "1" itoa = "1" diff --git a/aquatic_http_protocol/src/response.rs b/aquatic_http_protocol/src/response.rs index 0eeb7f7..baf511f 100644 --- a/aquatic_http_protocol/src/response.rs +++ b/aquatic_http_protocol/src/response.rs @@ -112,6 +112,21 @@ impl AnnounceResponse { } } +#[cfg(feature = "with-axum")] +impl axum::response::IntoResponse for AnnounceResponse { + fn into_response(self) -> axum::response::Response { + let mut response_bytes = Vec::with_capacity(128); + + self.write(&mut response_bytes).unwrap(); + + ( + [("Content-type", "text/plain; charset=utf-8")], + response_bytes, + ) + .into_response() + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct ScrapeResponse { /// BTreeMap instead of HashMap since keys need to be serialized in order @@ -142,6 +157,21 @@ impl ScrapeResponse { } } +#[cfg(feature = "with-axum")] +impl axum::response::IntoResponse for ScrapeResponse { + fn into_response(self) -> axum::response::Response { + let mut response_bytes = Vec::with_capacity(128); + + self.write(&mut response_bytes).unwrap(); + + ( + [("Content-type", "text/plain; charset=utf-8")], + response_bytes, + ) + .into_response() + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct FailureResponse { #[serde(rename = "failure reason")] @@ -170,6 +200,21 @@ impl FailureResponse { } } +#[cfg(feature = "with-axum")] +impl axum::response::IntoResponse for FailureResponse { + fn into_response(self) -> axum::response::Response { + let mut response_bytes = Vec::with_capacity(64); + + self.write(&mut response_bytes).unwrap(); + + ( + [("Content-type", "text/plain; charset=utf-8")], + response_bytes, + ) + .into_response() + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] pub enum Response { @@ -191,6 +236,17 @@ impl Response { } } +#[cfg(feature = "with-axum")] +impl axum::response::IntoResponse for Response { + fn into_response(self) -> axum::response::Response { + match self { + Self::Announce(r) => r.into_response(), + Self::Scrape(r) => r.into_response(), + Self::Failure(r) => r.into_response(), + } + } +} + #[cfg(test)] impl quickcheck::Arbitrary for ResponsePeer { fn arbitrary(g: &mut quickcheck::Gen) -> Self {