1use thiserror::Error;
8use warp::Reply;
9
10pub type Result<T> = std::result::Result<T, Error>;
12
13#[derive(Error, Debug)]
15pub enum Error {
16 #[error("Invalid DIDComm message: {0}")]
18 DIDComm(String),
19
20 #[error("Message validation failed: {0}")]
22 Validation(String),
23
24 #[error("Message authentication failed: {0}")]
26 Authentication(String),
27
28 #[error("JSON error: {0}")]
30 Json(String),
31
32 #[error("HTTP error: {0}")]
34 Http(String),
35
36 #[error("TAP Node error: {0}")]
38 Node(String),
39
40 #[error("Configuration error: {0}")]
42 Config(String),
43
44 #[error("IO error: {0}")]
46 Io(#[from] std::io::Error),
47
48 #[error("Rate limit exceeded: {0}")]
50 RateLimit(String),
51
52 #[error("TLS error: {0}")]
54 Tls(String),
55
56 #[error("Unknown error: {0}")]
58 Unknown(String),
59}
60
61#[derive(Debug, Clone, Copy, PartialEq, Eq)]
63pub enum ErrorSeverity {
64 Info,
66 Warning,
68 Critical,
70}
71
72impl Error {
73 pub fn status_code(&self) -> warp::http::StatusCode {
75 use warp::http::StatusCode;
76
77 match self {
78 Error::DIDComm(_) | Error::Validation(_) | Error::Json(_) => StatusCode::BAD_REQUEST,
79 Error::Authentication(_) => StatusCode::UNAUTHORIZED,
80 Error::RateLimit(_) => StatusCode::TOO_MANY_REQUESTS,
81 Error::Node(_) | Error::Unknown(_) | Error::Io(_) => StatusCode::INTERNAL_SERVER_ERROR,
82 Error::Config(_) => StatusCode::SERVICE_UNAVAILABLE,
83 Error::Http(_) => StatusCode::BAD_GATEWAY,
84 Error::Tls(_) => StatusCode::INTERNAL_SERVER_ERROR,
85 }
86 }
87
88 pub fn severity(&self) -> ErrorSeverity {
90 match self {
91 Error::DIDComm(_) | Error::Validation(_) | Error::Json(_) => ErrorSeverity::Info,
92 Error::RateLimit(_) | Error::Authentication(_) => ErrorSeverity::Warning,
93 Error::Node(_)
94 | Error::Http(_)
95 | Error::Config(_)
96 | Error::Tls(_)
97 | Error::Unknown(_)
98 | Error::Io(_) => ErrorSeverity::Critical,
99 }
100 }
101
102 pub fn to_response(&self) -> warp::reply::Response {
104 let status = self.status_code();
105 let message = self.to_string();
106 let error_type = match self {
107 Error::DIDComm(_) => "didcomm_error",
108 Error::Validation(_) => "validation_error",
109 Error::Authentication(_) => "authentication_error",
110 Error::Json(_) => "json_error",
111 Error::Http(_) => "http_error",
112 Error::Node(_) => "node_error",
113 Error::Config(_) => "configuration_error",
114 Error::Io(_) => "io_error",
115 Error::RateLimit(_) => "rate_limit_error",
116 Error::Tls(_) => "tls_error",
117 Error::Unknown(_) => "unknown_error",
118 };
119
120 warp::reply::with_status(
121 warp::reply::json(&serde_json::json!({
122 "status": "error",
123 "error": {
124 "type": error_type,
125 "message": message,
126 }
127 })),
128 status,
129 )
130 .into_response()
131 }
132}
133
134impl From<serde_json::Error> for Error {
135 fn from(err: serde_json::Error) -> Self {
136 Error::Json(err.to_string())
137 }
138}
139
140impl From<tap_msg::error::Error> for Error {
141 fn from(err: tap_msg::error::Error) -> Self {
142 Error::DIDComm(err.to_string())
143 }
144}
145
146impl From<tap_node::error::Error> for Error {
147 fn from(err: tap_node::error::Error) -> Self {
148 Error::Node(err.to_string())
149 }
150}
151
152impl warp::reject::Reject for Error {}
153
154#[cfg(test)]
155mod tests {
156 use super::*;
157
158 #[test]
159 fn test_error_display() {
160 let error = Error::DIDComm("test error".to_string());
161 assert_eq!(error.to_string(), "Invalid DIDComm message: test error");
162
163 let error = Error::Node("node error".to_string());
164 assert_eq!(error.to_string(), "TAP Node error: node error");
165
166 let error = Error::Http("server error".to_string());
167 assert_eq!(error.to_string(), "HTTP error: server error");
168
169 let io_error = std::io::Error::new(std::io::ErrorKind::NotFound, "file not found");
170 let error = Error::from(io_error);
171 assert!(error.to_string().contains("file not found"));
172 }
173
174 #[test]
175 fn test_error_conversions() {
176 let json_error = serde_json::from_str::<serde_json::Value>("invalid json").unwrap_err();
177 let error = Error::from(json_error);
178 assert!(matches!(error, Error::Json(_)));
179 }
180}