upub/src/errors.rs

140 lines
3.6 KiB
Rust
Raw Normal View History

use axum::{http::StatusCode, response::Redirect};
2024-04-23 04:07:32 +02:00
2024-03-27 04:00:18 +01:00
#[derive(Debug, thiserror::Error)]
pub enum UpubError {
2024-05-13 14:56:16 +02:00
#[error("database error: {0:?}")]
2024-03-27 04:00:18 +01:00
Database(#[from] sea_orm::DbErr),
2024-04-23 04:07:32 +02:00
#[error("{0}")]
2024-03-27 04:00:18 +01:00
Status(axum::http::StatusCode),
#[error("missing field: {0}")]
Field(#[from] crate::model::FieldError),
2024-05-13 14:56:16 +02:00
#[error("openssl error: {0:?}")]
2024-03-27 04:00:18 +01:00
OpenSSL(#[from] openssl::error::ErrorStack),
2024-05-13 14:56:16 +02:00
#[error("invalid UTF8 in key: {0:?}")]
OpenSSLParse(#[from] std::str::Utf8Error),
2024-05-13 14:56:16 +02:00
#[error("fetch error: {0:?}")]
2024-03-27 04:00:18 +01:00
Reqwest(#[from] reqwest::Error),
// TODO this is quite ugly because its basically a reqwest::Error but with extra string... buuut
// helps with debugging!
2024-05-13 14:56:16 +02:00
#[error("fetch error: {0:?} -- server responded with {1}")]
FetchError(reqwest::Error, String),
2024-05-13 14:56:16 +02:00
#[error("invalid base64 string: {0:?}")]
Base64(#[from] base64::DecodeError),
// TODO this isn't really an error but i need to redirect from some routes so this allows me to
// keep the type hints on the return type, still what the hell!!!!
#[error("redirecting to {0}")]
Redirect(String),
2024-03-27 04:00:18 +01:00
}
impl UpubError {
pub fn bad_request() -> Self {
2024-04-08 02:52:51 +02:00
Self::Status(axum::http::StatusCode::BAD_REQUEST)
}
pub fn unprocessable() -> Self {
Self::Status(axum::http::StatusCode::UNPROCESSABLE_ENTITY)
}
pub fn not_found() -> Self {
Self::Status(axum::http::StatusCode::NOT_FOUND)
}
pub fn forbidden() -> Self {
Self::Status(axum::http::StatusCode::FORBIDDEN)
}
pub fn unauthorized() -> Self {
Self::Status(axum::http::StatusCode::UNAUTHORIZED)
}
pub fn not_modified() -> Self {
Self::Status(axum::http::StatusCode::NOT_MODIFIED)
}
pub fn internal_server_error() -> Self {
Self::Status(axum::http::StatusCode::INTERNAL_SERVER_ERROR)
}
}
pub type UpubResult<T> = Result<T, UpubError>;
2024-03-27 04:00:18 +01:00
impl From<axum::http::StatusCode> for UpubError {
fn from(value: axum::http::StatusCode) -> Self {
UpubError::Status(value)
}
}
impl axum::response::IntoResponse for UpubError {
fn into_response(self) -> axum::response::Response {
match self {
UpubError::Redirect(to) => Redirect::to(&to).into_response(),
2024-05-23 03:12:45 +02:00
UpubError::Status(status) => status.into_response(),
UpubError::Database(e) => (
StatusCode::SERVICE_UNAVAILABLE,
axum::Json(serde_json::json!({
"error": "database",
"description": format!("{e:#?}"),
}))
).into_response(),
UpubError::Reqwest(x) | UpubError::FetchError(x, _) => (
x.status().unwrap_or(StatusCode::INTERNAL_SERVER_ERROR),
axum::Json(serde_json::json!({
"error": "request",
"status": x.status().map(|s| s.to_string()).unwrap_or_default(),
"url": x.url().map(|x| x.to_string()).unwrap_or_default(),
"description": format!("{x:#?}"),
}))
).into_response(),
UpubError::Field(x) => (
axum::http::StatusCode::BAD_REQUEST,
axum::Json(serde_json::json!({
"error": "field",
"field": x.0.to_string(),
"description": format!("missing required field from request: '{}'", x.0),
}))
).into_response(),
_ => (
StatusCode::INTERNAL_SERVER_ERROR,
axum::Json(serde_json::json!({
"error": "unknown",
"description": self.to_string(),
}))
).into_response(),
}
2024-03-27 04:00:18 +01:00
}
}
pub trait LoggableError {
fn info_failed(self, msg: &str);
fn warn_failed(self, msg: &str);
fn err_failed(self, msg: &str);
}
impl<T, E: std::error::Error> LoggableError for Result<T, E> {
fn info_failed(self, msg: &str) {
if let Err(e) = self {
tracing::info!("{} : {}", msg, e);
}
}
fn warn_failed(self, msg: &str) {
if let Err(e) = self {
tracing::warn!("{} : {}", msg, e);
}
}
fn err_failed(self, msg: &str) {
if let Err(e) = self {
tracing::error!("{} : {}", msg, e);
}
}
}