From 08eec0b60c3b8a9b65d5363e8c13c48d01d29e0d Mon Sep 17 00:00:00 2001 From: Volodymyr Kostyrko Date: Tue, 20 Aug 2024 19:01:07 +0300 Subject: [PATCH] abolish ErrorKind, bring in thiserror, now all Error's can be matched --- lib/Cargo.toml | 1 + lib/src/api.rs | 8 +-- lib/src/connector/hyper.rs | 20 +++--- lib/src/errors.rs | 69 ++++--------------- lib/src/lib.rs | 2 +- raw/Cargo.toml | 2 +- raw/src/requests/_base/errors.rs | 57 +++------------ raw/src/requests/_base/mod.rs | 1 - .../requests/_base/request_types/detached.rs | 2 +- raw/src/requests/_base/request_types/json.rs | 2 +- .../requests/_base/request_types/multipart.rs | 2 +- raw/src/requests/_base/response_types/json.rs | 6 +- 12 files changed, 45 insertions(+), 127 deletions(-) diff --git a/lib/Cargo.toml b/lib/Cargo.toml index 8eaa0242c5..fab597a639 100644 --- a/lib/Cargo.toml +++ b/lib/Cargo.toml @@ -21,6 +21,7 @@ default = ["openssl"] [dependencies] bytes = "1.0.1" +thiserror = "1.0.63" tokio = { version = "1.2", features = ["fs", "rt"]} tracing = "0.1.23" diff --git a/lib/src/api.rs b/lib/src/api.rs index 4afad4550b..9d3e577282 100644 --- a/lib/src/api.rs +++ b/lib/src/api.rs @@ -11,7 +11,7 @@ use tracing_futures::Instrument; use telegram_bot_raw::{HttpRequest, Request, ResponseType}; use crate::connector::{default_connector, Connector}; -use crate::errors::{Error, ErrorKind}; +use crate::errors::Error; use crate::stream::UpdatesStream; /// Main type for sending requests to the Telegram bot API. @@ -130,7 +130,7 @@ impl Api { async move { match timeout( duration, - api.send_http_request::(request.map_err(ErrorKind::from)?), + api.send_http_request::(request.map_err(Error::from)?), ) .await { @@ -165,7 +165,7 @@ impl Api { let api = self.clone(); let request = request.serialize(); async move { - api.send_http_request::(request.map_err(ErrorKind::from)?) + api.send_http_request::(request.map_err(Error::from)?) .await } } @@ -186,7 +186,7 @@ impl Api { }, "response received" ); - let response = Resp::deserialize(http_response).map_err(ErrorKind::from)?; + let response = Resp::deserialize(http_response).map_err(Error::from)?; tracing::trace!("response deserialized"); Ok(response) } diff --git a/lib/src/connector/hyper.rs b/lib/src/connector/hyper.rs index 11d417d737..a0fac454bc 100644 --- a/lib/src/connector/hyper.rs +++ b/lib/src/connector/hyper.rs @@ -22,7 +22,7 @@ use telegram_bot_raw::{ }; use super::Connector; -use crate::errors::{Error, ErrorKind}; +use crate::errors::Error; #[derive(Debug)] pub struct HyperConnector(Client); @@ -48,7 +48,7 @@ impl Connector for let client = self.0.clone(); let future = async move { - let uri = uri.map_err(HttpError::from).map_err(ErrorKind::from)?; + let uri = uri.map_err(HttpError::from).map_err(Error::from)?; let method = match req.method { TelegramMethod::Get => Method::GET, @@ -63,7 +63,7 @@ impl Connector for let content_type = "application/json" .parse() .map_err(HttpError::from) - .map_err(ErrorKind::from)?; + .map_err(Error::from)?; http_request .headers_mut() .map(move |headers| headers.insert(CONTENT_TYPE, content_type)); @@ -84,9 +84,9 @@ impl Connector for .and_then(|s| s.to_str()) .map(Into::into) }) - .ok_or(ErrorKind::InvalidMultipartFilename)?; + .ok_or(Error::InvalidMultipartFilename)?; - let data = tokio::fs::read(path).await.map_err(ErrorKind::from)?; + let data = tokio::fs::read(path).await.map_err(Error::from)?; fields.push(( key, MultipartTemporaryValue::Data { @@ -119,7 +119,7 @@ impl Connector for } part.prepare().map_err(|err| err.error) } - .map_err(ErrorKind::from)?; + .map_err(Error::from)?; let boundary = prepared.boundary(); @@ -127,20 +127,20 @@ impl Connector for format!("multipart/form-data;boundary={bound}", bound = boundary) .parse() .map_err(HttpError::from) - .map_err(ErrorKind::from)?; + .map_err(Error::from)?; if let Some(headers) = http_request.headers_mut() { headers.insert(CONTENT_TYPE, content_type); } let mut bytes = Vec::new(); - prepared.read_to_end(&mut bytes).map_err(ErrorKind::from)?; + prepared.read_to_end(&mut bytes).map_err(Error::from)?; http_request.body(bytes.into()) } body => panic!("Unknown body type {:?}", body), } - .map_err(ErrorKind::from)?; + .map_err(Error::from)?; - let response = client.request(request).await.map_err(ErrorKind::from)?; + let response = client.request(request).await.map_err(Error::from)?; let whole_chunk = to_bytes(response.into_body()).await; let body = whole_chunk diff --git a/lib/src/errors.rs b/lib/src/errors.rs index 0f632eed93..3e68052c21 100644 --- a/lib/src/errors.rs +++ b/lib/src/errors.rs @@ -1,58 +1,15 @@ -use std::error; -use std::fmt; - -#[derive(Debug)] -pub struct Error(ErrorKind); - -#[derive(Debug)] -pub enum ErrorKind { - Raw(telegram_bot_raw::Error), - Hyper(hyper::Error), - Http(hyper::http::Error), - Io(std::io::Error), +use thiserror::Error; + +#[derive(Error, Debug)] +pub enum Error { + #[error("error from Hyper library")] + Hyper(#[from] hyper::Error), + #[error("http request error from Hyper library")] + Http(#[from] hyper::http::Error), + #[error("Invalid multipart filename")] InvalidMultipartFilename, + #[error("ordinary IO Error")] + Io(#[from] std::io::Error), + #[error("raw error from Telegram API")] + Raw(#[from] telegram_bot_raw::Error), } - -impl From for ErrorKind { - fn from(error: telegram_bot_raw::Error) -> Self { - ErrorKind::Raw(error) - } -} - -impl From for ErrorKind { - fn from(error: hyper::Error) -> Self { - ErrorKind::Hyper(error) - } -} - -impl From for ErrorKind { - fn from(error: hyper::http::Error) -> Self { - ErrorKind::Http(error) - } -} - -impl From for ErrorKind { - fn from(error: std::io::Error) -> Self { - ErrorKind::Io(error) - } -} - -impl From for Error { - fn from(kind: ErrorKind) -> Self { - Error(kind) - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self.0 { - ErrorKind::Raw(error) => write!(f, "{}", error), - ErrorKind::Hyper(error) => write!(f, "{}", error), - ErrorKind::Http(error) => write!(f, "{}", error), - ErrorKind::Io(error) => write!(f, "{}", error), - ErrorKind::InvalidMultipartFilename => write!(f, "invalid multipart filename"), - } - } -} - -impl error::Error for Error {} diff --git a/lib/src/lib.rs b/lib/src/lib.rs index e7eeff69a6..615fa97439 100644 --- a/lib/src/lib.rs +++ b/lib/src/lib.rs @@ -12,7 +12,7 @@ pub mod types; pub mod util; pub use self::api::Api; -pub use self::errors::{Error, ErrorKind}; +pub use self::errors::Error; pub use prelude::*; pub use stream::UpdatesStream; pub use types::*; diff --git a/raw/Cargo.toml b/raw/Cargo.toml index 030c48b7b6..1157f013a9 100644 --- a/raw/Cargo.toml +++ b/raw/Cargo.toml @@ -15,9 +15,9 @@ categories = ["api-bindings"] license = "MIT" [dependencies] -anyhow = "1.0.86" bytes = "1.0" serde = { version = "1", features = ["derive"] } serde_derive = "1" serde_json = "1" serde-value = "0.7.0" +thiserror = "1.0.63" diff --git a/raw/src/requests/_base/errors.rs b/raw/src/requests/_base/errors.rs index b8101fead8..10eec45f2b 100644 --- a/raw/src/requests/_base/errors.rs +++ b/raw/src/requests/_base/errors.rs @@ -1,57 +1,18 @@ -use std::error; -use std::fmt; +use thiserror::Error; use crate::types::*; -#[derive(Debug)] -pub struct Error(ErrorKind); - -#[derive(Debug)] -pub enum ErrorKind { +#[derive(Error, Debug)] +pub enum Error { + #[error("Emtpy body")] EmptyBody, + #[error("Detached error")] + DetachedError(String), + #[error("JSON ser/de error")] + Json(#[from] serde_json::Error), + #[error("Telegram error")] TelegramError { description: String, parameters: Option, }, - DetachedError(String), - Json(::serde_json::Error), -} - -impl From<::serde_json::Error> for ErrorKind { - fn from(error: ::serde_json::Error) -> Self { - ErrorKind::Json(error) - } } - -impl From for Error { - fn from(kind: ErrorKind) -> Self { - Error(kind) - } -} - -impl fmt::Display for Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match &self.0 { - ErrorKind::EmptyBody => write!(f, "empty body"), - ErrorKind::TelegramError { - description, - parameters, - } => { - f.write_str(description)?; - if let Some(parameters) = parameters { - if let Some(chat_id) = parameters.migrate_to_chat_id { - write!(f, ", migrate to chat id: {}", chat_id)?; - } - if let Some(seconds) = parameters.retry_after { - write!(f, ", retry after: {}", seconds)?; - } - } - Ok(()) - } - ErrorKind::DetachedError(s) => f.write_str(s), - ErrorKind::Json(error) => write!(f, "{}", error), - } - } -} - -impl error::Error for Error {} diff --git a/raw/src/requests/_base/mod.rs b/raw/src/requests/_base/mod.rs index e8f300d0b6..01869511ae 100644 --- a/raw/src/requests/_base/mod.rs +++ b/raw/src/requests/_base/mod.rs @@ -3,7 +3,6 @@ pub use self::_base::*; mod errors; pub use self::errors::Error; -pub(crate) use self::errors::ErrorKind; mod http; pub use self::http::{Body, Multipart, MultipartValue, RequestUrl}; diff --git a/raw/src/requests/_base/request_types/detached.rs b/raw/src/requests/_base/request_types/detached.rs index 58b10eb599..504df11707 100644 --- a/raw/src/requests/_base/request_types/detached.rs +++ b/raw/src/requests/_base/request_types/detached.rs @@ -10,7 +10,7 @@ impl RequestType for DetachedRequestType { fn serialize(_options: Self::Options, request: &Self::Request) -> Result { match request { Ok(ref req) => Ok(req.clone()), - Err(ref err) => Err(ErrorKind::DetachedError(err.to_string()).into()), + Err(ref err) => Err(Error::DetachedError(err.to_string()).into()), } } } diff --git a/raw/src/requests/_base/request_types/json.rs b/raw/src/requests/_base/request_types/json.rs index 1390c46051..011fc144e1 100644 --- a/raw/src/requests/_base/request_types/json.rs +++ b/raw/src/requests/_base/request_types/json.rs @@ -12,7 +12,7 @@ impl RequestType for JsonRequestType { type Request = Request; fn serialize(url: Self::Options, request: &Self::Request) -> Result { - let body = serde_json::to_string(&request).map_err(ErrorKind::from)?; + let body = serde_json::to_string(&request).map_err(Error::from)?; Ok(HttpRequest { url, method: Method::Post, diff --git a/raw/src/requests/_base/request_types/multipart.rs b/raw/src/requests/_base/request_types/multipart.rs index 6e04cd3347..07fd0534de 100644 --- a/raw/src/requests/_base/request_types/multipart.rs +++ b/raw/src/requests/_base/request_types/multipart.rs @@ -74,7 +74,7 @@ macro_rules! multipart_field { }}; ($self:expr, $result:expr, $field:ident(json) => $val:expr) => {{ - let s = ::serde_json::to_string($val).map_err(ErrorKind::from)?; + let s = ::serde_json::to_string($val).map_err(Error::from)?; let value = MultipartValue::Text(s.into()); $result.push((stringify!($field), value)); }}; diff --git a/raw/src/requests/_base/response_types/json.rs b/raw/src/requests/_base/response_types/json.rs index 2a56ee4ece..0cb25e6ef8 100644 --- a/raw/src/requests/_base/response_types/json.rs +++ b/raw/src/requests/_base/response_types/json.rs @@ -40,20 +40,20 @@ where fn deserialize(resp: HttpResponse) -> Result { if let Some(body) = resp.body.as_ref() { - let raw = serde_json::from_slice(body).map_err(ErrorKind::from)?; + let raw = serde_json::from_slice(body).map_err(Error::from)?; match raw { ResponseWrapper::Success { result } => Ok(::map(result)), ResponseWrapper::Error { description, parameters, - } => Err(ErrorKind::TelegramError { + } => Err(Error::TelegramError { description, parameters, } .into()), } } else { - Err(ErrorKind::EmptyBody.into()) + Err(Error::EmptyBody.into()) } } }