diff --git a/matrix_sdk/src/client.rs b/matrix_sdk/src/client.rs index 2ea72ff1..6cdb7000 100644 --- a/matrix_sdk/src/client.rs +++ b/matrix_sdk/src/client.rs @@ -118,6 +118,7 @@ use matrix_sdk_common::{ }; use crate::{ + error::HttpError, http_client::{client_with_config, HttpClient, HttpSend}, Error, OutgoingRequest, Result, }; @@ -1451,7 +1452,7 @@ impl Client { content_type: Some(content_type.essence_str()), }); - self.http_client.upload(request).await + Ok(self.http_client.upload(request).await?) } /// Send an arbitrary request to the server, without updating client state. @@ -1494,9 +1495,9 @@ impl Client { pub async fn send(&self, request: Request) -> Result where Request: OutgoingRequest + Debug, - Error: From>, + HttpError: From>, { - self.http_client.send(request).await + Ok(self.http_client.send(request).await?) } #[cfg(feature = "encryption")] @@ -2276,7 +2277,7 @@ impl Client { #[cfg(test)] mod test { - use crate::ClientConfig; + use crate::{ClientConfig, HttpError}; use super::{ get_public_rooms, get_public_rooms_filtered, register::RegistrationKind, Client, @@ -2471,12 +2472,12 @@ mod test { .create(); if let Err(err) = client.login("example", "wordpass", None, None).await { - if let crate::Error::RumaResponse(crate::FromHttpResponseError::Http( - crate::ServerError::Known(crate::api::Error { + if let crate::Error::Http(HttpError::FromHttpResponse( + crate::FromHttpResponseError::Http(crate::ServerError::Known(crate::api::Error { kind, message, status_code, - }), + })), )) = err { if let crate::api::error::ErrorKind::Forbidden = kind { @@ -2517,10 +2518,10 @@ mod test { }); if let Err(err) = client.register(user).await { - if let crate::Error::UiaaError(crate::FromHttpResponseError::Http( + if let crate::Error::Http(HttpError::UiaaError(crate::FromHttpResponseError::Http( // TODO this should be a UiaaError need to investigate crate::ServerError::Unknown(e), - )) = err + ))) = err { assert!(e.to_string().starts_with("EOF while parsing")) } else { diff --git a/matrix_sdk/src/error.rs b/matrix_sdk/src/error.rs index 29b0d9b4..e4611628 100644 --- a/matrix_sdk/src/error.rs +++ b/matrix_sdk/src/error.rs @@ -20,7 +20,7 @@ use matrix_sdk_common::{ r0::uiaa::{UiaaInfo, UiaaResponse as UiaaError}, Error as RumaClientError, }, - FromHttpResponseError as RumaResponseError, IntoHttpError as RumaIntoHttpError, ServerError, + FromHttpResponseError, IntoHttpError, ServerError, }; use reqwest::Error as ReqwestError; use serde_json::Error as JsonError; @@ -33,9 +33,14 @@ use matrix_sdk_base::crypto::store::CryptoStoreError; /// Result type of the rust-sdk. pub type Result = std::result::Result; -/// Internal representation of errors. +/// An HTTP error, representing either a connection error or an error while +/// converting the raw HTTP response into a Matrix response. #[derive(Error, Debug)] -pub enum Error { +pub enum HttpError { + /// An error at the HTTP layer. + #[error(transparent)] + Reqwest(#[from] ReqwestError), + /// Queried endpoint requires authentication but was called on an anonymous client. #[error("the queried endpoint requires authentication but was called before logging in")] AuthenticationRequired, @@ -44,9 +49,33 @@ pub enum Error { #[error("the queried endpoint is not meant for clients")] NotClientRequest, - /// An error at the HTTP layer. + /// An error converting between ruma_client_api types and Hyper types. #[error(transparent)] - Reqwest(#[from] ReqwestError), + FromHttpResponse(#[from] FromHttpResponseError), + + /// An error converting between ruma_client_api types and Hyper types. + #[error(transparent)] + IntoHttp(#[from] IntoHttpError), + + /// An error occurred while authenticating. + /// + /// When registering or authenticating the Matrix server can send a `UiaaResponse` + /// as the error type, this is a User-Interactive Authentication API response. This + /// represents an error with information about how to authenticate the user. + #[error(transparent)] + UiaaError(#[from] FromHttpResponseError), +} + +/// Internal representation of errors. +#[derive(Error, Debug)] +pub enum Error { + /// Error doing an HTTP request. + #[error(transparent)] + Http(#[from] HttpError), + + /// Queried endpoint requires authentication but was called on an anonymous client. + #[error("the queried endpoint requires authentication but was called before logging in")] + AuthenticationRequired, /// An error de/serializing type for the `StateStore` #[error(transparent)] @@ -56,14 +85,6 @@ pub enum Error { #[error(transparent)] IO(#[from] IoError), - /// An error converting between ruma_client_api types and Hyper types. - #[error("can't parse the JSON response as a Matrix response")] - RumaResponse(RumaResponseError), - - /// An error converting between ruma_client_api types and Hyper types. - #[error("can't convert between ruma_client_api and hyper types.")] - IntoHttp(RumaIntoHttpError), - /// An error occurred in the Matrix client library. #[error(transparent)] MatrixError(#[from] MatrixError), @@ -76,14 +97,6 @@ pub enum Error { /// An error occured in the state store. #[error(transparent)] StateStore(#[from] StoreError), - - /// An error occurred while authenticating. - /// - /// When registering or authenticating the Matrix server can send a `UiaaResponse` - /// as the error type, this is a User-Interactive Authentication API response. This - /// represents an error with information about how to authenticate the user. - #[error("User-Interactive Authentication required.")] - UiaaError(RumaResponseError), } impl Error { @@ -99,9 +112,9 @@ impl Error { /// This method is an convenience method to get to the info the server /// returned on the first, failed request. pub fn uiaa_response(&self) -> Option<&UiaaInfo> { - if let Error::UiaaError(RumaResponseError::Http(ServerError::Known( + if let Error::Http(HttpError::UiaaError(FromHttpResponseError::Http(ServerError::Known( UiaaError::AuthResponse(i), - ))) = self + )))) = self { Some(i) } else { @@ -110,20 +123,8 @@ impl Error { } } -impl From> for Error { - fn from(error: RumaResponseError) -> Self { - Self::UiaaError(error) - } -} - -impl From> for Error { - fn from(error: RumaResponseError) -> Self { - Self::RumaResponse(error) - } -} - -impl From for Error { - fn from(error: RumaIntoHttpError) -> Self { - Self::IntoHttp(error) +impl From for Error { + fn from(e: ReqwestError) -> Self { + Error::Http(HttpError::Reqwest(e)) } } diff --git a/matrix_sdk/src/http_client.rs b/matrix_sdk/src/http_client.rs index fd84a424..64f83cc2 100644 --- a/matrix_sdk/src/http_client.rs +++ b/matrix_sdk/src/http_client.rs @@ -24,7 +24,7 @@ use matrix_sdk_common::{ FromHttpResponseError, }; -use crate::{ClientConfig, Error, OutgoingRequest, Result, Session}; +use crate::{error::HttpError, ClientConfig, OutgoingRequest, Session}; /// Abstraction around the http layer. The allows implementors to use different /// http libraries. @@ -74,7 +74,7 @@ pub trait HttpSend: AsyncTraitDeps { async fn send_request( &self, request: http::Request>, - ) -> Result>>; + ) -> Result>, HttpError>; } #[derive(Clone, Debug)] @@ -90,7 +90,7 @@ impl HttpClient { request: Request, session: Arc>>, content_type: Option, - ) -> Result>> { + ) -> Result>, HttpError> { let mut request = { let read_guard; let access_token = match Request::METADATA.authentication { @@ -100,11 +100,11 @@ impl HttpClient { if let Some(session) = read_guard.as_ref() { Some(session.access_token.as_str()) } else { - return Err(Error::AuthenticationRequired); + return Err(HttpError::AuthenticationRequired); } } AuthScheme::None => None, - _ => return Err(Error::NotClientRequest), + _ => return Err(HttpError::NotClientRequest), }; request.try_into_http_request(&self.homeserver.to_string(), access_token)? @@ -124,17 +124,20 @@ impl HttpClient { pub async fn upload( &self, request: create_content::Request<'_>, - ) -> Result { + ) -> Result { let response = self .send_request(request, self.session.clone(), None) .await?; Ok(create_content::Response::try_from(response)?) } - pub async fn send(&self, request: Request) -> Result + pub async fn send( + &self, + request: Request, + ) -> Result where - Request: OutgoingRequest, - Error: From>, + Request: OutgoingRequest + Debug, + HttpError: From>, { let content_type = HeaderValue::from_static("application/json"); let response = self @@ -143,12 +146,14 @@ impl HttpClient { trace!("Got response: {:?}", response); - Ok(Request::IncomingResponse::try_from(response)?) + let response = Request::IncomingResponse::try_from(response)?; + + Ok(response) } } /// Build a client with the specified configuration. -pub(crate) fn client_with_config(config: &ClientConfig) -> Result { +pub(crate) fn client_with_config(config: &ClientConfig) -> Result { let http_client = reqwest::Client::builder(); #[cfg(not(target_arch = "wasm32"))] @@ -188,7 +193,9 @@ pub(crate) fn client_with_config(config: &ClientConfig) -> Result { Ok(http_client.build()?) } -async fn response_to_http_response(mut response: Response) -> Result>> { +async fn response_to_http_response( + mut response: Response, +) -> Result>, reqwest::Error> { let status = response.status(); let mut http_builder = HttpResponse::builder().status(status); @@ -211,7 +218,7 @@ impl HttpSend for Client { async fn send_request( &self, request: http::Request>, - ) -> Result>> { + ) -> Result>, HttpError> { Ok( response_to_http_response(self.execute(reqwest::Request::try_from(request)?).await?) .await?, diff --git a/matrix_sdk/src/lib.rs b/matrix_sdk/src/lib.rs index 8528e920..23e14f8f 100644 --- a/matrix_sdk/src/lib.rs +++ b/matrix_sdk/src/lib.rs @@ -90,7 +90,7 @@ pub use client::{Client, ClientConfig, LoopCtrl, SyncSettings}; #[cfg(feature = "encryption")] #[cfg_attr(feature = "docs", doc(cfg(encryption)))] pub use device::Device; -pub use error::{Error, Result}; +pub use error::{Error, HttpError, Result}; pub use http_client::HttpSend; #[cfg(feature = "encryption")] #[cfg_attr(feature = "docs", doc(cfg(encryption)))]