use core::error::Error as _;
use snafu::Snafu;
use ureq::http::Uri;
#[derive(Debug, Snafu)]
#[snafu(visibility(pub(crate)))]
pub enum ApiRequestError {
#[snafu(display("Couldn't successfully send the http request to {uri}"))]
UreqError {
source: ureq::Error,
#[snafu(implicit)]
location: snafu::Location,
uri: Uri,
#[cfg(feature = "backtrace")]
backtrace: snafu::Backtrace,
},
#[snafu(display("Couldn't parse the response of {uri}"))]
ParsingError {
source: ureq::Error,
#[snafu(implicit)]
location: snafu::Location,
uri: Uri,
#[cfg(feature = "backtrace")]
backtrace: snafu::Backtrace,
},
#[snafu(display(
"The max retry count for the request as been exeeded. You may want to check if the correct url is set, the server is online, or you aren't hitting the ratelimit."
))]
MaxRetriesExceeded {
#[snafu(implicit)]
location: snafu::Location,
#[cfg(feature = "backtrace")]
backtrace: snafu::Backtrace,
},
#[snafu(display("The api's response couldn't be deserialized:\n{data}"))]
JsonParsingError {
source: serde_json::Error,
data: String,
#[snafu(implicit)]
location: snafu::Location,
#[cfg(feature = "backtrace")]
backtrace: snafu::Backtrace,
},
#[cfg(feature = "image")]
#[snafu(display("Couldn't parse the image"))]
ImageParsingError {
source: image::ImageError,
data: Vec<u8>,
#[snafu(implicit)]
location: snafu::Location,
#[cfg(feature = "backtrace")]
backtrace: snafu::Backtrace,
},
}
impl ApiRequestError {
pub fn is_retryable(&self) -> bool {
self.is_timeout() || self.is_connection_reset() || self.is_peer_disconnected()
}
pub fn is_timeout(&self) -> bool {
let Some(source) = self.source() else {
return false;
};
let Some(ureq_error) = source.downcast_ref::<ureq::Error>() else {
return false;
};
matches!(ureq_error, ureq::Error::Timeout(_))
}
pub fn is_connection_reset(&self) -> bool {
let Some(source) = self.source() else {
return false;
};
let Some(ureq_error) = source.downcast_ref::<ureq::Error>() else {
return false;
};
let ureq::Error::Io(std_error) = ureq_error else {
return false;
};
std_error.kind() == std::io::ErrorKind::ConnectionReset
}
pub fn is_peer_disconnected(&self) -> bool {
let Some(source) = self.source() else {
return false;
};
let Some(ureq_error) = source.downcast_ref::<ureq::Error>() else {
return false;
};
let ureq::Error::Io(std_error) = ureq_error else {
return false;
};
std_error.kind() == std::io::ErrorKind::UnexpectedEof
}
}