1use hyper::{header::InvalidHeaderValue, StatusCode};
4use regex::Regex;
5use std::{
6 error::Error as StdError,
7 fmt::{self, Display},
8 result::Result,
9 str::Utf8Error,
10};
11
12pub type ConnectResult<T> = Result<T, Error>;
14
15pub type Cause = Box<dyn StdError + Send + Sync>;
17
18pub struct Error {
20 inner: Box<ErrorImpl>,
21}
22
23struct ErrorImpl {
24 kind: Kind,
25 cause: Option<Cause>,
26}
27
28impl fmt::Debug for Error {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 let mut f = f.debug_tuple("hyper::Error");
31 f.field(&self.inner.kind);
32 if let Some(ref cause) = self.inner.cause {
33 f.field(cause);
34 }
35 f.finish()
36 }
37}
38
39impl fmt::Display for Error {
40 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41 if let Some(ref cause) = self.inner.cause {
42 write!(f, "{}: {}", self.description(), cause)
43 } else {
44 f.write_str(&self.description())
45 }
46 }
47}
48
49impl StdError for Error {
50 fn source(&self) -> Option<&(dyn StdError + 'static)> {
51 self.inner
52 .cause
53 .as_ref()
54 .map(|cause| &**cause as &(dyn StdError + 'static))
55 }
56}
57
58impl Error {
59 pub(super) fn new(kind: Kind) -> Error {
60 Error {
61 inner: Box::new(ErrorImpl { kind, cause: None }),
62 }
63 }
64
65 pub(super) fn with<C: Into<Cause>>(mut self, cause: C) -> Error {
66 self.inner.cause = Some(cause.into());
67 self
68 }
69
70 pub(crate) fn find_source<E: StdError + 'static>(&self) -> Option<&E> {
71 let mut cause = self.source();
72 while let Some(err) = cause {
73 if let Some(ref typed) = err.downcast_ref() {
74 return Some(typed);
75 }
76 cause = err.source();
77 }
78
79 None
81 }
82
83 pub(super) fn new_network_error<E: Into<Cause>>(cause: E) -> Self {
84 Error::new(Kind::NetworkError).with(cause)
85 }
86
87 pub(super) fn new_parsing_error<E: Into<Cause>>(cause: E) -> Self {
88 Error::new(Kind::ParsingError).with(cause)
89 }
90
91 pub(super) fn new_retry_error<E: Into<Cause>>(cause: E) -> Self {
92 Error::new(Kind::RetryError).with(cause)
93 }
94
95 pub(super) fn new_connect_error(err: ConnectAPIError) -> Self {
96 Error::new(Kind::ConnectAPIError(err))
97 }
98
99 pub(super) fn new_internal_error() -> Self {
100 Error::new(Kind::InternalError)
101 }
102
103 pub fn message(&self) -> impl fmt::Display + '_ {
105 self.description()
106 }
107
108 fn description(&self) -> String {
109 match &self.inner.kind {
110 Kind::HyperError(_) => "this is a Hyper related error!".to_string(),
111 Kind::HyperHttpError(_) => "this is a Hyper HTTP related error!".to_string(),
112 Kind::InternalError => "internal error".to_string(),
113 Kind::InvalidHeaderValue => "invalid header value".to_string(),
114 Kind::NetworkError => "network error".to_string(),
115 Kind::NotImplementedError => "not implemented error".to_string(),
116 Kind::ParsingError => "parsing error".to_string(),
117 Kind::RetryError => "retry error".to_string(),
118 Kind::RequestNotSuccessful(err) => {
119 format!("client returned an unsuccessful HTTP status code: {}", err)
120 }
121 Kind::SerdeJsonError(_) => "serde deserialization error".to_string(),
122 Kind::Utf8Error => "parsing bytes experienced a UTF8 error".to_string(),
123 Kind::CustomError(err) => {
124 format!("Error: {}", err)
125 }
126 Kind::ConnectAPIError(err) => {
127 format!("Connect API error: {}", err)
128 }
129 }
130 }
131}
132
133#[derive(Debug)]
135pub struct RequestNotSuccessful {
136 pub status: StatusCode,
138 pub body: String,
140}
141
142impl RequestNotSuccessful {
143 pub fn new(status: StatusCode, body: String) -> Self {
145 Self { status, body }
146 }
147}
148
149impl StdError for RequestNotSuccessful {}
150
151impl Display for RequestNotSuccessful {
152 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
153 write!(f, "StatusCode: {}, Body: {}", self.status, self.body)
154 }
155}
156
157#[derive(Debug)]
159pub struct ConnectAPIError {
160 pub message: String,
162 pub status: String,
164}
165
166impl ConnectAPIError {
167 pub fn new(status: String, message: &str) -> Self {
169 Self {
170 status: status.to_string(),
171 message: message.to_string(),
172 }
173 }
174}
175
176impl StdError for ConnectAPIError {}
177
178impl Display for ConnectAPIError {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 write!(f, "StatusCode: {}, Message: {}", self.status, self.message)
181 }
182}
183
184#[derive(Debug)]
186pub struct CustomError {
187 pub message: String,
189}
190
191impl CustomError {
192 pub fn new(message: &str) -> Self {
194 Self {
195 message: message.to_string(),
196 }
197 }
198}
199
200impl StdError for CustomError {}
201
202impl Display for CustomError {
203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204 write!(f, "Message: {}", self.message)
205 }
206}
207
208#[derive(Debug)]
209pub(super) enum Kind {
210 CustomError(CustomError),
211
212 HyperError(hyper::Error),
214
215 HyperHttpError(hyper::http::Error),
217
218 InternalError,
219
220 InvalidHeaderValue,
221
222 NetworkError,
224
225 NotImplementedError,
226
227 ParsingError,
228
229 RetryError,
230
231 RequestNotSuccessful(RequestNotSuccessful),
232
233 SerdeJsonError(serde_json::Error),
234
235 Utf8Error,
236
237 ConnectAPIError(ConnectAPIError),
238}
239
240impl fmt::Display for Kind {
241 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
242 match self {
243 &Self::HyperError(_) => {
244 write!(f, "HyperError")
245 }
246 &Self::HyperHttpError(_) => {
247 write!(f, "HyperHttpError")
248 }
249 Self::InternalError => {
250 write!(f, "InternalError")
251 }
252 Self::InvalidHeaderValue => {
253 write!(f, "InvalidHeaderValue")
254 }
255 Self::NetworkError => {
256 write!(f, "NetworkError")
257 }
258 Self::NotImplementedError => {
259 write!(f, "NotImplementedError")
260 }
261 Self::ParsingError => {
262 write!(f, "ParsingError")
263 }
264 Self::RetryError => {
265 write!(f, "RetryError")
266 }
267 &Self::RequestNotSuccessful(_) => {
268 write!(f, "RequestNotSuccessful")
269 }
270 &Self::SerdeJsonError(_) => {
271 write!(f, "SerdeJsonError")
272 }
273 Self::Utf8Error => {
274 write!(f, "Utf8Error")
275 }
276 &Self::ConnectAPIError(_) => {
277 write!(f, "ConnectAPIError")
278 }
279 &Self::CustomError(_) => {
280 write!(f, "CustomError")
281 }
282 }
283 }
284}
285
286impl From<hyper::Error> for Error {
287 fn from(err: hyper::Error) -> Self {
288 Error::new(Kind::HyperError(err))
289 }
290}
291
292impl From<hyper::http::Error> for Error {
293 fn from(err: hyper::http::Error) -> Self {
294 Error::new(Kind::HyperHttpError(err))
295 }
296}
297
298impl From<InvalidHeaderValue> for Error {
299 fn from(_err: InvalidHeaderValue) -> Self {
300 Error::new(Kind::InvalidHeaderValue)
301 }
302}
303
304impl From<RequestNotSuccessful> for Error {
305 fn from(err: RequestNotSuccessful) -> Self {
306 Error::new(Kind::RequestNotSuccessful(err))
307 }
308}
309
310impl From<Utf8Error> for Error {
311 fn from(err: Utf8Error) -> Self {
312 Error::new(Kind::Utf8Error).with(err)
313 }
314}
315
316impl From<serde_json::Error> for Error {
317 fn from(err: serde_json::Error) -> Self {
318 Error::new(Kind::SerdeJsonError(err))
319 }
320}
321
322#[derive(Debug)]
324pub struct OPError {
325 pub(super) status_code: Option<u16>,
326 pub(super) captures: Option<Vec<String>>,
327}
328
329pub fn process_connect_error_response(err_message: String) -> Result<OPError, Error> {
331 let input_re = Regex::new(r#"(StatusCode):\s+(\d+)"#).unwrap();
332
333 let captures = input_re.captures(&err_message).map(|captures| {
335 captures
336 .iter() .skip(1) .flat_map(|c| c) .map(|c| c.as_str()) .collect::<Vec<_>>() });
342
343 dbg!(&captures);
344
345 let status_code: Option<u16> = match captures.as_ref().map(|c| c.as_slice()) {
347 Some(["StatusCode", x]) => {
348 let x = x.parse().expect("can't parse number");
349 Some(x)
350 }
351 _ => None,
352 };
353
354 let return_captures: Option<Vec<String>> =
355 captures.map(|b| b.into_iter().map(|c| c.to_owned()).collect::<Vec<_>>());
356
357 Ok(OPError {
358 status_code,
359 captures: return_captures,
360 })
361}