use rocket::{
Request, Response,
http::Status,
response::{self, Responder},
};
use serde_json::json;
use std::{borrow::Cow, io};
use thiserror::Error;
use tracing::{error, info};
use xapi_data::DataError;
#[derive(Debug, Error)]
pub enum MyError {
#[error("Failed matching '{input:?}' to {name:?} format pattern")]
Format {
#[doc(hidden)]
input: Cow<'static, str>,
#[doc(hidden)]
name: Cow<'static, str>,
},
#[error("General data error: {0}")]
Data(
#[doc(hidden)]
#[from]
DataError,
),
#[error("Base64 decode error: {0}")]
Base64(
#[doc(hidden)]
#[from]
base64::DecodeError,
),
#[error("UTF8 conversion error: {0}")]
UTF8(
#[doc(hidden)]
#[from]
std::str::Utf8Error,
),
#[error("Multipart/mixed parse error: {0}")]
MULTIPART(
#[doc(hidden)]
#[from]
rocket_multipart::Error,
),
#[error("DB error: {0}")]
DB(
#[doc(hidden)]
#[from]
sqlx::Error,
),
#[error("DB migration error: {0}")]
DBMigrate(
#[doc(hidden)]
#[from]
sqlx::migrate::MigrateError,
),
#[error("{0}")]
Runtime(#[doc(hidden)] Cow<'static, str>),
#[error("I/O error: {0}")]
IO(
#[doc(hidden)]
#[from]
io::Error,
),
#[error("OpenSSL error: {0}")]
OSSL(
#[doc(hidden)]
#[from]
openssl::error::ErrorStack,
),
#[error("JOSE error: {0}")]
JOSE(
#[doc(hidden)]
#[from]
josekit::JoseError,
),
#[error("Rocket handler error ({status}): {info}")]
HTTP {
status: Status,
info: Cow<'static, str>,
},
}
impl MyError {
pub fn with_status(self, s: Status) -> Self {
match self {
MyError::HTTP { status, info } => {
info!("Replace status {} w/ {}", status, s);
MyError::HTTP { status: s, info }
}
_ => MyError::HTTP {
status: s,
info: self.to_string().into(),
},
}
}
}
#[rocket::async_trait]
impl<'r> Responder<'r, 'static> for MyError {
fn respond_to(self, req: &'r Request<'_>) -> response::Result<'static> {
let status = match self {
MyError::HTTP { status, .. } => status,
_ => Status::InternalServerError,
};
error!("Failed: {}", &self);
Response::build_from(
json!({
"status": status.code,
"info": format!("{}", self),
})
.respond_to(req)?,
)
.status(status)
.ok()
}
}