use crate::types::GatewayErrorBody;
#[derive(Debug, thiserror::Error)]
pub enum SolariError {
#[error("{message}")]
Auth { status: u16, message: String, code: Option<String> },
#[error("{message}")]
Plan { status: u16, message: String, code: Option<String> },
#[error("{message}")]
ConcurrencyLimit { status: u16, message: String, code: Option<String> },
#[error("{message}")]
NoCapacity { status: u16, message: String, code: Option<String> },
#[error("{message}")]
Gateway { status: u16, message: String, code: Option<String> },
#[error("{message}")]
Action { method: String, message: String, code: Option<String> },
#[error("Action \"{method}\" timed out after {timeout_ms}ms")]
Timeout { method: String, timeout_ms: u64 },
#[error("{message}")]
Connection { message: String },
#[error("{message}")]
Git { message: String },
#[error("{0}")]
Other(String),
}
impl SolariError {
pub(crate) fn connection(msg: impl Into<String>) -> Self {
SolariError::Connection { message: msg.into() }
}
pub fn status(&self) -> Option<u16> {
match self {
SolariError::Auth { status, .. }
| SolariError::Plan { status, .. }
| SolariError::ConcurrencyLimit { status, .. }
| SolariError::NoCapacity { status, .. }
| SolariError::Gateway { status, .. } => Some(*status),
_ => None,
}
}
}
pub(crate) fn map_gateway_error(status: u16, body: Option<GatewayErrorBody>) -> SolariError {
let code = body.as_ref().and_then(|b| b.code.clone());
let message = body
.as_ref()
.and_then(|b| b.message.clone().or_else(|| b.error.clone()).or_else(|| b.code.clone()))
.unwrap_or_else(|| format!("Gateway request failed with status {status}"));
match status {
401 | 403 => SolariError::Auth { status, message, code },
402 => SolariError::Plan { status, message, code },
429 => SolariError::ConcurrencyLimit { status, message, code },
503 => SolariError::NoCapacity { status, message, code },
_ => SolariError::Gateway { status, message, code },
}
}
pub(crate) fn is_route_unavailable(err: &SolariError) -> bool {
matches!(err.status(), Some(404) | Some(405) | Some(501))
}