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}