hyaenidae/server/src/error.rs

108 lines
2.5 KiB
Rust

use crate::{rendered, State};
use actix_web::{http::StatusCode, HttpResponse, ResponseError};
pub(crate) trait ResultExt<T> {
fn state(self, state: &State) -> Result<T, StateError>;
}
pub(crate) trait OptionExt<T> {
fn req(self) -> Result<T, Error>;
}
#[derive(Debug, thiserror::Error)]
#[error("{error}")]
pub(crate) struct StateError {
state: State,
error: Error,
}
#[derive(Debug, thiserror::Error)]
pub(crate) enum Error {
#[error("{0}")]
Accounts(#[from] hyaenidae_accounts::Error),
#[error("{0}")]
Profiles(#[from] hyaenidae_profiles::Error),
#[error("{0}")]
Render(std::io::Error),
#[error("{0}")]
Sled(#[from] sled::Error),
#[error("{0}")]
Minify(String),
#[error("Required data was not present")]
Required,
}
impl ResponseError for StateError {
fn status_code(&self) -> StatusCode {
match self.error {
Error::Render(_)
| Error::Minify(_)
| Error::Accounts(_)
| Error::Profiles(_)
| Error::Sled(_)
| Error::Required => StatusCode::INTERNAL_SERVER_ERROR,
}
}
fn error_response(&self) -> HttpResponse {
match rendered(HttpResponse::build(self.status_code()), |cursor| {
crate::templates::error(cursor, self.error.to_string())
}) {
Ok(res) => res,
Err(_) => HttpResponse::build(self.status_code())
.content_type(mime::TEXT_PLAIN.essence_str())
.body(self.error.to_string()),
}
}
}
impl<T, E> ResultExt<T> for Result<T, E>
where
Error: From<E>,
{
fn state(self, state: &State) -> Result<T, StateError> {
self.map_err(|e| state.error(e))
}
}
impl<T> OptionExt<T> for Option<T> {
fn req(self) -> Result<T, Error> {
self.ok_or_else(|| Error::Required)
}
}
impl From<minify_html::Error> for Error {
fn from(e: minify_html::Error) -> Self {
Error::Minify(format!("{:?}", e))
}
}
impl From<hyaenidae_profiles::store::StoreError> for Error {
fn from(e: hyaenidae_profiles::store::StoreError) -> Self {
Error::Profiles(From::from(e))
}
}
impl From<hyaenidae_profiles::apub::StoreError> for Error {
fn from(e: hyaenidae_profiles::apub::StoreError) -> Self {
Error::Profiles(From::from(e))
}
}
impl State {
pub(crate) fn error<E>(&self, error: E) -> StateError
where
Error: From<E>,
{
StateError {
state: self.clone(),
error: error.into(),
}
}
}