spacegate_plugin/
error.rs

1use std::fmt::Display;
2
3use hyper::{header::HeaderValue, Response, StatusCode};
4use spacegate_kernel::{SgBody, SgResponseExt};
5
6use crate::Plugin;
7
8/// # Usage
9/// 1. Create a plugin error with a status code
10/// ```rust ignore
11/// let x = result.map_err(PluginError::status::<MyPlugin, 404>);
12/// ```
13/// 2. Create a plugin error with a status 500
14/// ```rust ignore
15/// let x = result.map_err(PluginError::internal_error::<MyPlugin>);
16/// ```
17/// 3. Convert it into a response
18///
19/// Just use [`Response<SgBody>::from`].
20#[derive(Debug)]
21pub struct PluginError<E> {
22    plugin_code: &'static str,
23    source: E,
24    status: StatusCode,
25}
26
27const PLUGIN_ERROR_HEADER: &str = "X-Plugin-Error";
28
29impl<E> From<PluginError<E>> for Response<SgBody>
30where
31    E: Display,
32{
33    fn from(val: PluginError<E>) -> Self {
34        let mut resp = Response::with_code_message(val.status, val.to_string());
35        resp.headers_mut().insert(PLUGIN_ERROR_HEADER, HeaderValue::from_static(val.plugin_code));
36        resp
37    }
38}
39
40impl<E> PluginError<E> {
41    pub fn status<P: Plugin, const S: u16>(error: E) -> Self {
42        Self {
43            plugin_code: P::CODE,
44            source: error,
45            status: StatusCode::from_u16(S).expect("invalid status value"),
46        }
47    }
48    pub fn internal_error<P: Plugin>(e: E) -> Self {
49        Self {
50            plugin_code: P::CODE,
51            source: e,
52            status: StatusCode::INTERNAL_SERVER_ERROR,
53        }
54    }
55}
56
57impl<E> std::fmt::Display for PluginError<E>
58where
59    E: std::fmt::Display,
60{
61    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
62        write!(f, "[Sg.Plugin.{p}] {e}", p = self.plugin_code, e = self.source)
63    }
64}
65
66impl<E> std::error::Error for PluginError<E>
67where
68    E: std::error::Error + 'static,
69{
70    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
71        Some(&self.source)
72    }
73}
74
75pub mod code {
76    macro_rules! status_codes {
77        ($(
78            $(#[$docs:meta])*
79            ($code: expr, $key: ident, $reason: literal);
80        )*) => {
81            $(
82                $(#[$docs])*
83                pub const $key: u16 = $code;
84            )*
85
86        };
87    }
88    status_codes! {
89        /// 100 Continue
90        /// [[RFC7231, Section 6.2.1](https://tools.ietf.org/html/rfc7231#section-6.2.1)]
91        (100, CONTINUE, "Continue");
92        /// 101 Switching Protocols
93        /// [[RFC7231, Section 6.2.2](https://tools.ietf.org/html/rfc7231#section-6.2.2)]
94        (101, SWITCHING_PROTOCOLS, "Switching Protocols");
95        /// 102 Processing
96        /// [[RFC2518](https://tools.ietf.org/html/rfc2518)]
97        (102, PROCESSING, "Processing");
98
99        /// 200 OK
100        /// [[RFC7231, Section 6.3.1](https://tools.ietf.org/html/rfc7231#section-6.3.1)]
101        (200, OK, "OK");
102        /// 201 Created
103        /// [[RFC7231, Section 6.3.2](https://tools.ietf.org/html/rfc7231#section-6.3.2)]
104        (201, CREATED, "Created");
105        /// 202 Accepted
106        /// [[RFC7231, Section 6.3.3](https://tools.ietf.org/html/rfc7231#section-6.3.3)]
107        (202, ACCEPTED, "Accepted");
108        /// 203 Non-Authoritative Information
109        /// [[RFC7231, Section 6.3.4](https://tools.ietf.org/html/rfc7231#section-6.3.4)]
110        (203, NON_AUTHORITATIVE_INFORMATION, "Non Authoritative Information");
111        /// 204 No Content
112        /// [[RFC7231, Section 6.3.5](https://tools.ietf.org/html/rfc7231#section-6.3.5)]
113        (204, NO_CONTENT, "No Content");
114        /// 205 Reset Content
115        /// [[RFC7231, Section 6.3.6](https://tools.ietf.org/html/rfc7231#section-6.3.6)]
116        (205, RESET_CONTENT, "Reset Content");
117        /// 206 Partial Content
118        /// [[RFC7233, Section 4.1](https://tools.ietf.org/html/rfc7233#section-4.1)]
119        (206, PARTIAL_CONTENT, "Partial Content");
120        /// 207 Multi-Status
121        /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
122        (207, MULTI_STATUS, "Multi-Status");
123        /// 208 Already Reported
124        /// [[RFC5842](https://tools.ietf.org/html/rfc5842)]
125        (208, ALREADY_REPORTED, "Already Reported");
126
127        /// 226 IM Used
128        /// [[RFC3229](https://tools.ietf.org/html/rfc3229)]
129        (226, IM_USED, "IM Used");
130
131        /// 300 Multiple Choices
132        /// [[RFC7231, Section 6.4.1](https://tools.ietf.org/html/rfc7231#section-6.4.1)]
133        (300, MULTIPLE_CHOICES, "Multiple Choices");
134        /// 301 Moved Permanently
135        /// [[RFC7231, Section 6.4.2](https://tools.ietf.org/html/rfc7231#section-6.4.2)]
136        (301, MOVED_PERMANENTLY, "Moved Permanently");
137        /// 302 Found
138        /// [[RFC7231, Section 6.4.3](https://tools.ietf.org/html/rfc7231#section-6.4.3)]
139        (302, FOUND, "Found");
140        /// 303 See Other
141        /// [[RFC7231, Section 6.4.4](https://tools.ietf.org/html/rfc7231#section-6.4.4)]
142        (303, SEE_OTHER, "See Other");
143        /// 304 Not Modified
144        /// [[RFC7232, Section 4.1](https://tools.ietf.org/html/rfc7232#section-4.1)]
145        (304, NOT_MODIFIED, "Not Modified");
146        /// 305 Use Proxy
147        /// [[RFC7231, Section 6.4.5](https://tools.ietf.org/html/rfc7231#section-6.4.5)]
148        (305, USE_PROXY, "Use Proxy");
149        /// 307 Temporary Redirect
150        /// [[RFC7231, Section 6.4.7](https://tools.ietf.org/html/rfc7231#section-6.4.7)]
151        (307, TEMPORARY_REDIRECT, "Temporary Redirect");
152        /// 308 Permanent Redirect
153        /// [[RFC7238](https://tools.ietf.org/html/rfc7238)]
154        (308, PERMANENT_REDIRECT, "Permanent Redirect");
155
156        /// 400 Bad Request
157        /// [[RFC7231, Section 6.5.1](https://tools.ietf.org/html/rfc7231#section-6.5.1)]
158        (400, BAD_REQUEST, "Bad Request");
159        /// 401 Unauthorized
160        /// [[RFC7235, Section 3.1](https://tools.ietf.org/html/rfc7235#section-3.1)]
161        (401, UNAUTHORIZED, "Unauthorized");
162        /// 402 Payment Required
163        /// [[RFC7231, Section 6.5.2](https://tools.ietf.org/html/rfc7231#section-6.5.2)]
164        (402, PAYMENT_REQUIRED, "Payment Required");
165        /// 403 Forbidden
166        /// [[RFC7231, Section 6.5.3](https://tools.ietf.org/html/rfc7231#section-6.5.3)]
167        (403, FORBIDDEN, "Forbidden");
168        /// 404 Not Found
169        /// [[RFC7231, Section 6.5.4](https://tools.ietf.org/html/rfc7231#section-6.5.4)]
170        (404, NOT_FOUND, "Not Found");
171        /// 405 Method Not Allowed
172        /// [[RFC7231, Section 6.5.5](https://tools.ietf.org/html/rfc7231#section-6.5.5)]
173        (405, METHOD_NOT_ALLOWED, "Method Not Allowed");
174        /// 406 Not Acceptable
175        /// [[RFC7231, Section 6.5.6](https://tools.ietf.org/html/rfc7231#section-6.5.6)]
176        (406, NOT_ACCEPTABLE, "Not Acceptable");
177        /// 407 Proxy Authentication Required
178        /// [[RFC7235, Section 3.2](https://tools.ietf.org/html/rfc7235#section-3.2)]
179        (407, PROXY_AUTHENTICATION_REQUIRED, "Proxy Authentication Required");
180        /// 408 Request Timeout
181        /// [[RFC7231, Section 6.5.7](https://tools.ietf.org/html/rfc7231#section-6.5.7)]
182        (408, REQUEST_TIMEOUT, "Request Timeout");
183        /// 409 Conflict
184        /// [[RFC7231, Section 6.5.8](https://tools.ietf.org/html/rfc7231#section-6.5.8)]
185        (409, CONFLICT, "Conflict");
186        /// 410 Gone
187        /// [[RFC7231, Section 6.5.9](https://tools.ietf.org/html/rfc7231#section-6.5.9)]
188        (410, GONE, "Gone");
189        /// 411 Length Required
190        /// [[RFC7231, Section 6.5.10](https://tools.ietf.org/html/rfc7231#section-6.5.10)]
191        (411, LENGTH_REQUIRED, "Length Required");
192        /// 412 Precondition Failed
193        /// [[RFC7232, Section 4.2](https://tools.ietf.org/html/rfc7232#section-4.2)]
194        (412, PRECONDITION_FAILED, "Precondition Failed");
195        /// 413 Payload Too Large
196        /// [[RFC7231, Section 6.5.11](https://tools.ietf.org/html/rfc7231#section-6.5.11)]
197        (413, PAYLOAD_TOO_LARGE, "Payload Too Large");
198        /// 414 URI Too Long
199        /// [[RFC7231, Section 6.5.12](https://tools.ietf.org/html/rfc7231#section-6.5.12)]
200        (414, URI_TOO_LONG, "URI Too Long");
201        /// 415 Unsupported Media Type
202        /// [[RFC7231, Section 6.5.13](https://tools.ietf.org/html/rfc7231#section-6.5.13)]
203        (415, UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
204        /// 416 Range Not Satisfiable
205        /// [[RFC7233, Section 4.4](https://tools.ietf.org/html/rfc7233#section-4.4)]
206        (416, RANGE_NOT_SATISFIABLE, "Range Not Satisfiable");
207        /// 417 Expectation Failed
208        /// [[RFC7231, Section 6.5.14](https://tools.ietf.org/html/rfc7231#section-6.5.14)]
209        (417, EXPECTATION_FAILED, "Expectation Failed");
210        /// 418 I'm a teapot
211        /// [curiously not registered by IANA but [RFC2324](https://tools.ietf.org/html/rfc2324)]
212        (418, IM_A_TEAPOT, "I'm a teapot");
213
214        /// 421 Misdirected Request
215        /// [RFC7540, Section 9.1.2](https://tools.ietf.org/html/rfc7540#section-9.1.2)
216        (421, MISDIRECTED_REQUEST, "Misdirected Request");
217        /// 422 Unprocessable Entity
218        /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
219        (422, UNPROCESSABLE_ENTITY, "Unprocessable Entity");
220        /// 423 Locked
221        /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
222        (423, LOCKED, "Locked");
223        /// 424 Failed Dependency
224        /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
225        (424, FAILED_DEPENDENCY, "Failed Dependency");
226
227        /// 426 Upgrade Required
228        /// [[RFC7231, Section 6.5.15](https://tools.ietf.org/html/rfc7231#section-6.5.15)]
229        (426, UPGRADE_REQUIRED, "Upgrade Required");
230
231        /// 428 Precondition Required
232        /// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
233        (428, PRECONDITION_REQUIRED, "Precondition Required");
234        /// 429 Too Many Requests
235        /// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
236        (429, TOO_MANY_REQUESTS, "Too Many Requests");
237
238        /// 431 Request Header Fields Too Large
239        /// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
240        (431, REQUEST_HEADER_FIELDS_TOO_LARGE, "Request Header Fields Too Large");
241
242        /// 451 Unavailable For Legal Reasons
243        /// [[RFC7725](https://tools.ietf.org/html/rfc7725)]
244        (451, UNAVAILABLE_FOR_LEGAL_REASONS, "Unavailable For Legal Reasons");
245
246        /// 500 Internal Server Error
247        /// [[RFC7231, Section 6.6.1](https://tools.ietf.org/html/rfc7231#section-6.6.1)]
248        (500, INTERNAL_SERVER_ERROR, "Internal Server Error");
249        /// 501 Not Implemented
250        /// [[RFC7231, Section 6.6.2](https://tools.ietf.org/html/rfc7231#section-6.6.2)]
251        (501, NOT_IMPLEMENTED, "Not Implemented");
252        /// 502 Bad Gateway
253        /// [[RFC7231, Section 6.6.3](https://tools.ietf.org/html/rfc7231#section-6.6.3)]
254        (502, BAD_GATEWAY, "Bad Gateway");
255        /// 503 Service Unavailable
256        /// [[RFC7231, Section 6.6.4](https://tools.ietf.org/html/rfc7231#section-6.6.4)]
257        (503, SERVICE_UNAVAILABLE, "Service Unavailable");
258        /// 504 Gateway Timeout
259        /// [[RFC7231, Section 6.6.5](https://tools.ietf.org/html/rfc7231#section-6.6.5)]
260        (504, GATEWAY_TIMEOUT, "Gateway Timeout");
261        /// 505 HTTP Version Not Supported
262        /// [[RFC7231, Section 6.6.6](https://tools.ietf.org/html/rfc7231#section-6.6.6)]
263        (505, HTTP_VERSION_NOT_SUPPORTED, "HTTP Version Not Supported");
264        /// 506 Variant Also Negotiates
265        /// [[RFC2295](https://tools.ietf.org/html/rfc2295)]
266        (506, VARIANT_ALSO_NEGOTIATES, "Variant Also Negotiates");
267        /// 507 Insufficient Storage
268        /// [[RFC4918](https://tools.ietf.org/html/rfc4918)]
269        (507, INSUFFICIENT_STORAGE, "Insufficient Storage");
270        /// 508 Loop Detected
271        /// [[RFC5842](https://tools.ietf.org/html/rfc5842)]
272        (508, LOOP_DETECTED, "Loop Detected");
273
274        /// 510 Not Extended
275        /// [[RFC2774](https://tools.ietf.org/html/rfc2774)]
276        (510, NOT_EXTENDED, "Not Extended");
277        /// 511 Network Authentication Required
278        /// [[RFC6585](https://tools.ietf.org/html/rfc6585)]
279        (511, NETWORK_AUTHENTICATION_REQUIRED, "Network Authentication Required");
280    }
281}