enigma_node_registry/
error.rs

1use actix_web::http::StatusCode;
2use actix_web::{HttpResponse, ResponseError};
3use serde::Serialize;
4use serde_json::Value;
5use thiserror::Error;
6
7pub type RegistryResult<T> = Result<T, RegistryError>;
8
9#[derive(Debug, Serialize)]
10pub struct ErrorResponse {
11    pub error: ErrorBody,
12}
13
14#[derive(Debug, Serialize)]
15pub struct ErrorBody {
16    pub code: String,
17    pub message: String,
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub details: Option<Value>,
20}
21
22#[derive(Debug, Error)]
23pub enum RegistryError {
24    #[error("invalid input: {0}")]
25    InvalidInput(String),
26    #[error("conflict")]
27    Conflict,
28    #[error("not found")]
29    NotFound,
30    #[error("rate limited")]
31    RateLimited,
32    #[error("pow required")]
33    PowRequired,
34    #[error("unauthorized")]
35    Unauthorized,
36    #[error("config error: {0}")]
37    Config(String),
38    #[error("feature disabled: {0}")]
39    FeatureDisabled(String),
40    #[error("internal error")]
41    Internal,
42}
43
44impl RegistryError {
45    pub fn with_details(self, details: Value) -> Self {
46        match self {
47            RegistryError::InvalidInput(msg) => {
48                RegistryError::InvalidInput(format!("{}: {}", msg, details))
49            }
50            RegistryError::Config(msg) => RegistryError::Config(format!("{}: {}", msg, details)),
51            other => other,
52        }
53    }
54}
55
56impl ResponseError for RegistryError {
57    fn status_code(&self) -> StatusCode {
58        match self {
59            RegistryError::InvalidInput(_) => StatusCode::BAD_REQUEST,
60            RegistryError::Conflict => StatusCode::CONFLICT,
61            RegistryError::NotFound => StatusCode::NOT_FOUND,
62            RegistryError::RateLimited => StatusCode::TOO_MANY_REQUESTS,
63            RegistryError::PowRequired => StatusCode::BAD_REQUEST,
64            RegistryError::Unauthorized => StatusCode::UNAUTHORIZED,
65            RegistryError::Config(_) => StatusCode::BAD_REQUEST,
66            RegistryError::FeatureDisabled(_) => StatusCode::BAD_REQUEST,
67            RegistryError::Internal => StatusCode::INTERNAL_SERVER_ERROR,
68        }
69    }
70
71    fn error_response(&self) -> HttpResponse {
72        let code = match self {
73            RegistryError::InvalidInput(_) => "INVALID_INPUT",
74            RegistryError::Conflict => "CONFLICT",
75            RegistryError::NotFound => "NOT_FOUND",
76            RegistryError::RateLimited => "RATE_LIMITED",
77            RegistryError::PowRequired => "POW_REQUIRED",
78            RegistryError::Unauthorized => "UNAUTHORIZED",
79            RegistryError::Config(_) => "CONFIG",
80            RegistryError::FeatureDisabled(_) => "FEATURE_DISABLED",
81            RegistryError::Internal => "INTERNAL",
82        };
83        let message = self.to_string();
84        let body = ErrorResponse {
85            error: ErrorBody {
86                code: code.to_string(),
87                message,
88                details: None,
89            },
90        };
91        HttpResponse::build(self.status_code()).json(body)
92    }
93}
94
95impl From<serde_json::Error> for RegistryError {
96    fn from(err: serde_json::Error) -> Self {
97        RegistryError::InvalidInput(err.to_string())
98    }
99}
100
101impl From<std::io::Error> for RegistryError {
102    fn from(err: std::io::Error) -> Self {
103        RegistryError::Config(err.to_string())
104    }
105}
106
107#[cfg(feature = "persistence")]
108impl From<sled::Error> for RegistryError {
109    fn from(err: sled::Error) -> Self {
110        RegistryError::Internal.with_details(serde_json::json!({ "error": err.to_string() }))
111    }
112}