tlaternet-webserver/server/src/errors.rs

73 lines
2.0 KiB
Rust

use actix_web::body::BoxBody;
use actix_web::dev::ServiceResponse;
use actix_web::http::header::ContentType;
use actix_web::http::StatusCode;
use actix_web::middleware::ErrorHandlerResponse;
use actix_web::{web, HttpResponse, ResponseError};
use derive_more::{Display, Error};
use super::SharedData;
use crate::template_utils::{render_template, ErrorMessage, TemplateArgs};
#[derive(Debug, Display, Error)]
pub enum UserError {
NotFound,
#[display(fmt = "Internal error. Try again later.")]
InternalError,
}
impl ResponseError for UserError {
fn error_response(&self) -> HttpResponse {
HttpResponse::build(self.status_code())
.insert_header(ContentType::html())
.body(self.to_string())
}
fn status_code(&self) -> StatusCode {
match *self {
UserError::NotFound => StatusCode::NOT_FOUND,
UserError::InternalError => StatusCode::INTERNAL_SERVER_ERROR,
}
}
}
pub fn generic_error<B>(
res: ServiceResponse<B>,
) -> actix_web::Result<ErrorHandlerResponse<BoxBody>> {
let data = res
.request()
.app_data::<web::Data<SharedData>>()
.map(|t| t.get_ref());
let status_code = res.response().status();
let message = if let Some(error) = status_code.canonical_reason() {
error
} else {
""
};
let response = match data {
Some(SharedData {
handlebars,
config: _,
}) => {
let args = TemplateArgs::builder()
.error_page(ErrorMessage::new(message, status_code.as_u16()))
.build();
let body = render_template(handlebars, "error", &args)
.map_err(|_| UserError::InternalError)?;
HttpResponse::build(res.status())
.content_type(ContentType::html())
.body(body)
}
None => Err(UserError::InternalError)?,
};
Ok(ErrorHandlerResponse::Response(ServiceResponse::new(
res.into_parts().0,
response.map_into_left_body(),
)))
}