1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
mod exception_handler_trait;
mod exception_handler_wrapper;

use crate::headers::ContentType;
use crate::{Response, StatusCode};
pub(crate) use exception_handler_trait::ExceptionHandler;
pub(crate) use exception_handler_wrapper::ExceptionHandlerWrapper;
use serde::Serialize;
use serde_json::Value;
use std::backtrace::Backtrace;
use std::io;
use thiserror::Error;

/// BoxedError
pub type BoxedError = Box<dyn std::error::Error + Send + Sync>;

/// SilentError is the error type for the `silent` library.
#[derive(Error, Debug)]
pub enum SilentError {
    /// IO 错误
    #[error("io error")]
    IOError(#[from] io::Error),
    #[cfg(feature = "upgrade")]
    /// Websocket IO 错误
    #[error("io error")]
    TungsteniteError(#[from] tokio_tungstenite::tungstenite::Error),
    /// 反序列化 错误
    #[error("serde_json error `{0}`")]
    SerdeJsonError(#[from] serde_json::Error),
    /// 反序列化 错误
    #[error("serde de error `{0}`")]
    SerdeDeError(#[from] serde::de::value::Error),
    /// Hyper 错误
    #[error("the data for key `{0}` is not available")]
    HyperError(#[from] hyper::Error),
    #[cfg(feature = "multipart")]
    /// 上传文件读取 错误
    #[error("upload file read error `{0}`")]
    FileEmpty(#[from] multer::Error),
    /// Body为空 错误
    #[error("body is empty")]
    BodyEmpty,
    /// Json为空 错误
    #[error("json is empty")]
    JsonEmpty,
    /// Json为空 错误
    #[error("content-type is error")]
    ContentTypeError,
    /// Params为空 错误
    #[error("params is empty")]
    ParamsEmpty,
    /// Params为空 错误
    #[error("params not found")]
    ParamsNotFound,
    /// 配置不存在 错误
    #[error("config not found")]
    ConfigNotFound,
    /// websocket错误
    #[error("websocket error: {0}")]
    WsError(String),
    /// anyhow错误
    #[error("{0}")]
    AnyhowError(#[from] anyhow::Error),
    /// 业务错误
    #[error("business error: {msg} ({code})")]
    BusinessError {
        /// 错误码
        code: StatusCode,
        /// 错误信息
        msg: String,
    },
}

pub type SilentResult<T> = Result<T, SilentError>;

impl From<(StatusCode, String)> for SilentError {
    fn from(value: (StatusCode, String)) -> Self {
        Self::business_error(value.0, value.1)
    }
}

impl From<(u16, String)> for SilentError {
    fn from(value: (u16, String)) -> Self {
        Self::business_error(
            StatusCode::from_u16(value.0).expect("invalid status code"),
            value.1,
        )
    }
}

impl From<String> for SilentError {
    fn from(value: String) -> Self {
        Self::business_error(StatusCode::INTERNAL_SERVER_ERROR, value)
    }
}

impl From<BoxedError> for SilentError {
    fn from(value: BoxedError) -> Self {
        Self::business_error(StatusCode::INTERNAL_SERVER_ERROR, value.to_string())
    }
}

impl SilentError {
    pub fn business_error_obj<S>(code: StatusCode, msg: S) -> Self
    where
        S: Serialize,
    {
        let msg = serde_json::to_string(&msg).unwrap_or_default();
        Self::BusinessError { code, msg }
    }
    pub fn business_error(code: StatusCode, msg: String) -> Self {
        Self::BusinessError { code, msg }
    }
    pub fn status(&self) -> StatusCode {
        match self {
            Self::BusinessError { code, .. } => *code,
            Self::SerdeDeError(_) => StatusCode::UNPROCESSABLE_ENTITY,
            Self::SerdeJsonError(_) => StatusCode::UNPROCESSABLE_ENTITY,
            _ => StatusCode::INTERNAL_SERVER_ERROR,
        }
    }
    pub fn message(&self) -> String {
        match self {
            Self::BusinessError { msg, .. } => msg.clone(),
            Self::SerdeDeError(e) => e.to_string(),
            Self::SerdeJsonError(e) => e.to_string(),
            _ => self.to_string(),
        }
    }
    pub fn trace(&self) -> Backtrace {
        Backtrace::capture()
    }
}

impl From<SilentError> for Response {
    fn from(value: SilentError) -> Self {
        let mut res = Response::empty();
        res.set_status(value.status());
        if serde_json::from_str::<Value>(&value.message()).is_ok() {
            res.set_typed_header(ContentType::json());
        }
        res.set_body(value.message().into());
        res
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::Response;
    use http_body_util::BodyExt;
    use hyper::StatusCode;
    use serde_json::Value;

    #[derive(Serialize)]
    struct ResBody {
        code: u16,
        msg: String,
        data: Value,
    }

    #[tokio::test]
    async fn test_silent_error() {
        let res_body = ResBody {
            code: 400,
            msg: "bad request".to_string(),
            data: Value::Null,
        };
        let err = SilentError::business_error_obj(StatusCode::BAD_REQUEST, res_body);
        let mut res: Response = err.into();
        assert_eq!(res.status, StatusCode::BAD_REQUEST);
        println!("{:#?}", res.headers);
        println!(
            "{:#?}",
            res.body.frame().await.unwrap().unwrap().data_ref().unwrap()
        );
    }
}