backend/
error.rs

1use std::{io, time::SystemTimeError};
2
3use actix_web::{
4    HttpResponse,
5    error::{PayloadError, ResponseError},
6    http::{
7        StatusCode,
8        header::{ContentType, ToStrError},
9    },
10};
11use bunny_api_tokio::error::Error as BunnyError;
12use deadpool::managed::{BuildError, PoolError};
13use diesel::{ConnectionError, result::Error as DieselError};
14use diesel_async::pooled_connection::PoolError as DieselPoolError;
15use lettre::{
16    address::AddressError, error::Error as EmailError, transport::smtp::Error as SmtpError,
17};
18use log::{debug, error};
19use redis::RedisError;
20use serde::Serialize;
21use serde_json::Error as JsonError;
22use thiserror::Error;
23use tokio::task::JoinError;
24use toml::de::Error as TomlError;
25
26#[derive(Debug, Error)]
27pub enum Error {
28    #[error(transparent)]
29    SqlError(#[from] DieselError),
30    #[error(transparent)]
31    PoolError(#[from] PoolError<DieselPoolError>),
32    #[error(transparent)]
33    BuildError(#[from] BuildError),
34    #[error(transparent)]
35    RedisError(#[from] RedisError),
36    #[error(transparent)]
37    ConnectionError(#[from] ConnectionError),
38    #[error(transparent)]
39    JoinError(#[from] JoinError),
40    #[error(transparent)]
41    IoError(#[from] io::Error),
42    #[error(transparent)]
43    TomlError(#[from] TomlError),
44    #[error(transparent)]
45    JsonError(#[from] JsonError),
46    #[error(transparent)]
47    SystemTimeError(#[from] SystemTimeError),
48    #[error(transparent)]
49    ToStrError(#[from] ToStrError),
50    #[error(transparent)]
51    RandomError(#[from] getrandom::Error),
52    #[error(transparent)]
53    BunnyError(#[from] BunnyError),
54    #[error(transparent)]
55    UrlParseError(#[from] url::ParseError),
56    #[error(transparent)]
57    PayloadError(#[from] PayloadError),
58    #[error(transparent)]
59    WsClosed(#[from] actix_ws::Closed),
60    #[error(transparent)]
61    EmailError(#[from] EmailError),
62    #[error(transparent)]
63    SmtpError(#[from] SmtpError),
64    #[error(transparent)]
65    SmtpAddressError(#[from] AddressError),
66    #[error("{0}")]
67    PasswordHashError(String),
68    #[error("{0}")]
69    BadRequest(String),
70    #[error("{0}")]
71    Unauthorized(String),
72    #[error("{0}")]
73    Forbidden(String),
74    #[error("{0}")]
75    TooManyRequests(String),
76    #[error("{0}")]
77    InternalServerError(String),
78}
79
80impl ResponseError for Error {
81    fn error_response(&self) -> HttpResponse {
82        debug!("{:?}", self);
83        error!("{}: {}", self.status_code(), self);
84
85        HttpResponse::build(self.status_code())
86            .insert_header(ContentType::json())
87            .json(WebError::new(self.to_string()))
88    }
89
90    fn status_code(&self) -> StatusCode {
91        match *self {
92            Error::SqlError(DieselError::NotFound) => StatusCode::NOT_FOUND,
93            Error::BunnyError(BunnyError::NotFound(_)) => StatusCode::NOT_FOUND,
94            Error::BadRequest(_) => StatusCode::BAD_REQUEST,
95            Error::Unauthorized(_) => StatusCode::UNAUTHORIZED,
96            Error::Forbidden(_) => StatusCode::FORBIDDEN,
97            Error::TooManyRequests(_) => StatusCode::TOO_MANY_REQUESTS,
98            _ => StatusCode::INTERNAL_SERVER_ERROR,
99        }
100    }
101}
102
103#[derive(Serialize)]
104struct WebError {
105    message: String,
106}
107
108impl WebError {
109    fn new(message: String) -> Self {
110        Self { message }
111    }
112}