use converge_core::ConvergeError;
use serde::Serialize;
use thiserror::Error;
use utoipa::ToSchema;
#[derive(Debug, Error, ToSchema)]
#[schema(as = RuntimeErrorResponse)]
pub enum RuntimeError {
#[error("converge error: {0}")]
Converge(#[from] ConvergeError),
#[error("serialization error: {0}")]
Serialization(#[from] serde_json::Error),
#[error("HTTP error: {0}")]
Http(#[from] axum::Error),
#[error("I/O error: {0}")]
Io(#[from] std::io::Error),
#[error("configuration error: {0}")]
Config(String),
}
#[derive(Debug, Serialize, ToSchema)]
pub struct RuntimeErrorResponse {
pub error: String,
pub status: u16,
}
pub type RuntimeResult<T> = Result<T, RuntimeError>;
impl axum::response::IntoResponse for RuntimeError {
fn into_response(self) -> axum::response::Response {
let (status, message) = match self {
RuntimeError::Converge(e) => {
let status = match e {
ConvergeError::BudgetExhausted { .. } => {
axum::http::StatusCode::PAYLOAD_TOO_LARGE
}
ConvergeError::InvariantViolation { .. } => {
axum::http::StatusCode::UNPROCESSABLE_ENTITY
}
ConvergeError::AgentFailed { .. } => {
axum::http::StatusCode::INTERNAL_SERVER_ERROR
}
ConvergeError::Conflict { .. } => axum::http::StatusCode::CONFLICT,
};
(status, format!("Converge error: {e}"))
}
RuntimeError::Serialization(e) => (
axum::http::StatusCode::BAD_REQUEST,
format!("Invalid JSON: {e}"),
),
RuntimeError::Http(e) => (
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
format!("HTTP error: {e}"),
),
RuntimeError::Io(e) => (
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
format!("I/O error: {e}"),
),
RuntimeError::Config(msg) => (
axum::http::StatusCode::INTERNAL_SERVER_ERROR,
format!("Configuration error: {msg}"),
),
};
let body = RuntimeErrorResponse {
error: message,
status: status.as_u16(),
};
(status, axum::Json(body)).into_response()
}
}