From 7256b4645b3b7fb92661a3b715742a97ad4b7132 Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Mon, 12 Feb 2024 11:13:04 +0000 Subject: [PATCH 1/2] feat: [#473] add timeout to Tracker API Client requests Default timeout of 5 seconds. --- src/tracker/api.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/tracker/api.rs b/src/tracker/api.rs index f64430b7..39a7b42b 100644 --- a/src/tracker/api.rs +++ b/src/tracker/api.rs @@ -1,3 +1,5 @@ +use std::time::Duration; + use reqwest::{Error, Response}; pub struct ConnectionInfo { /// The URL of the tracker. Eg: or @@ -15,6 +17,7 @@ impl ConnectionInfo { pub struct Client { pub connection_info: ConnectionInfo, + timeout: Duration, base_url: String, } @@ -24,6 +27,7 @@ impl Client { let base_url = format!("{}/api/v1", connection_info.url); Self { connection_info, + timeout: Duration::from_secs(5), base_url, } } @@ -36,7 +40,7 @@ impl Client { pub async fn whitelist_torrent(&self, info_hash: &str) -> Result { let request_url = format!("{}/whitelist/{}", self.base_url, info_hash); - let client = reqwest::Client::new(); + let client = reqwest::Client::builder().timeout(self.timeout).build()?; let params = [("token", &self.connection_info.token)]; @@ -51,7 +55,7 @@ impl Client { pub async fn remove_torrent_from_whitelist(&self, info_hash: &str) -> Result { let request_url = format!("{}/whitelist/{}", self.base_url, info_hash); - let client = reqwest::Client::new(); + let client = reqwest::Client::builder().timeout(self.timeout).build()?; let params = [("token", &self.connection_info.token)]; @@ -66,7 +70,7 @@ impl Client { pub async fn retrieve_new_tracker_key(&self, token_valid_seconds: u64) -> Result { let request_url = format!("{}/key/{}", self.base_url, token_valid_seconds); - let client = reqwest::Client::new(); + let client = reqwest::Client::builder().timeout(self.timeout).build()?; let params = [("token", &self.connection_info.token)]; @@ -81,7 +85,7 @@ impl Client { pub async fn get_torrent_info(&self, info_hash: &str) -> Result { let request_url = format!("{}/torrent/{}", self.base_url, info_hash); - let client = reqwest::Client::new(); + let client = reqwest::Client::builder().timeout(self.timeout).build()?; let params = [("token", &self.connection_info.token)]; From 3f629c283d624dfea72af4ba69b3ab815f5d1c3c Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Mon, 12 Feb 2024 12:11:59 +0000 Subject: [PATCH 2/2] refactor: [#473] tracker API client. Remove duplicate code --- src/tracker/api.rs | 57 ++++++++++++++++++------------------------ src/tracker/service.rs | 6 ++++- 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/src/tracker/api.rs b/src/tracker/api.rs index 39a7b42b..d3c00188 100644 --- a/src/tracker/api.rs +++ b/src/tracker/api.rs @@ -2,7 +2,7 @@ use std::time::Duration; use reqwest::{Error, Response}; pub struct ConnectionInfo { - /// The URL of the tracker. Eg: or + /// The URL of the tracker API. Eg: . pub url: String, /// The token used to authenticate with the tracker API. pub token: String, @@ -17,19 +17,26 @@ impl ConnectionInfo { pub struct Client { pub connection_info: ConnectionInfo, - timeout: Duration, - base_url: String, + api_base_url: String, + client: reqwest::Client, + token_param: [(String, String); 1], } impl Client { - #[must_use] - pub fn new(connection_info: ConnectionInfo) -> Self { + /// # Errors + /// + /// Will fails if it can't build a HTTP client with a timeout. + pub fn new(connection_info: ConnectionInfo) -> Result { let base_url = format!("{}/api/v1", connection_info.url); - Self { + let client = reqwest::Client::builder().timeout(Duration::from_secs(5)).build()?; + let token_param = [("token".to_string(), connection_info.token.to_string())]; + + Ok(Self { connection_info, - timeout: Duration::from_secs(5), - base_url, - } + api_base_url: base_url, + client, + token_param, + }) } /// Add a torrent to the tracker whitelist. @@ -38,13 +45,9 @@ impl Client { /// /// Will return an error if the HTTP request fails. pub async fn whitelist_torrent(&self, info_hash: &str) -> Result { - let request_url = format!("{}/whitelist/{}", self.base_url, info_hash); - - let client = reqwest::Client::builder().timeout(self.timeout).build()?; - - let params = [("token", &self.connection_info.token)]; + let request_url = format!("{}/whitelist/{}", self.api_base_url, info_hash); - client.post(request_url).query(¶ms).send().await + self.client.post(request_url).query(&self.token_param).send().await } /// Remove a torrent from the tracker whitelist. @@ -53,13 +56,9 @@ impl Client { /// /// Will return an error if the HTTP request fails. pub async fn remove_torrent_from_whitelist(&self, info_hash: &str) -> Result { - let request_url = format!("{}/whitelist/{}", self.base_url, info_hash); + let request_url = format!("{}/whitelist/{}", self.api_base_url, info_hash); - let client = reqwest::Client::builder().timeout(self.timeout).build()?; - - let params = [("token", &self.connection_info.token)]; - - client.delete(request_url).query(¶ms).send().await + self.client.delete(request_url).query(&self.token_param).send().await } /// Retrieve a new tracker key. @@ -68,13 +67,9 @@ impl Client { /// /// Will return an error if the HTTP request fails. pub async fn retrieve_new_tracker_key(&self, token_valid_seconds: u64) -> Result { - let request_url = format!("{}/key/{}", self.base_url, token_valid_seconds); - - let client = reqwest::Client::builder().timeout(self.timeout).build()?; + let request_url = format!("{}/key/{}", self.api_base_url, token_valid_seconds); - let params = [("token", &self.connection_info.token)]; - - client.post(request_url).query(¶ms).send().await + self.client.post(request_url).query(&self.token_param).send().await } /// Retrieve the info for a torrent. @@ -83,12 +78,8 @@ impl Client { /// /// Will return an error if the HTTP request fails. pub async fn get_torrent_info(&self, info_hash: &str) -> Result { - let request_url = format!("{}/torrent/{}", self.base_url, info_hash); - - let client = reqwest::Client::builder().timeout(self.timeout).build()?; - - let params = [("token", &self.connection_info.token)]; + let request_url = format!("{}/torrent/{}", self.api_base_url, info_hash); - client.get(request_url).query(¶ms).send().await + self.client.get(request_url).query(&self.token_param).send().await } } diff --git a/src/tracker/service.rs b/src/tracker/service.rs index 265109d2..64a76602 100644 --- a/src/tracker/service.rs +++ b/src/tracker/service.rs @@ -73,12 +73,16 @@ pub struct Service { } impl Service { + /// # Panics + /// + /// Will panic if it can't build a Tracker API client. pub async fn new(cfg: Arc, database: Arc>) -> Service { let settings = cfg.settings.read().await; let api_client = Client::new(ConnectionInfo::new( settings.tracker.api_url.clone(), settings.tracker.token.clone(), - )); + )) + .expect("a reqwest client should be provided"); let token_valid_seconds = settings.tracker.token_valid_seconds; let tracker_url = settings.tracker.url.clone(); drop(settings);