1use axum::http::StatusCode;
4use axum::response::{IntoResponse, Response};
5use axum::Json;
6use kindling_service::ServiceError;
7use serde_json::json;
8
9#[derive(Debug, thiserror::Error)]
15pub enum ServerError {
16 #[error("a kindling daemon is already running (pid {0})")]
18 AlreadyRunning(i32),
19
20 #[error("pid file error: {0}")]
22 Pid(String),
23
24 #[error(transparent)]
26 Io(#[from] std::io::Error),
27
28 #[error(transparent)]
30 Service(#[from] ServiceError),
31}
32
33#[derive(Debug)]
35pub enum ApiError {
36 BadRequest(String),
38 NotFound(String),
40 Conflict(String),
42 Internal(String),
44}
45
46impl ApiError {
47 fn parts(&self) -> (StatusCode, &str) {
48 match self {
49 ApiError::BadRequest(m) => (StatusCode::BAD_REQUEST, m),
50 ApiError::NotFound(m) => (StatusCode::NOT_FOUND, m),
51 ApiError::Conflict(m) => (StatusCode::CONFLICT, m),
52 ApiError::Internal(m) => (StatusCode::INTERNAL_SERVER_ERROR, m),
53 }
54 }
55}
56
57impl From<ServiceError> for ApiError {
58 fn from(err: ServiceError) -> Self {
59 match err {
60 ServiceError::Validation(_) => ApiError::BadRequest(err.to_string()),
61 ServiceError::NotFound(_) => ApiError::NotFound(err.to_string()),
62 ServiceError::Conflict(_) | ServiceError::AlreadyClosed(_) => {
63 ApiError::Conflict(err.to_string())
64 }
65 ServiceError::Store(_) | ServiceError::Provider(_) | ServiceError::Json(_) => {
66 ApiError::Internal(err.to_string())
67 }
68 }
69 }
70}
71
72impl IntoResponse for ApiError {
73 fn into_response(self) -> Response {
74 let (status, message) = self.parts();
75 (status, Json(json!({ "error": message }))).into_response()
76 }
77}