use std::fmt;
#[derive(thiserror::Error, Debug, Clone)]
pub struct Error {
pub code: ErrorCode,
pub status: u16,
pub message: String,
pub server_code: Option<i64>,
pub ip_address: Option<String>,
pub retry_after_ms: Option<u64>,
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
if self.status == 0 {
write!(f, "cryptohopper: [{}] {}", self.code, self.message)
} else {
write!(
f,
"cryptohopper: [{} {}] {}",
self.code, self.status, self.message
)
}
}
}
impl Error {
pub(crate) fn network(message: impl Into<String>) -> Self {
Error {
code: ErrorCode::NetworkError,
status: 0,
message: message.into(),
server_code: None,
ip_address: None,
retry_after_ms: None,
}
}
pub(crate) fn timeout(message: impl Into<String>) -> Self {
Error {
code: ErrorCode::Timeout,
status: 0,
message: message.into(),
server_code: None,
ip_address: None,
retry_after_ms: None,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ErrorCode {
ValidationError,
Unauthorized,
Forbidden,
NotFound,
Conflict,
RateLimited,
ServerError,
ServiceUnavailable,
DeviceUnauthorized,
NetworkError,
Timeout,
Unknown,
Other(String),
}
impl ErrorCode {
pub fn as_str(&self) -> &str {
match self {
ErrorCode::ValidationError => "VALIDATION_ERROR",
ErrorCode::Unauthorized => "UNAUTHORIZED",
ErrorCode::Forbidden => "FORBIDDEN",
ErrorCode::NotFound => "NOT_FOUND",
ErrorCode::Conflict => "CONFLICT",
ErrorCode::RateLimited => "RATE_LIMITED",
ErrorCode::ServerError => "SERVER_ERROR",
ErrorCode::ServiceUnavailable => "SERVICE_UNAVAILABLE",
ErrorCode::DeviceUnauthorized => "DEVICE_UNAUTHORIZED",
ErrorCode::NetworkError => "NETWORK_ERROR",
ErrorCode::Timeout => "TIMEOUT",
ErrorCode::Unknown => "UNKNOWN",
ErrorCode::Other(s) => s.as_str(),
}
}
pub(crate) fn from_status(status: u16) -> Self {
match status {
400 | 422 => ErrorCode::ValidationError,
401 => ErrorCode::Unauthorized,
402 => ErrorCode::DeviceUnauthorized,
403 => ErrorCode::Forbidden,
404 => ErrorCode::NotFound,
409 => ErrorCode::Conflict,
429 => ErrorCode::RateLimited,
503 => ErrorCode::ServiceUnavailable,
s if s >= 500 => ErrorCode::ServerError,
_ => ErrorCode::Unknown,
}
}
}
impl fmt::Display for ErrorCode {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str(self.as_str())
}
}