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}