palpo_data/
error.rs

1use std::borrow::Cow;
2use std::io;
3use std::string::FromUtf8Error;
4
5use async_trait::async_trait;
6use palpo_core::MatrixError;
7use salvo::http::{StatusCode, StatusError};
8use salvo::oapi::{self, EndpointOutRegister, ToSchema};
9use salvo::prelude::{Depot, Request, Response, Writer};
10use thiserror::Error;
11// use crate::User;
12// use crate::DepotExt;
13
14#[derive(Error, Debug)]
15pub enum DataError {
16    #[error("public: `{0}`")]
17    Public(String),
18    #[error("internal: `{0}`")]
19    Internal(String),
20    #[error("parse int error: `{0}`")]
21    ParseIntError(#[from] std::num::ParseIntError),
22    #[error("io: `{0}`")]
23    Io(#[from] io::Error),
24    #[error("utf8: `{0}`")]
25    FromUtf8(#[from] FromUtf8Error),
26    #[error("decoding: `{0}`")]
27    Decoding(Cow<'static, str>),
28    #[error("url parse: `{0}`")]
29    UrlParse(#[from] url::ParseError),
30    #[error("serde json: `{0}`")]
31    SerdeJson(#[from] serde_json::error::Error),
32    #[error("diesel: `{0}`")]
33    Diesel(#[from] diesel::result::Error),
34    #[error("regex: `{0}`")]
35    Regex(#[from] regex::Error),
36    #[error("pool: `{0}`")]
37    Pool(#[from] crate::PoolError),
38    #[error("utf8: `{0}`")]
39    Utf8Error(#[from] std::str::Utf8Error),
40    #[error("Matrix error: `{0}`")]
41    Matrix(#[from] palpo_core::MatrixError),
42    #[error("Uiaa error: `{0}`")]
43    Uiaa(#[from] palpo_core::client::uiaa::UiaaInfo),
44    #[error("Send error: `{0}`")]
45    Send(#[from] palpo_core::sending::SendError),
46    #[error("ID parse error: `{0}`")]
47    IdParse(#[from] palpo_core::identifiers::IdParseError),
48    #[error("CanonicalJson error: `{0}`")]
49    CanonicalJson(#[from] palpo_core::serde::CanonicalJsonError),
50    #[error("MxcUriError: `{0}`")]
51    MxcUriError(#[from] palpo_core::identifiers::MxcUriError),
52    #[error("ImageError: `{0}`")]
53    ImageError(#[from] image::ImageError),
54    #[error("Signatures: `{0}`")]
55    Signatures(#[from] palpo_core::signatures::Error),
56}
57
58impl DataError {
59    pub fn public<S: Into<String>>(msg: S) -> Self {
60        Self::Public(msg.into())
61    }
62
63    pub fn internal<S: Into<String>>(msg: S) -> Self {
64        Self::Internal(msg.into())
65    }
66}
67
68#[async_trait]
69impl Writer for DataError {
70    async fn write(mut self, req: &mut Request, depot: &mut Depot, res: &mut Response) {
71        let matrix = match self {
72            Self::Public(msg) => MatrixError::unknown(msg),
73            Self::Internal(_msg) => MatrixError::unknown("unknown error."),
74            Self::Matrix(e) => e,
75            Self::Uiaa(uiaa) => {
76                use crate::core::client::uiaa::ErrorKind;
77                if res.status_code.map(|c| c.is_success()).unwrap_or(true) {
78                    let code = if let Some(error) = &uiaa.auth_error {
79                        match &error.kind {
80                            ErrorKind::Forbidden | ErrorKind::UserDeactivated => StatusCode::FORBIDDEN,
81                            ErrorKind::NotFound => StatusCode::NOT_FOUND,
82                            ErrorKind::BadState | ErrorKind::BadJson | ErrorKind::BadStatus | ErrorKind::BadAlias => {
83                                StatusCode::BAD_REQUEST
84                            }
85                            ErrorKind::Unauthorized => StatusCode::UNAUTHORIZED,
86                            ErrorKind::CannotOverwriteMedia => StatusCode::CONFLICT,
87                            ErrorKind::NotYetUploaded => StatusCode::GATEWAY_TIMEOUT,
88                            _ => StatusCode::INTERNAL_SERVER_ERROR,
89                        }
90                    } else {
91                        StatusCode::UNAUTHORIZED
92                    };
93                    res.status_code(code);
94                }
95                res.add_header(salvo::http::header::CONTENT_TYPE, "application/json", true)
96                    .ok();
97                let body: Vec<u8> = crate::core::serde::json_to_buf(&uiaa).unwrap();
98                res.write_body(body).ok();
99                return;
100            }
101            Self::Diesel(e) => {
102                tracing::error!(error = ?e, "diesel db error.");
103                if let diesel::result::Error::NotFound = e {
104                    MatrixError::not_found("Resource not found.")
105                } else {
106                    MatrixError::unknown("unknown db error.")
107                }
108            }
109            _ => MatrixError::unknown("unknown error happened."),
110        };
111        matrix.write(req, depot, res).await;
112    }
113}
114impl EndpointOutRegister for DataError {
115    fn register(components: &mut oapi::Components, operation: &mut oapi::Operation) {
116        operation.responses.insert(
117            StatusCode::INTERNAL_SERVER_ERROR.as_str(),
118            oapi::Response::new("Internal server error")
119                .add_content("application/json", StatusError::to_schema(components)),
120        );
121        operation.responses.insert(
122            StatusCode::NOT_FOUND.as_str(),
123            oapi::Response::new("Not found").add_content("application/json", StatusError::to_schema(components)),
124        );
125        operation.responses.insert(
126            StatusCode::BAD_REQUEST.as_str(),
127            oapi::Response::new("Bad request").add_content("application/json", StatusError::to_schema(components)),
128        );
129    }
130}