1use thiserror::Error;
4
5pub type ProxyResult<T> = Result<T, ProxyError>;
7
8#[derive(Error, Debug)]
10pub enum ProxyError {
11 #[error("Configuration error: {0}")]
13 Config(String),
14
15 #[error("Database error: {0}")]
17 Database(#[from] sqlx::Error),
18
19 #[error("IO error: {0}")]
21 Io(#[from] std::io::Error),
22
23 #[error("TLS error: {0}")]
25 Tls(String),
26
27 #[error("ACME error: {0}")]
29 Acme(String),
30
31 #[error("HTTP error: {0}")]
33 Http(String),
34
35 #[error("Upstream error: {0}")]
37 Upstream(String),
38
39 #[error("Health check error: {0}")]
41 HealthCheck(String),
42
43 #[error("Rate limit exceeded")]
45 RateLimitExceeded,
46
47 #[error("Route not found: {0}")]
49 RouteNotFound(String),
50
51 #[error("Backend not found: {0}")]
53 BackendNotFound(String),
54
55 #[error("No healthy backends available for upstream: {0}")]
57 NoHealthyBackends(String),
58
59 #[error("Invalid URL: {0}")]
61 InvalidUrl(#[from] url::ParseError),
62
63 #[error("TOML parsing error: {0}")]
65 Toml(#[from] toml::de::Error),
66
67 #[error("File watcher error: {0}")]
69 Notify(#[from] notify::Error),
70
71 #[error("Internal error: {0}")]
73 Internal(String),
74
75 #[error("Domain verification error: {0}")]
78 Verification(String),
79
80 #[error("Authentication error: {0}")]
82 Auth(String),
83
84 #[error("Validation error: {0}")]
86 Validation(String),
87
88 #[error("Quota exceeded: {0}")]
90 QuotaExceeded(String),
91
92 #[error("Conflict: {0}")]
94 Conflict(String),
95
96 #[error("Tenant suspended")]
98 TenantSuspended,
99
100 #[error("Not found: {0}")]
102 NotFound(String),
103
104 #[error("Forbidden: {0}")]
106 Forbidden(String),
107}
108
109impl ProxyError {
110 pub fn status_code(&self) -> http::StatusCode {
112 match self {
113 ProxyError::Config(_) => http::StatusCode::INTERNAL_SERVER_ERROR,
114 ProxyError::Database(_) => http::StatusCode::INTERNAL_SERVER_ERROR,
115 ProxyError::Io(_) => http::StatusCode::INTERNAL_SERVER_ERROR,
116 ProxyError::Tls(_) => http::StatusCode::INTERNAL_SERVER_ERROR,
117 ProxyError::Acme(_) => http::StatusCode::INTERNAL_SERVER_ERROR,
118 ProxyError::Http(_) => http::StatusCode::BAD_GATEWAY,
119 ProxyError::Upstream(_) => http::StatusCode::BAD_GATEWAY,
120 ProxyError::HealthCheck(_) => http::StatusCode::SERVICE_UNAVAILABLE,
121 ProxyError::RateLimitExceeded => http::StatusCode::TOO_MANY_REQUESTS,
122 ProxyError::RouteNotFound(_) => http::StatusCode::NOT_FOUND,
123 ProxyError::BackendNotFound(_) => http::StatusCode::NOT_FOUND,
124 ProxyError::NoHealthyBackends(_) => http::StatusCode::SERVICE_UNAVAILABLE,
125 ProxyError::InvalidUrl(_) => http::StatusCode::BAD_REQUEST,
126 ProxyError::Toml(_) => http::StatusCode::INTERNAL_SERVER_ERROR,
127 ProxyError::Notify(_) => http::StatusCode::INTERNAL_SERVER_ERROR,
128 ProxyError::Internal(_) => http::StatusCode::INTERNAL_SERVER_ERROR,
129 ProxyError::Verification(_) => http::StatusCode::BAD_REQUEST,
130 ProxyError::Auth(_) => http::StatusCode::UNAUTHORIZED,
131 ProxyError::Validation(_) => http::StatusCode::BAD_REQUEST,
132 ProxyError::QuotaExceeded(_) => http::StatusCode::PAYMENT_REQUIRED,
133 ProxyError::Conflict(_) => http::StatusCode::CONFLICT,
134 ProxyError::TenantSuspended => http::StatusCode::FORBIDDEN,
135 ProxyError::NotFound(_) => http::StatusCode::NOT_FOUND,
136 ProxyError::Forbidden(_) => http::StatusCode::FORBIDDEN,
137 }
138 }
139}