slack_morphism/
errors.rs

1use rsb_derive::Builder;
2use std::error::Error;
3use std::fmt::Display;
4use std::fmt::Formatter;
5use std::time::Duration;
6use url::ParseError;
7
8#[derive(Debug)]
9pub enum SlackClientError {
10    ApiError(SlackClientApiError),
11    HttpError(SlackClientHttpError),
12    HttpProtocolError(SlackClientHttpProtocolError),
13    EndOfStream(SlackClientEndOfStreamError),
14    SystemError(SlackClientSystemError),
15    ProtocolError(SlackClientProtocolError),
16    SocketModeProtocolError(SlackClientSocketModeProtocolError),
17    RateLimitError(SlackRateLimitError),
18}
19
20impl SlackClientError {
21    fn option_to_string<T: ToString>(value: &Option<T>) -> String {
22        value
23            .as_ref()
24            .map_or_else(|| "-".to_string(), |v| v.to_string())
25    }
26}
27
28impl Display for SlackClientError {
29    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
30        match *self {
31            SlackClientError::ApiError(ref err) => err.fmt(f),
32            SlackClientError::HttpError(ref err) => err.fmt(f),
33            SlackClientError::HttpProtocolError(ref err) => err.fmt(f),
34            SlackClientError::EndOfStream(ref err) => err.fmt(f),
35            SlackClientError::ProtocolError(ref err) => err.fmt(f),
36            SlackClientError::SocketModeProtocolError(ref err) => err.fmt(f),
37            SlackClientError::SystemError(ref err) => err.fmt(f),
38            SlackClientError::RateLimitError(ref err) => err.fmt(f),
39        }
40    }
41}
42
43impl Error for SlackClientError {
44    fn source(&self) -> Option<&(dyn Error + 'static)> {
45        match *self {
46            SlackClientError::ApiError(ref err) => Some(err),
47            SlackClientError::HttpError(ref err) => Some(err),
48            SlackClientError::HttpProtocolError(ref err) => Some(err),
49            SlackClientError::EndOfStream(ref err) => Some(err),
50            SlackClientError::ProtocolError(ref err) => Some(err),
51            SlackClientError::SocketModeProtocolError(ref err) => Some(err),
52            SlackClientError::SystemError(ref err) => Some(err),
53            SlackClientError::RateLimitError(ref err) => Some(err),
54        }
55    }
56}
57
58#[derive(Debug, PartialEq, Eq, Clone, Builder)]
59pub struct SlackClientApiError {
60    pub code: String,
61    pub errors: Option<Vec<String>>,
62    pub warnings: Option<Vec<String>>,
63    pub http_response_body: Option<String>,
64}
65
66impl Display for SlackClientApiError {
67    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
68        write!(
69            f,
70            "Slack API error: {}\nBody: '{}'",
71            self.code,
72            SlackClientError::option_to_string(&self.http_response_body)
73        )
74    }
75}
76
77impl Error for SlackClientApiError {}
78
79#[derive(Debug, PartialEq, Eq, Clone, Builder)]
80pub struct SlackClientHttpError {
81    pub status_code: http::StatusCode,
82    pub http_response_body: Option<String>,
83}
84
85impl Display for SlackClientHttpError {
86    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
87        write!(
88            f,
89            "Slack HTTP error status: {}. Body: '{}'",
90            self.status_code,
91            SlackClientError::option_to_string(&self.http_response_body)
92        )
93    }
94}
95
96impl std::error::Error for SlackClientHttpError {}
97
98#[derive(Debug, Builder)]
99pub struct SlackClientHttpProtocolError {
100    pub cause: Option<Box<dyn std::error::Error + Sync + Send>>,
101}
102
103impl Display for SlackClientHttpProtocolError {
104    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
105        write!(f, "Slack http protocol error: {:?}", self.cause)
106    }
107}
108
109impl std::error::Error for SlackClientHttpProtocolError {}
110
111#[derive(Debug, PartialEq, Eq, Clone, Builder)]
112pub struct SlackClientEndOfStreamError {}
113
114impl Display for SlackClientEndOfStreamError {
115    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
116        write!(f, "Slack end of stream error")
117    }
118}
119
120impl std::error::Error for SlackClientEndOfStreamError {}
121
122#[derive(Debug, Builder)]
123pub struct SlackClientProtocolError {
124    pub json_error: serde_json::Error,
125    pub json_body: Option<String>,
126}
127
128impl Display for SlackClientProtocolError {
129    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
130        write!(
131            f,
132            "Slack JSON protocol error: {}. Body: '{}'",
133            self.json_error,
134            SlackClientError::option_to_string(&self.json_body)
135        )
136    }
137}
138
139impl std::error::Error for SlackClientProtocolError {}
140
141#[derive(Debug, PartialEq, Eq, Clone, Builder)]
142pub struct SlackClientSocketModeProtocolError {
143    pub message: String,
144}
145
146impl Display for SlackClientSocketModeProtocolError {
147    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
148        write!(f, "Slack socket mode protocol error: {}", self.message)
149    }
150}
151
152impl std::error::Error for SlackClientSocketModeProtocolError {}
153
154#[derive(Debug, Builder)]
155pub struct SlackClientSystemError {
156    pub message: Option<String>,
157    pub cause: Option<Box<dyn std::error::Error + Sync + Send + 'static>>,
158}
159
160impl Display for SlackClientSystemError {
161    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
162        write!(
163            f,
164            "Slack system protocol error. {}{:?}",
165            self.message.as_ref().unwrap_or(&"".to_string()),
166            self.cause
167        )
168    }
169}
170
171impl std::error::Error for SlackClientSystemError {}
172
173#[derive(Debug, PartialEq, Eq, Clone, Builder)]
174pub struct SlackRateLimitError {
175    pub retry_after: Option<Duration>,
176    pub code: Option<String>,
177    pub warnings: Option<Vec<String>>,
178    pub http_response_body: Option<String>,
179}
180
181impl Display for SlackRateLimitError {
182    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
183        write!(
184            f,
185            "Slack API rate limit error: {}\nBody: '{}'. Retry after: `{:?}`",
186            SlackClientError::option_to_string(&self.code),
187            SlackClientError::option_to_string(&self.http_response_body),
188            self.retry_after,
189        )
190    }
191}
192
193impl Error for SlackRateLimitError {}
194
195impl From<url::ParseError> for SlackClientError {
196    fn from(url_parse_error: ParseError) -> Self {
197        SlackClientError::HttpProtocolError(
198            SlackClientHttpProtocolError::new().with_cause(Box::new(url_parse_error)),
199        )
200    }
201}
202
203impl From<Box<dyn std::error::Error + Sync + Send>> for SlackClientError {
204    fn from(err: Box<dyn Error + Sync + Send>) -> Self {
205        SlackClientError::SystemError(SlackClientSystemError::new().with_cause(err))
206    }
207}
208
209pub fn map_serde_error(err: serde_json::Error, tried_to_parse: Option<&str>) -> SlackClientError {
210    SlackClientError::ProtocolError(
211        SlackClientProtocolError::new(err).opt_json_body(tried_to_parse.map(|s| s.to_string())),
212    )
213}