use std::io::Error as IoError;
use http::StatusCode;
#[cfg(feature = "qrcode")]
use matrix_sdk_base::crypto::ScanError;
#[cfg(feature = "e2e-encryption")]
use matrix_sdk_base::crypto::{
CryptoStoreError, DecryptorError, KeyExportError, MegolmError, OlmError,
};
use matrix_sdk_base::{Error as SdkBaseError, StoreError};
use reqwest::Error as ReqwestError;
use ruma::{
api::{
client::uiaa::{UiaaInfo, UiaaResponse as UiaaError},
error::{FromHttpResponseError, IntoHttpError, ServerError},
},
events::tag::InvalidUserTagName,
IdParseError,
};
use serde_json::Error as JsonError;
use thiserror::Error;
use url::ParseError as UrlParseError;
pub type Result<T, E = Error> = std::result::Result<T, E>;
pub type HttpResult<T> = std::result::Result<T, HttpError>;
#[derive(Error, Debug)]
pub enum RumaApiError {
#[error(transparent)]
ClientApi(ruma::api::client::Error),
#[error(transparent)]
Other(ruma::api::error::MatrixError),
}
#[derive(Error, Debug)]
pub enum HttpError {
#[error(transparent)]
Reqwest(#[from] ReqwestError),
#[error("the queried endpoint requires authentication but was called before logging in")]
AuthenticationRequired,
#[error("the queried endpoint is not meant for clients")]
NotClientRequest,
#[error(transparent)]
Api(FromHttpResponseError<RumaApiError>),
#[error(transparent)]
IntoHttp(#[from] IntoHttpError),
#[error(transparent)]
UiaaError(#[from] FromHttpResponseError<UiaaError>),
#[error("Server returned an error {0}")]
Server(StatusCode),
#[error("The request cannot be cloned")]
UnableToCloneRequest,
#[error(transparent)]
RefreshToken(#[from] RefreshTokenError),
}
#[derive(Error, Debug)]
#[non_exhaustive]
pub enum Error {
#[error(transparent)]
Http(#[from] HttpError),
#[error("the queried endpoint requires authentication but was called before logging in")]
AuthenticationRequired,
#[cfg(feature = "e2e-encryption")]
#[error("The olm machine has already been initialized")]
BadCryptoStoreState,
#[cfg(feature = "e2e-encryption")]
#[error("The olm machine isn't yet available")]
NoOlmMachine,
#[error(transparent)]
SerdeJson(#[from] JsonError),
#[error(transparent)]
Io(#[from] IoError),
#[cfg(feature = "e2e-encryption")]
#[error(transparent)]
CryptoStoreError(#[from] CryptoStoreError),
#[cfg(feature = "e2e-encryption")]
#[error(transparent)]
OlmError(#[from] OlmError),
#[cfg(feature = "e2e-encryption")]
#[error(transparent)]
MegolmError(#[from] MegolmError),
#[cfg(feature = "e2e-encryption")]
#[error(transparent)]
DecryptorError(#[from] DecryptorError),
#[error(transparent)]
StateStore(#[from] StoreError),
#[error(transparent)]
Identifier(#[from] IdParseError),
#[error(transparent)]
Url(#[from] UrlParseError),
#[cfg(feature = "qrcode")]
#[error(transparent)]
QrCodeScanError(#[from] ScanError),
#[error(transparent)]
UserTagName(#[from] InvalidUserTagName),
#[cfg(feature = "image-proc")]
#[error(transparent)]
ImageError(#[from] ImageError),
#[error("unknown error: {0}")]
UnknownError(Box<dyn std::error::Error + Send + Sync>),
}
#[cfg(feature = "e2e-encryption")]
#[derive(Error, Debug)]
#[allow(dead_code)]
pub enum RoomKeyImportError {
#[error(transparent)]
SerdeJson(#[from] JsonError),
#[error("The crypto store hasn't been yet opened, can't import yet.")]
StoreClosed,
#[error(transparent)]
Io(#[from] IoError),
#[error(transparent)]
CryptoStore(#[from] CryptoStoreError),
#[error(transparent)]
Export(#[from] KeyExportError),
}
impl HttpError {
pub fn uiaa_response(&self) -> Option<&UiaaInfo> {
if let HttpError::UiaaError(FromHttpResponseError::Server(ServerError::Known(
UiaaError::AuthResponse(i),
))) = self
{
Some(i)
} else {
None
}
}
}
impl Error {
pub fn uiaa_response(&self) -> Option<&UiaaInfo> {
if let Error::Http(HttpError::UiaaError(FromHttpResponseError::Server(
ServerError::Known(UiaaError::AuthResponse(i)),
))) = self
{
Some(i)
} else {
None
}
}
}
impl From<FromHttpResponseError<ruma::api::client::Error>> for HttpError {
fn from(err: FromHttpResponseError<ruma::api::client::Error>) -> Self {
Self::Api(err.map(|e| e.map(RumaApiError::ClientApi)))
}
}
impl From<FromHttpResponseError<ruma::api::error::MatrixError>> for HttpError {
fn from(err: FromHttpResponseError<ruma::api::error::MatrixError>) -> Self {
Self::Api(err.map(|e| e.map(RumaApiError::Other)))
}
}
impl From<SdkBaseError> for Error {
fn from(e: SdkBaseError) -> Self {
match e {
SdkBaseError::AuthenticationRequired => Self::AuthenticationRequired,
SdkBaseError::StateStore(e) => Self::StateStore(e),
SdkBaseError::SerdeJson(e) => Self::SerdeJson(e),
SdkBaseError::IoError(e) => Self::Io(e),
#[cfg(feature = "e2e-encryption")]
SdkBaseError::CryptoStore(e) => Self::CryptoStoreError(e),
#[cfg(feature = "e2e-encryption")]
SdkBaseError::BadCryptoStoreState => Self::BadCryptoStoreState,
#[cfg(feature = "e2e-encryption")]
SdkBaseError::OlmError(e) => Self::OlmError(e),
#[cfg(feature = "e2e-encryption")]
SdkBaseError::MegolmError(e) => Self::MegolmError(e),
#[cfg(feature = "eyre")]
_ => Self::UnknownError(eyre::eyre!(e).into()),
#[cfg(all(not(feature = "eyre"), feature = "anyhow"))]
_ => Self::UnknownError(anyhow::anyhow!(e).into()),
#[cfg(all(not(feature = "eyre"), not(feature = "anyhow")))]
_ => {
let e: Box<dyn std::error::Error + Sync + Send> = format!("{:?}", e).into();
Self::UnknownError(e)
}
}
}
}
impl From<ReqwestError> for Error {
fn from(e: ReqwestError) -> Self {
Error::Http(HttpError::Reqwest(e))
}
}
#[cfg(feature = "image-proc")]
#[derive(Error, Debug)]
pub enum ImageError {
#[error(transparent)]
Proc(#[from] image::ImageError),
#[error("the image format is not supported")]
FormatNotSupported,
#[error("the thumbnail size is bigger than the original image size")]
ThumbnailBiggerThanOriginal,
}
#[derive(Debug, Error, Clone)]
pub enum RefreshTokenError {
#[error(transparent)]
ClientApi(#[from] ruma::api::client::Error),
#[error("missing refresh token")]
RefreshTokenRequired,
#[error("the access token could not be refreshed")]
UnableToRefreshToken,
}