1pub type Result<T> = std::result::Result<T, Error>;
5
6#[derive(Debug, thiserror::Error)]
8pub enum Error {
9 #[error("Validation error: {message}")]
11 Validation {
12 message: String,
14 },
15
16 #[error("Routing error: {message}")]
18 Routing {
19 message: String,
21 },
22
23 #[error("Proxy error: {message}")]
25 Proxy {
26 message: String,
28 },
29
30 #[error("Latency simulation error: {message}")]
32 Latency {
33 message: String,
35 },
36
37 #[error("Configuration error: {message}")]
39 Config {
40 message: String,
42 },
43
44 #[error("Protocol not found: {message}")]
46 ProtocolNotFound {
47 message: String,
49 },
50
51 #[error("Protocol disabled: {message}")]
53 ProtocolDisabled {
54 message: String,
56 },
57
58 #[error("Protocol handler in use: {message}")]
60 ProtocolHandlerInUse {
61 message: String,
63 },
64
65 #[error("Protocol validation error: {message}")]
67 ProtocolValidationError {
68 protocol: String,
70 message: String,
72 },
73
74 #[error("IO error: {0}")]
76 Io(#[from] std::io::Error),
77
78 #[error("JSON error: {0}")]
80 Json(#[from] serde_json::Error),
81
82 #[error("YAML error: {0}")]
84 Yaml(#[from] serde_yaml::Error),
85
86 #[error("HTTP error: {0}")]
88 Http(#[from] reqwest::Error),
89
90 #[error("URL parse error: {0}")]
92 UrlParse(#[from] url::ParseError),
93
94 #[error("Regex error: {0}")]
96 Regex(#[from] regex::Error),
97
98 #[error("Route not found: {method} {path}")]
100 RouteNotFound {
101 method: String,
103 path: String,
105 },
106
107 #[error("Schema validation failed at '{path}': expected {expected}, got {actual}")]
109 SchemaValidationFailed {
110 path: String,
112 expected: String,
114 actual: String,
116 },
117
118 #[error("Configuration error: {message}")]
120 ConfigWithSource {
121 message: String,
123 #[source]
125 source: Box<dyn std::error::Error + Send + Sync>,
126 },
127
128 #[error("Generic error: {0}")]
130 Generic(String),
131
132 #[error("Encryption error: {0}")]
134 Encryption(#[from] crate::encryption::EncryptionError),
135
136 #[cfg(feature = "scripting")]
138 #[error("JavaScript error: {0}")]
139 JavaScript(#[from] rquickjs::Error),
140}
141
142impl From<String> for Error {
143 fn from(message: String) -> Self {
144 Self::Generic(message)
145 }
146}
147
148impl Error {
149 pub fn validation<S: Into<String>>(message: S) -> Self {
151 Self::Validation {
152 message: message.into(),
153 }
154 }
155
156 pub fn routing<S: Into<String>>(message: S) -> Self {
158 Self::Routing {
159 message: message.into(),
160 }
161 }
162
163 pub fn proxy<S: Into<String>>(message: S) -> Self {
165 Self::Proxy {
166 message: message.into(),
167 }
168 }
169
170 pub fn latency<S: Into<String>>(message: S) -> Self {
172 Self::Latency {
173 message: message.into(),
174 }
175 }
176
177 pub fn config<S: Into<String>>(message: S) -> Self {
179 Self::Config {
180 message: message.into(),
181 }
182 }
183
184 pub fn protocol_not_found<S: Into<String>>(message: S) -> Self {
186 Self::ProtocolNotFound {
187 message: message.into(),
188 }
189 }
190
191 pub fn protocol_disabled<S: Into<String>>(message: S) -> Self {
193 Self::ProtocolDisabled {
194 message: message.into(),
195 }
196 }
197
198 pub fn protocol_handler_in_use<S: Into<String>>(message: S) -> Self {
200 Self::ProtocolHandlerInUse {
201 message: message.into(),
202 }
203 }
204
205 pub fn protocol_validation_error<S: Into<String>>(protocol: S, message: S) -> Self {
207 Self::ProtocolValidationError {
208 protocol: protocol.into(),
209 message: message.into(),
210 }
211 }
212
213 pub fn route_not_found<S: Into<String>>(method: S, path: S) -> Self {
215 Self::RouteNotFound {
216 method: method.into(),
217 path: path.into(),
218 }
219 }
220
221 pub fn schema_validation_failed<S: Into<String>>(path: S, expected: S, actual: S) -> Self {
223 Self::SchemaValidationFailed {
224 path: path.into(),
225 expected: expected.into(),
226 actual: actual.into(),
227 }
228 }
229
230 pub fn config_with_source<S: Into<String>>(
232 message: S,
233 source: impl std::error::Error + Send + Sync + 'static,
234 ) -> Self {
235 Self::ConfigWithSource {
236 message: message.into(),
237 source: Box::new(source),
238 }
239 }
240
241 pub fn generic<S: Into<String>>(message: S) -> Self {
243 Self::Generic(message.into())
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250
251 #[test]
252 fn test_validation_error() {
253 let err = Error::validation("test validation");
254 assert!(err.to_string().contains("Validation error"));
255 assert!(err.to_string().contains("test validation"));
256 }
257
258 #[test]
259 fn test_routing_error() {
260 let err = Error::routing("test routing");
261 assert!(err.to_string().contains("Routing error"));
262 assert!(err.to_string().contains("test routing"));
263 }
264
265 #[test]
266 fn test_proxy_error() {
267 let err = Error::proxy("test proxy");
268 assert!(err.to_string().contains("Proxy error"));
269 assert!(err.to_string().contains("test proxy"));
270 }
271
272 #[test]
273 fn test_latency_error() {
274 let err = Error::latency("test latency");
275 assert!(err.to_string().contains("Latency simulation error"));
276 assert!(err.to_string().contains("test latency"));
277 }
278
279 #[test]
280 fn test_config_error() {
281 let err = Error::config("test config");
282 assert!(err.to_string().contains("Configuration error"));
283 assert!(err.to_string().contains("test config"));
284 }
285
286 #[test]
287 fn test_generic_error() {
288 let err = Error::generic("test generic");
289 assert!(err.to_string().contains("Generic error"));
290 assert!(err.to_string().contains("test generic"));
291 }
292
293 #[test]
294 fn test_from_string() {
295 let err: Error = "test message".to_string().into();
296 assert!(matches!(err, Error::Generic(_)));
297 assert!(err.to_string().contains("test message"));
298 }
299
300 #[test]
301 fn test_json_error_conversion() {
302 let json_err = serde_json::from_str::<serde_json::Value>("invalid json");
303 assert!(json_err.is_err());
304 let err: Error = json_err.unwrap_err().into();
305 assert!(matches!(err, Error::Json(_)));
306 }
307
308 #[test]
309 fn test_url_parse_error_conversion() {
310 let url_err = url::Url::parse("not a url");
311 assert!(url_err.is_err());
312 let err: Error = url_err.unwrap_err().into();
313 assert!(matches!(err, Error::UrlParse(_)));
314 }
315
316 #[test]
317 #[allow(clippy::invalid_regex)]
318 fn test_regex_error_conversion() {
319 let regex_err = regex::Regex::new("[invalid(");
320 assert!(regex_err.is_err());
321 let err: Error = regex_err.unwrap_err().into();
322 assert!(matches!(err, Error::Regex(_)));
323 }
324
325 #[test]
326 fn test_error_display() {
327 let errors = vec![
328 (Error::validation("msg"), "Validation error: msg"),
329 (Error::routing("msg"), "Routing error: msg"),
330 (Error::proxy("msg"), "Proxy error: msg"),
331 (Error::latency("msg"), "Latency simulation error: msg"),
332 (Error::config("msg"), "Configuration error: msg"),
333 (Error::generic("msg"), "Generic error: msg"),
334 ];
335
336 for (err, expected) in errors {
337 assert_eq!(err.to_string(), expected);
338 }
339 }
340}