From ae71f2cd7c0f22c3c213a1aa70fbc0889699db96 Mon Sep 17 00:00:00 2001 From: Aedius Date: Fri, 21 Jul 2023 22:06:25 +0200 Subject: [PATCH 1/2] handle error with thiserror --- Cargo.toml | 1 + src/client.rs | 44 +++++++++++++++++++++++--------------------- src/email_redir.rs | 15 ++++++++------- src/error.rs | 23 +++++++++++++++++++++++ src/lib.rs | 1 + 5 files changed, 56 insertions(+), 28 deletions(-) create mode 100644 src/error.rs diff --git a/Cargo.toml b/Cargo.toml index f65e801..173befe 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" phf = { version = "0.10", features = ["macros"] } configparser = "2.1.0" +thiserror = "1.0" [dev-dependencies] clap = "3.0.0-beta.4" \ No newline at end of file diff --git a/src/client.rs b/src/client.rs index 78e934d..5ab505d 100644 --- a/src/client.rs +++ b/src/client.rs @@ -8,6 +8,7 @@ use std::{ path::Path, time::{SystemTime, UNIX_EPOCH}, }; +use crate::error::OvhError; // Private data @@ -107,25 +108,25 @@ impl OvhClient { /// ; with a single consumer key. /// ;consumer_key=my_consumer_key /// ``` - pub fn from_conf(path: T) -> Result> + pub fn from_conf(path: T) -> Result where T: AsRef, { let mut conf = Ini::new(); - conf.load(path)?; + conf.load(path).map_err(|e| OvhError::Generic(e))?; let endpoint = conf .get("default", "endpoint") - .ok_or("missing key `endpoint`")?; + .ok_or(OvhError::Generic("missing key `endpoint`".to_owned()))?; let application_key = conf .get(&endpoint, "application_key") - .ok_or("missing key `application_key`")?; + .ok_or(OvhError::Generic("missing key `application_key`".to_owned()))?; let application_secret = conf .get(&endpoint, "application_secret") - .ok_or("missing key `application_secret`")?; + .ok_or(OvhError::Generic("missing key `application_secret`".to_owned()))?; let consumer_key = conf .get(&endpoint, "consumer_key") - .ok_or("missing key `consumer_key`")?; + .ok_or(OvhError::Generic("missing key `consumer_key`".to_owned()))?; let c = Self::new( &endpoint, @@ -133,7 +134,7 @@ impl OvhClient { &application_secret, &consumer_key, ) - .ok_or("failed to create client")?; + .ok_or(OvhError::Generic("failed to create client".to_owned()))?; Ok(c) } @@ -160,9 +161,10 @@ impl OvhClient { /// This method will perform a request to the API server to get its /// local time, and then subtract it from the local time of the machine. /// The result is a time delta value, is seconds. - pub async fn time_delta(&self) -> Result> { - let server_time: u64 = self.get_noauth("/auth/time").await?.text().await?.parse()?; - let delta = (now() - server_time).try_into()?; + pub async fn time_delta(&self) -> Result { + let server_time: u64 = self.get_noauth("/auth/time").await?.text().await.map_err(|e| OvhError::Reqwest)?.parse().map_err(|e| OvhError::ParseIntError)?; + + let delta = (now() - server_time).try_into().map_err(|e| OvhError::TryFromInt)?; Ok(delta) } @@ -180,11 +182,11 @@ impl OvhClient { url: &str, method: &str, body: &str, - ) -> Result> { + ) -> Result { let mut headers = self.default_headers(); let time_delta = self.time_delta().await?; - let now: i64 = now().try_into()?; + let now: i64 = now().try_into().map_err(|e| OvhError::TryFromInt)?; let timestamp = now + time_delta; let timestamp = timestamp.to_string(); @@ -198,11 +200,11 @@ impl OvhClient { } /// Performs a GET request. - pub async fn get(&self, path: &str) -> Result> { + pub async fn get(&self, path: &str) -> Result { let url = self.url(path); let headers = self.gen_headers(&url, "GET", "").await?; - let resp = self.client.get(url).headers(headers).send().await?; + let resp = self.client.get(url).headers(headers).send().await.map_err(|e| OvhError::Reqwest)?; Ok(resp) } @@ -210,11 +212,11 @@ impl OvhClient { pub async fn delete( &self, path: &str, - ) -> Result> { + ) -> Result { let url = self.url(path); let headers = self.gen_headers(&url, "DELETE", "").await?; - let resp = self.client.delete(url).headers(headers).send().await?; + let resp = self.client.delete(url).headers(headers).send().await.map_err(|e| OvhError::Reqwest)?; Ok(resp) } @@ -223,12 +225,12 @@ impl OvhClient { &self, path: &str, data: &T, - ) -> Result> { + ) -> Result { let url = self.url(path); // Cannot call RequestBuilder.json directly because of body // signature requirement. - let body = serde_json::to_string(data)?; + let body = serde_json::to_string(data).map_err(|e| OvhError::Serde)?; let headers = self.gen_headers(&url, "POST", &body).await?; let resp = self @@ -237,7 +239,7 @@ impl OvhClient { .headers(headers) .body(body) .send() - .await?; + .await.map_err(|e| OvhError::Reqwest)?; Ok(resp) } @@ -245,11 +247,11 @@ impl OvhClient { pub async fn get_noauth( &self, path: &str, - ) -> Result> { + ) -> Result { let url = self.url(path); let headers = self.default_headers(); - let resp = self.client.get(url).headers(headers).send().await?; + let resp = self.client.get(url).headers(headers).send().await.map_err(|e| OvhError::Reqwest)?; Ok(resp) } } diff --git a/src/email_redir.rs b/src/email_redir.rs index a50cab1..4e1bf52 100644 --- a/src/email_redir.rs +++ b/src/email_redir.rs @@ -7,6 +7,7 @@ use crate::client::OvhClient; use reqwest::Response; use serde::{Deserialize, Serialize}; +use crate::error::OvhError; /// Structure representing a single email redirection. #[derive(Debug, Deserialize)] @@ -25,12 +26,12 @@ impl OvhMailRedir { client: &OvhClient, domain: &str, id: &str, - ) -> Result> { + ) -> Result { let res = client .get(&format!("/email/domain/{}/redirection/{}", domain, id)) .await? .json() - .await?; + .await.map_err(|e| OvhError::Reqwest)?; Ok(res) } @@ -58,13 +59,13 @@ impl OvhMailRedir { pub async fn list( client: &OvhClient, domain: &str, - ) -> Result, Box> { + ) -> Result, OvhError> { let resp = client .get(&format!("/email/domain/{}/redirection", domain)) .await?; - let resp = resp.error_for_status()?; + let resp = resp.error_for_status().map_err(|e| OvhError::Reqwest)?; - let res = resp.json::>().await?; + let res = resp.json::>().await.map_err(|e| OvhError::Reqwest)?; let res: Vec<_> = futures::future::join_all(res.iter().map(|id| Self::get_redir(client, domain, id))) .await; @@ -94,7 +95,7 @@ impl OvhMailRedir { from: &str, to: &str, local_copy: bool, - ) -> Result> { + ) -> Result { let data = OvhMailRedirCreate { from, to, @@ -122,7 +123,7 @@ impl OvhMailRedir { c: &OvhClient, domain: &str, id: &str, - ) -> Result> { + ) -> Result { c.delete(&format!("/email/domain/{}/redirection/{}", domain, id)) .await } diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..47fb6a1 --- /dev/null +++ b/src/error.rs @@ -0,0 +1,23 @@ +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum OvhError { + + #[error("network issue")] + Reqwest, + + #[error("parseInt issue")] + ParseIntError, + + #[error("tryFromInt issue")] + TryFromInt, + + #[error("serde issue")] + Serde, + + #[error("generic error : `{0}`")] + Generic(String), + + #[error("unknown data store error")] + Unknown, +} \ No newline at end of file diff --git a/src/lib.rs b/src/lib.rs index ccd8681..c13b757 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,3 +2,4 @@ pub mod client; pub mod email_redir; +pub mod error; From 7d040b7d8afbca465b1e0c7f5821b3c8141a4ffb Mon Sep 17 00:00:00 2001 From: Aedius Date: Mon, 31 Jul 2023 20:41:17 +0200 Subject: [PATCH 2/2] derive error from previous --- src/client.rs | 72 +++++++++++++++++++++++++++++++--------------- src/email_redir.rs | 23 +++++++-------- src/error.rs | 17 ++++++----- 3 files changed, 67 insertions(+), 45 deletions(-) diff --git a/src/client.rs b/src/client.rs index 5ab505d..29efdb0 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,5 +1,6 @@ //! Low-level access to the OVH API. +use crate::error::OvhError; use configparser::ini::Ini; use reqwest::{header::HeaderMap, Response}; use serde::Serialize; @@ -8,7 +9,6 @@ use std::{ path::Path, time::{SystemTime, UNIX_EPOCH}, }; -use crate::error::OvhError; // Private data @@ -113,17 +113,21 @@ impl OvhClient { T: AsRef, { let mut conf = Ini::new(); - conf.load(path).map_err(|e| OvhError::Generic(e))?; + conf.load(path).map_err(OvhError::Generic)?; let endpoint = conf .get("default", "endpoint") .ok_or(OvhError::Generic("missing key `endpoint`".to_owned()))?; let application_key = conf .get(&endpoint, "application_key") - .ok_or(OvhError::Generic("missing key `application_key`".to_owned()))?; - let application_secret = conf - .get(&endpoint, "application_secret") - .ok_or(OvhError::Generic("missing key `application_secret`".to_owned()))?; + .ok_or(OvhError::Generic( + "missing key `application_key`".to_owned(), + ))?; + let application_secret = + conf.get(&endpoint, "application_secret") + .ok_or(OvhError::Generic( + "missing key `application_secret`".to_owned(), + ))?; let consumer_key = conf .get(&endpoint, "consumer_key") .ok_or(OvhError::Generic("missing key `consumer_key`".to_owned()))?; @@ -162,9 +166,18 @@ impl OvhClient { /// local time, and then subtract it from the local time of the machine. /// The result is a time delta value, is seconds. pub async fn time_delta(&self) -> Result { - let server_time: u64 = self.get_noauth("/auth/time").await?.text().await.map_err(|e| OvhError::Reqwest)?.parse().map_err(|e| OvhError::ParseIntError)?; - - let delta = (now() - server_time).try_into().map_err(|e| OvhError::TryFromInt)?; + let server_time: u64 = self + .get_noauth("/auth/time") + .await? + .text() + .await + .map_err(OvhError::Reqwest)? + .parse() + .map_err(OvhError::ParseIntError)?; + + let delta = (now() - server_time) + .try_into() + .map_err(OvhError::TryFromInt)?; Ok(delta) } @@ -186,7 +199,7 @@ impl OvhClient { let mut headers = self.default_headers(); let time_delta = self.time_delta().await?; - let now: i64 = now().try_into().map_err(|e| OvhError::TryFromInt)?; + let now: i64 = now().try_into().map_err(OvhError::TryFromInt)?; let timestamp = now + time_delta; let timestamp = timestamp.to_string(); @@ -204,19 +217,28 @@ impl OvhClient { let url = self.url(path); let headers = self.gen_headers(&url, "GET", "").await?; - let resp = self.client.get(url).headers(headers).send().await.map_err(|e| OvhError::Reqwest)?; + let resp = self + .client + .get(url) + .headers(headers) + .send() + .await + .map_err(OvhError::Reqwest)?; Ok(resp) } /// Performs a DELETE request. - pub async fn delete( - &self, - path: &str, - ) -> Result { + pub async fn delete(&self, path: &str) -> Result { let url = self.url(path); let headers = self.gen_headers(&url, "DELETE", "").await?; - let resp = self.client.delete(url).headers(headers).send().await.map_err(|e| OvhError::Reqwest)?; + let resp = self + .client + .delete(url) + .headers(headers) + .send() + .await + .map_err(OvhError::Reqwest)?; Ok(resp) } @@ -230,7 +252,7 @@ impl OvhClient { // Cannot call RequestBuilder.json directly because of body // signature requirement. - let body = serde_json::to_string(data).map_err(|e| OvhError::Serde)?; + let body = serde_json::to_string(data).map_err(OvhError::Serde)?; let headers = self.gen_headers(&url, "POST", &body).await?; let resp = self @@ -239,19 +261,23 @@ impl OvhClient { .headers(headers) .body(body) .send() - .await.map_err(|e| OvhError::Reqwest)?; + .await + .map_err(OvhError::Reqwest)?; Ok(resp) } /// Performs a GET request without auth. - pub async fn get_noauth( - &self, - path: &str, - ) -> Result { + pub async fn get_noauth(&self, path: &str) -> Result { let url = self.url(path); let headers = self.default_headers(); - let resp = self.client.get(url).headers(headers).send().await.map_err(|e| OvhError::Reqwest)?; + let resp = self + .client + .get(url) + .headers(headers) + .send() + .await + .map_err(OvhError::Reqwest)?; Ok(resp) } } diff --git a/src/email_redir.rs b/src/email_redir.rs index 4e1bf52..94e2556 100644 --- a/src/email_redir.rs +++ b/src/email_redir.rs @@ -6,8 +6,8 @@ use std::fmt::Display; use crate::client::OvhClient; use reqwest::Response; -use serde::{Deserialize, Serialize}; use crate::error::OvhError; +use serde::{Deserialize, Serialize}; /// Structure representing a single email redirection. #[derive(Debug, Deserialize)] @@ -31,7 +31,8 @@ impl OvhMailRedir { .get(&format!("/email/domain/{}/redirection/{}", domain, id)) .await? .json() - .await.map_err(|e| OvhError::Reqwest)?; + .await + .map_err(OvhError::Reqwest)?; Ok(res) } @@ -56,16 +57,16 @@ impl OvhMailRedir { /// } /// } /// ``` - pub async fn list( - client: &OvhClient, - domain: &str, - ) -> Result, OvhError> { + pub async fn list(client: &OvhClient, domain: &str) -> Result, OvhError> { let resp = client .get(&format!("/email/domain/{}/redirection", domain)) .await?; - let resp = resp.error_for_status().map_err(|e| OvhError::Reqwest)?; + let resp = resp.error_for_status().map_err(OvhError::Reqwest)?; - let res = resp.json::>().await.map_err(|e| OvhError::Reqwest)?; + let res = resp + .json::>() + .await + .map_err(OvhError::Reqwest)?; let res: Vec<_> = futures::future::join_all(res.iter().map(|id| Self::get_redir(client, domain, id))) .await; @@ -119,11 +120,7 @@ impl OvhMailRedir { /// .unwrap(); /// } /// ``` - pub async fn delete( - c: &OvhClient, - domain: &str, - id: &str, - ) -> Result { + pub async fn delete(c: &OvhClient, domain: &str, id: &str) -> Result { c.delete(&format!("/email/domain/{}/redirection/{}", domain, id)) .await } diff --git a/src/error.rs b/src/error.rs index 47fb6a1..4d2644d 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,23 +1,22 @@ +use reqwest::Error as ReqError; +use serde_json::Error as SerError; +use std::num::{ParseIntError, TryFromIntError}; use thiserror::Error; #[derive(Error, Debug)] pub enum OvhError { - #[error("network issue")] - Reqwest, + Reqwest(#[from] ReqError), #[error("parseInt issue")] - ParseIntError, + ParseIntError(#[from] ParseIntError), #[error("tryFromInt issue")] - TryFromInt, + TryFromInt(#[from] TryFromIntError), #[error("serde issue")] - Serde, + Serde(#[from] SerError), #[error("generic error : `{0}`")] Generic(String), - - #[error("unknown data store error")] - Unknown, -} \ No newline at end of file +}