From a8c2f84aedba7d8379f60fdc1c80375d557b013e Mon Sep 17 00:00:00 2001 From: Jose Celano Date: Fri, 9 Feb 2024 16:44:21 +0000 Subject: [PATCH] refactor: [#472] move unwraps from generic HTTP client up to Index API client --- src/web/api/client/v1/client.rs | 128 ++++++++++--- src/web/api/client/v1/http.rs | 307 ++++++++++++++++---------------- 2 files changed, 263 insertions(+), 172 deletions(-) diff --git a/src/web/api/client/v1/client.rs b/src/web/api/client/v1/client.rs index 72723959..c56b9b59 100644 --- a/src/web/api/client/v1/client.rs +++ b/src/web/api/client/v1/client.rs @@ -46,113 +46,199 @@ impl Client { // Context: about + /// # Panics + /// + /// Will panic if the request fails. pub async fn about(&self) -> TextResponse { - self.http_client.get("/about", Query::empty()).await + self.http_client.get("/about", Query::empty()).await.unwrap() } + /// # Panics + /// + /// Will panic if the request fails. pub async fn license(&self) -> TextResponse { - self.http_client.get("/about/license", Query::empty()).await + self.http_client.get("/about/license", Query::empty()).await.unwrap() } // Context: category + /// # Panics + /// + /// Will panic if the request fails. pub async fn get_categories(&self) -> TextResponse { - self.http_client.get("/category", Query::empty()).await + self.http_client.get("/category", Query::empty()).await.unwrap() } + /// # Panics + /// + /// Will panic if the request fails. pub async fn add_category(&self, add_category_form: AddCategoryForm) -> TextResponse { - self.http_client.post("/category", &add_category_form).await + self.http_client.post("/category", &add_category_form).await.unwrap() } + /// # Panics + /// + /// Will panic if the request fails. pub async fn delete_category(&self, delete_category_form: DeleteCategoryForm) -> TextResponse { - self.http_client.delete_with_body("/category", &delete_category_form).await + self.http_client + .delete_with_body("/category", &delete_category_form) + .await + .unwrap() } // Context: tag + /// # Panics + /// + /// Will panic if the request fails. pub async fn get_tags(&self) -> TextResponse { // code-review: some endpoint are using plural // (for instance, `get_categories`) and some singular. - self.http_client.get("/tags", Query::empty()).await + self.http_client.get("/tags", Query::empty()).await.unwrap() } + /// # Panics + /// + /// Will panic if the request fails. pub async fn add_tag(&self, add_tag_form: AddTagForm) -> TextResponse { - self.http_client.post("/tag", &add_tag_form).await + self.http_client.post("/tag", &add_tag_form).await.unwrap() } + /// # Panics + /// + /// Will panic if the request fails. pub async fn delete_tag(&self, delete_tag_form: DeleteTagForm) -> TextResponse { - self.http_client.delete_with_body("/tag", &delete_tag_form).await + self.http_client.delete_with_body("/tag", &delete_tag_form).await.unwrap() } // Context: root + /// # Panics + /// + /// Will panic if the request fails. pub async fn root(&self) -> TextResponse { - self.http_client.get("", Query::empty()).await + self.http_client.get("", Query::empty()).await.unwrap() } // Context: settings + /// # Panics + /// + /// Will panic if the request fails. pub async fn get_public_settings(&self) -> TextResponse { - self.http_client.get("/settings/public", Query::empty()).await + self.http_client.get("/settings/public", Query::empty()).await.unwrap() } + /// # Panics + /// + /// Will panic if the request fails. pub async fn get_site_name(&self) -> TextResponse { - self.http_client.get("/settings/name", Query::empty()).await + self.http_client.get("/settings/name", Query::empty()).await.unwrap() } + /// # Panics + /// + /// Will panic if the request fails. pub async fn get_settings(&self) -> TextResponse { - self.http_client.get("/settings", Query::empty()).await + self.http_client.get("/settings", Query::empty()).await.unwrap() } // Context: torrent + /// # Panics + /// + /// Will panic if the request fails. pub async fn get_torrents(&self, params: Query) -> TextResponse { - self.http_client.get("/torrents", params).await + self.http_client.get("/torrents", params).await.unwrap() } + /// # Panics + /// + /// Will panic if the request fails. pub async fn get_torrent(&self, info_hash: &InfoHash) -> TextResponse { - self.http_client.get(&format!("/torrent/{info_hash}"), Query::empty()).await + self.http_client + .get(&format!("/torrent/{info_hash}"), Query::empty()) + .await + .unwrap() } + /// # Panics + /// + /// Will panic if the request fails. pub async fn delete_torrent(&self, info_hash: &InfoHash) -> TextResponse { - self.http_client.delete(&format!("/torrent/{info_hash}")).await + self.http_client.delete(&format!("/torrent/{info_hash}")).await.unwrap() } + /// # Panics + /// + /// Will panic if the request fails. pub async fn update_torrent(&self, info_hash: &InfoHash, update_torrent_form: UpdateTorrentForm) -> TextResponse { self.http_client .put(&format!("/torrent/{info_hash}"), &update_torrent_form) .await + .unwrap() } + /// # Panics + /// + /// Will panic if the request fails. pub async fn upload_torrent(&self, form: multipart::Form) -> TextResponse { - self.http_client.post_multipart("/torrent/upload", form).await + self.http_client.post_multipart("/torrent/upload", form).await.unwrap() } + /// # Panics + /// + /// Will panic if the request fails. pub async fn download_torrent(&self, info_hash: &InfoHash) -> responses::BinaryResponse { self.http_client .get_binary(&format!("/torrent/download/{info_hash}"), Query::empty()) .await + .unwrap() } // Context: user + /// # Panics + /// + /// Will panic if the request fails. pub async fn register_user(&self, registration_form: RegistrationForm) -> TextResponse { - self.http_client.post("/user/register", ®istration_form).await + self.http_client.post("/user/register", ®istration_form).await.unwrap() } + /// # Panics + /// + /// Will panic if the request fails. pub async fn login_user(&self, registration_form: LoginForm) -> TextResponse { - self.http_client.post("/user/login", ®istration_form).await + self.http_client.post("/user/login", ®istration_form).await.unwrap() } + /// # Panics + /// + /// Will panic if the request fails. pub async fn verify_token(&self, token_verification_form: TokenVerificationForm) -> TextResponse { - self.http_client.post("/user/token/verify", &token_verification_form).await + self.http_client + .post("/user/token/verify", &token_verification_form) + .await + .unwrap() } + /// # Panics + /// + /// Will panic if the request fails. pub async fn renew_token(&self, token_verification_form: TokenRenewalForm) -> TextResponse { - self.http_client.post("/user/token/renew", &token_verification_form).await + self.http_client + .post("/user/token/renew", &token_verification_form) + .await + .unwrap() } + /// # Panics + /// + /// Will panic if the request fails. pub async fn ban_user(&self, username: Username) -> TextResponse { - self.http_client.delete(&format!("/user/ban/{}", &username.value)).await + self.http_client + .delete(&format!("/user/ban/{}", &username.value)) + .await + .unwrap() } } diff --git a/src/web/api/client/v1/http.rs b/src/web/api/client/v1/http.rs index 1c90890a..ca42d462 100644 --- a/src/web/api/client/v1/http.rs +++ b/src/web/api/client/v1/http.rs @@ -1,6 +1,6 @@ use std::time::Duration; -use reqwest::multipart; +use reqwest::{multipart, Error}; use serde::Serialize; use super::connection_info::ConnectionInfo; @@ -81,203 +81,208 @@ impl Http { } } - /// # Panics + /// # Errors /// - /// Will panic if there was an error while sending request, redirect loop - /// was detected or redirect limit was exhausted. - pub async fn get(&self, path: &str, params: Query) -> TextResponse { + /// Will return an error if there was an error while sending request, + /// redirect loop was detected or redirect limit was exhausted. + pub async fn get(&self, path: &str, params: Query) -> Result { let response = match &self.connection_info.token { - Some(token) => reqwest::Client::builder() - .timeout(self.timeout) - .build() - .unwrap() - .get(self.base_url(path).clone()) - .query(&ReqwestQuery::from(params)) - .bearer_auth(token) - .send() - .await - .unwrap(), - None => reqwest::Client::builder() - .timeout(self.timeout) - .build() - .unwrap() - .get(self.base_url(path).clone()) - .query(&ReqwestQuery::from(params)) - .send() - .await - .unwrap(), + Some(token) => { + reqwest::Client::builder() + .timeout(self.timeout) + .build()? + .get(self.base_url(path).clone()) + .query(&ReqwestQuery::from(params)) + .bearer_auth(token) + .send() + .await? + } + None => { + reqwest::Client::builder() + .timeout(self.timeout) + .build()? + .get(self.base_url(path).clone()) + .query(&ReqwestQuery::from(params)) + .send() + .await? + } }; - TextResponse::from(response).await + + Ok(TextResponse::from(response).await) } - /// # Panics + /// # Errors /// - /// Will panic if there was an error while sending request, redirect loop - /// was detected or redirect limit was exhausted. - pub async fn get_binary(&self, path: &str, params: Query) -> BinaryResponse { + /// Will return an error if there was an error while sending request, + /// redirect loop was detected or redirect limit was exhausted. + pub async fn get_binary(&self, path: &str, params: Query) -> Result { let response = match &self.connection_info.token { - Some(token) => reqwest::Client::builder() - .timeout(self.timeout) - .build() - .unwrap() - .get(self.base_url(path).clone()) - .query(&ReqwestQuery::from(params)) - .bearer_auth(token) - .send() - .await - .unwrap(), - None => reqwest::Client::builder() - .timeout(self.timeout) - .build() - .unwrap() - .get(self.base_url(path).clone()) - .query(&ReqwestQuery::from(params)) - .send() - .await - .unwrap(), + Some(token) => { + reqwest::Client::builder() + .timeout(self.timeout) + .build()? + .get(self.base_url(path).clone()) + .query(&ReqwestQuery::from(params)) + .bearer_auth(token) + .send() + .await? + } + None => { + reqwest::Client::builder() + .timeout(self.timeout) + .build()? + .get(self.base_url(path).clone()) + .query(&ReqwestQuery::from(params)) + .send() + .await? + } }; + // todo: If the response is a JSON, it returns the JSON body in a byte // array. This is not the expected behavior. // - Rename BinaryResponse to BinaryTorrentResponse // - Return an error if the response is not a bittorrent file - BinaryResponse::from(response).await + Ok(BinaryResponse::from(response).await) } /// # Errors /// - /// Will fail if there was an error while sending request, redirect loop - /// was detected or redirect limit was exhausted. - /// - /// # Panics - /// - /// This method fails it can't build a `reqwest` client. + /// Will return an error if there was an error while sending request, + /// redirect loop was detected or redirect limit was exhausted. pub async fn inner_get(&self, path: &str) -> Result { reqwest::Client::builder() .timeout(self.timeout) - .build() - .unwrap() + .build()? .get(self.base_url(path).clone()) .send() .await } - /// # Panics + /// # Errors /// - /// Will panic if there was an error while sending request, redirect loop - /// was detected or redirect limit was exhausted. - pub async fn post(&self, path: &str, form: &T) -> TextResponse { + /// Will return an error if there was an error while sending request, + /// redirect loop was detected or redirect limit was exhausted. + pub async fn post(&self, path: &str, form: &T) -> Result { let response = match &self.connection_info.token { - Some(token) => reqwest::Client::new() - .post(self.base_url(path).clone()) - .bearer_auth(token) - .json(&form) - .send() - .await - .unwrap(), - None => reqwest::Client::new() - .post(self.base_url(path).clone()) - .json(&form) - .send() - .await - .unwrap(), + Some(token) => { + reqwest::Client::new() + .post(self.base_url(path).clone()) + .bearer_auth(token) + .json(&form) + .send() + .await? + } + None => { + reqwest::Client::new() + .post(self.base_url(path).clone()) + .json(&form) + .send() + .await? + } }; - TextResponse::from(response).await + + Ok(TextResponse::from(response).await) } - /// # Panics + /// # Errors /// - /// Will panic if there was an error while sending request, redirect loop - /// was detected or redirect limit was exhausted. - pub async fn post_multipart(&self, path: &str, form: multipart::Form) -> TextResponse { + /// Will return an error if there was an error while sending request, + /// redirect loop was detected or redirect limit was exhausted. + pub async fn post_multipart(&self, path: &str, form: multipart::Form) -> Result { let response = match &self.connection_info.token { - Some(token) => reqwest::Client::builder() - .timeout(self.timeout) - .build() - .unwrap() - .post(self.base_url(path).clone()) - .multipart(form) - .bearer_auth(token) - .send() - .await - .expect("failed to send multipart request with token"), - None => reqwest::Client::builder() - .timeout(self.timeout) - .build() - .unwrap() - .post(self.base_url(path).clone()) - .multipart(form) - .send() - .await - .expect("failed to send multipart request without token"), + Some(token) => { + reqwest::Client::builder() + .timeout(self.timeout) + .build()? + .post(self.base_url(path).clone()) + .multipart(form) + .bearer_auth(token) + .send() + .await? + } + None => { + reqwest::Client::builder() + .timeout(self.timeout) + .build()? + .post(self.base_url(path).clone()) + .multipart(form) + .send() + .await? + } }; - TextResponse::from(response).await + + Ok(TextResponse::from(response).await) } - /// # Panics + /// # Errors /// - /// Will panic if there was an error while sending request, redirect loop - /// was detected or redirect limit was exhausted. - pub async fn put(&self, path: &str, form: &T) -> TextResponse { + /// Will return an error if there was an error while sending request, + /// redirect loop was detected or redirect limit was exhausted. + pub async fn put(&self, path: &str, form: &T) -> Result { let response = match &self.connection_info.token { - Some(token) => reqwest::Client::new() - .put(self.base_url(path).clone()) - .bearer_auth(token) - .json(&form) - .send() - .await - .unwrap(), - None => reqwest::Client::new() - .put(self.base_url(path).clone()) - .json(&form) - .send() - .await - .unwrap(), + Some(token) => { + reqwest::Client::new() + .put(self.base_url(path).clone()) + .bearer_auth(token) + .json(&form) + .send() + .await? + } + None => { + reqwest::Client::new() + .put(self.base_url(path).clone()) + .json(&form) + .send() + .await? + } }; - TextResponse::from(response).await + + Ok(TextResponse::from(response).await) } - /// # Panics + /// # Errors /// - /// Will panic if there was an error while sending request, redirect loop - /// was detected or redirect limit was exhausted. - pub async fn delete(&self, path: &str) -> TextResponse { + /// Will return an error if there was an error while sending request, + /// redirect loop was detected or redirect limit was exhausted. + pub async fn delete(&self, path: &str) -> Result { let response = match &self.connection_info.token { - Some(token) => reqwest::Client::new() - .delete(self.base_url(path).clone()) - .bearer_auth(token) - .send() - .await - .unwrap(), - None => reqwest::Client::new() - .delete(self.base_url(path).clone()) - .send() - .await - .unwrap(), + Some(token) => { + reqwest::Client::new() + .delete(self.base_url(path).clone()) + .bearer_auth(token) + .send() + .await? + } + None => reqwest::Client::new().delete(self.base_url(path).clone()).send().await?, }; - TextResponse::from(response).await + + Ok(TextResponse::from(response).await) } - /// # Panics + /// # Errors /// - /// Will panic if there was an error while sending request, redirect loop - /// was detected or redirect limit was exhausted. - pub async fn delete_with_body(&self, path: &str, form: &T) -> TextResponse { + /// Will return an error if there was an error while sending request, + /// redirect loop was detected or redirect limit was exhausted. + pub async fn delete_with_body(&self, path: &str, form: &T) -> Result { let response = match &self.connection_info.token { - Some(token) => reqwest::Client::new() - .delete(self.base_url(path).clone()) - .bearer_auth(token) - .json(&form) - .send() - .await - .unwrap(), - None => reqwest::Client::new() - .delete(self.base_url(path).clone()) - .json(&form) - .send() - .await - .unwrap(), + Some(token) => { + reqwest::Client::new() + .delete(self.base_url(path).clone()) + .bearer_auth(token) + .json(&form) + .send() + .await? + } + None => { + reqwest::Client::new() + .delete(self.base_url(path).clone()) + .json(&form) + .send() + .await? + } }; - TextResponse::from(response).await + + Ok(TextResponse::from(response).await) } fn base_url(&self, path: &str) -> String {