1use crate::data::DataError;
4use rocket::{
5 http::Status,
6 response::{self, Responder},
7 Request, Response,
8};
9use serde_json::json;
10use std::{borrow::Cow, io};
11use thiserror::Error;
12use tracing::{error, info};
13
14#[derive(Debug, Error)]
16pub enum MyError {
17 #[error("Failed matching '{input:?}' to {name:?} format pattern")]
19 Format {
20 #[doc(hidden)]
21 input: Cow<'static, str>,
22 #[doc(hidden)]
23 name: Cow<'static, str>,
24 },
25
26 #[error("General data error: {0}")]
28 Data(
29 #[doc(hidden)]
30 #[from]
31 DataError,
32 ),
33
34 #[error("Base64 decode error: {0}")]
36 Base64(
37 #[doc(hidden)]
38 #[from]
39 base64::DecodeError,
40 ),
41
42 #[error("UTF8 conversion error: {0}")]
44 UTF8(
45 #[doc(hidden)]
46 #[from]
47 std::str::Utf8Error,
48 ),
49
50 #[error("Multipart/mixed parse error: {0}")]
52 MULTIPART(
53 #[doc(hidden)]
54 #[from]
55 rocket_multipart::Error,
56 ),
57
58 #[error("DB error: {0}")]
60 DB(
61 #[doc(hidden)]
62 #[from]
63 sqlx::Error,
64 ),
65
66 #[error("DB migration error: {0}")]
68 DBMigrate(
69 #[doc(hidden)]
70 #[from]
71 sqlx::migrate::MigrateError,
72 ),
73
74 #[error("{0}")]
76 Runtime(#[doc(hidden)] Cow<'static, str>),
77
78 #[error("I/O error: {0}")]
80 IO(
81 #[doc(hidden)]
82 #[from]
83 io::Error,
84 ),
85
86 #[error("OpenSSL error: {0}")]
88 OSSL(
89 #[doc(hidden)]
90 #[from]
91 openssl::error::ErrorStack,
92 ),
93
94 #[error("JOSE error: {0}")]
96 JOSE(
97 #[doc(hidden)]
98 #[from]
99 josekit::JoseError,
100 ),
101
102 #[error("Rocket handler error ({status}): {info}")]
104 HTTP {
105 status: Status,
107 info: Cow<'static, str>,
109 },
110}
111
112impl MyError {
113 pub fn with_status(self, s: Status) -> Self {
116 match self {
117 MyError::HTTP { status, info } => {
118 info!("Replace status {} w/ {}", status, s);
119 MyError::HTTP { status: s, info }
120 }
121 _ => MyError::HTTP {
122 status: s,
123 info: self.to_string().into(),
124 },
125 }
126 }
127}
128
129#[rocket::async_trait]
130impl<'r> Responder<'r, 'static> for MyError {
131 fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
132 let status = match self {
133 MyError::HTTP { status, .. } => status,
134 _ => Status::InternalServerError,
135 };
136 error!("Failed: {}", &self);
137 Response::build_from(
138 json!({
139 "status": status.code,
140 "info": format!("{}", self),
141 })
142 .respond_to(req)?,
143 )
144 .status(status)
145 .ok()
146 }
147}