use actix_web::{HttpResponse, ResponseError};
use std::{error, fmt};
#[derive(Debug)]
pub enum Error {
ActixWeb(actix_web::error::Error),
Anyhow(anyhow::Error),
Database(sqlx::Error),
Generic(String),
Template(tera::Error),
Json(serde_json::error::Error),
}
impl ResponseError for Error {
fn error_response(&self) -> HttpResponse {
HttpResponse::build(actix_web::http::StatusCode::INTERNAL_SERVER_ERROR)
.content_type("text/html;charset=utf-8")
.body(render(self))
}
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self)
}
}
impl error::Error for Error {
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
match self {
Error::ActixWeb(e) => Some(e),
Error::Anyhow(e) => Some(e.root_cause()),
Error::Database(e) => Some(e),
Error::Template(e) => Some(e),
Error::Json(e) => Some(e),
Error::Generic(_) => None,
}
}
}
impl From<actix_web::error::Error> for Error {
fn from(e: actix_web::error::Error) -> Self {
Error::ActixWeb(e)
}
}
impl From<serde_json::error::Error> for Error {
fn from(e: serde_json::error::Error) -> Self {
Error::Json(e)
}
}
impl From<sqlx::Error> for Error {
fn from(e: sqlx::Error) -> Self {
Error::Database(e)
}
}
impl From<anyhow::Error> for Error {
fn from(e: anyhow::Error) -> Self {
Error::Anyhow(e)
}
}
impl From<tera::Error> for Error {
fn from(e: tera::Error) -> Self {
Error::Template(e)
}
}
pub(crate) fn render<E: std::fmt::Debug>(e: E) -> String {
format!(
r#"<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no, maximum-scale=1.0">
<title>Jelly: An Error Occurred</title>
<style>
html, body {{
margin: 0;
padding: 0;
background: #F0DEE0;
color: #111;
font-family: -apple-system, "Helvetica Neue", Helvetica, "Segoe UI", Ubuntu, arial, sans-serif;
}}
h1 {{ margin: 0; background: #F05758; border-bottom: 1px solid #C7484A; padding: 20px; font-size: 30px; font-weight: 600; line-height: 40px; }}
code {{
display: block;
font-family: "Anonymous Pro", Consolas, Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif;
font-size: 16px;
line-height: 20px;
padding: 20px;
}}
</style>
</head>
<body>
<h1>Error</h1>
<code>{:#?}<code>
</body>
</html>
"#,
e
)
}