error.rs 5.13 KB
use std::{fmt::Display, pin::Pin, sync::Arc};

use actix_rt::blocking::BlockingError;
use actix_web::{http::{StatusCode, header::ToStrError}, ResponseError};
use async_std::channel::SendError;
use diesel::result;
use diffy::{ParsePatchError, ApplyError};
use image::ImageError;
use mime::FromStrError;
use r2d2;
use rexiv2::Rexiv2Error;

use crate::{Pool, models::image::Image};

type ParentError = Option<Pin<Box<dyn std::error::Error>>>;

#[derive(Debug)]
pub struct Error {
    source  :ParentError,
    message :String,
    status  :Option<StatusCode>
}

unsafe impl Send for Error {}

pub(crate) type Result<T> = std::result::Result<T, Error>;

impl std::error::Error for Error {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        self.source.as_deref()
    }
}

impl ResponseError for Error {
    fn status_code(&self) -> StatusCode {
        self.status.unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)
    }
}

impl Display for Error {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Error { source: Some(source), message, status } =>
                write!( f
                      , "[{}] {}: {}"
                      , status.unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)
                      , message
                      , source ),
            Error { source: None, message, status } =>
                write!( f
                      , "[{}] {}"
                      , status.unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)
                      , message ),
        }
    }
}

impl Error {
    pub(crate) fn new(message :&str, status :StatusCode) -> Self {
        Self { source: None
             , message: String::from(message)
             , status: Some(status)
        }
    }
}

impl From<result::Error> for Error {
    fn from(source: result::Error) -> Self {
        Self { source: Some(Box::pin(source))
             , message: String::from("Diesel Result Error")
             , status: Some(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

impl From<r2d2::Error> for Error {
    fn from(source: r2d2::Error) -> Self {
        Self { source: Some(Box::pin(source))
             , message: String::from("R2D2 Pool Error")
             , status: Some(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

impl From<std::io::Error> for Error {
    fn from(source: std::io::Error) -> Self {
        Self { source: Some(Box::pin(source))
             , message: String::from("IO Error")
             , status: Some(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

impl From<std::str::Utf8Error> for Error {
    fn from(source: std::str::Utf8Error) -> Self {
        Self { source: Some(Box::pin(source))
             , message: String::from("UTF8 Error")
             , status: Some(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

impl From<ParsePatchError> for Error {
    fn from(source: ParsePatchError) -> Self {
        Self { source: Some(Box::pin(source))
             , message: String::from("Diffy Error")
             , status: Some(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

impl From<ApplyError> for Error {
    fn from(source: ApplyError) -> Self {
        Self { source: Some(Box::pin(source))
             , message: String::from("Diffy Error")
             , status: Some(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

impl From<uuid::Error> for Error {
    fn from(source: uuid::Error) -> Self {
        Self { source: Some(Box::pin(source))
             , message: String::from("UUID error")
             , status: Some(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

impl From<FromStrError> for Error {
    fn from(source: FromStrError) -> Self {
        Self { source: Some(Box::pin(source))
             , message: String::from("Mime error")
             , status: Some(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

impl From<ToStrError> for Error {
    fn from(source: ToStrError) -> Self {
        Self { source: Some(Box::pin(source))
             , message: String::from("Header error")
             , status: Some(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

impl From<SendError<(Arc<Pool>, Image)>> for Error {
    fn from(source: SendError<(Arc<Pool>, Image)>) -> Self {
        Self { source: Some(Box::pin(source))
             , message: String::from("Image Worker send error")
             , status: Some(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

impl From<ImageError> for Error {
    fn from(source: ImageError) -> Self {
        Self { source: Some(Box::pin(source))
             , message: String::from("Image processing error")
             , status: Some(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

impl From<Rexiv2Error> for Error {
    fn from(source: Rexiv2Error) -> Self {
        Self { source: Some(Box::pin(source))
             , message: String::from("Exiv error")
             , status: Some(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}

impl From<BlockingError<Error>> for Error {
    fn from(source: BlockingError<Error>) -> Self {
        Self { source: Some(Box::pin(source))
             , message: String::from("web::block error")
             , status: Some(StatusCode::INTERNAL_SERVER_ERROR)
        }
    }
}