use thiserror::Error;
#[derive(Error, Debug, Clone)]
pub enum CloudError {
#[error("HTTP request failed: {0}")]
Request(String),
#[error("Bad Request (400): {message}")]
BadRequest {
message: String,
},
#[error("Authentication failed (401): {message}")]
AuthenticationFailed {
message: String,
},
#[error("Forbidden (403): {message}")]
Forbidden {
message: String,
},
#[error("Not Found (404): {message}")]
NotFound {
message: String,
},
#[error("Precondition Failed (412): Feature flag for this flow is off")]
PreconditionFailed,
#[error("Rate Limited (429): {message}")]
RateLimited {
message: String,
},
#[error("Internal Server Error (500): {message}")]
InternalServerError {
message: String,
},
#[error("Service Unavailable (503): {message}")]
ServiceUnavailable {
message: String,
},
#[error("API error ({code}): {message}")]
ApiError {
code: u16,
message: String,
},
#[error("Connection error: {0}")]
ConnectionError(String),
#[error("JSON error: {0}")]
JsonError(String),
}
impl CloudError {
#[must_use]
pub fn is_retryable(&self) -> bool {
matches!(
self,
CloudError::RateLimited { .. }
| CloudError::ServiceUnavailable { .. }
| CloudError::Request(_)
| CloudError::ConnectionError(_)
)
}
#[must_use]
pub fn is_not_found(&self) -> bool {
matches!(self, CloudError::NotFound { .. })
}
#[must_use]
pub fn is_unauthorized(&self) -> bool {
matches!(
self,
CloudError::AuthenticationFailed { .. } | CloudError::Forbidden { .. }
)
}
#[must_use]
pub fn is_server_error(&self) -> bool {
matches!(
self,
CloudError::InternalServerError { .. } | CloudError::ServiceUnavailable { .. }
)
}
#[must_use]
pub fn is_timeout(&self) -> bool {
match self {
CloudError::ConnectionError(msg) | CloudError::Request(msg) => {
msg.to_lowercase().contains("timeout")
}
_ => false,
}
}
#[must_use]
pub fn is_rate_limited(&self) -> bool {
matches!(self, CloudError::RateLimited { .. })
}
#[must_use]
pub fn is_conflict(&self) -> bool {
matches!(self, CloudError::PreconditionFailed)
}
#[must_use]
pub fn is_bad_request(&self) -> bool {
matches!(self, CloudError::BadRequest { .. })
}
}
impl From<reqwest::Error> for CloudError {
fn from(err: reqwest::Error) -> Self {
CloudError::Request(err.to_string())
}
}
impl From<serde_json::Error> for CloudError {
fn from(err: serde_json::Error) -> Self {
CloudError::JsonError(err.to_string())
}
}
pub type Result<T> = std::result::Result<T, CloudError>;