]> Untitled Git - lemmy.git/blob - crates/utils/src/lib.rs
Consolidate and lower reqwest timeouts. Fixes #2150 (#2151)
[lemmy.git] / crates / utils / src / lib.rs
1 #[macro_use]
2 extern crate strum_macros;
3 #[macro_use]
4 extern crate smart_default;
5
6 pub mod apub;
7 pub mod email;
8 pub mod rate_limit;
9 pub mod request;
10 pub mod settings;
11
12 pub mod claims;
13 #[cfg(test)]
14 mod test;
15 pub mod utils;
16 pub mod version;
17
18 mod sensitive;
19
20 pub use sensitive::Sensitive;
21
22 use actix_web::HttpResponse;
23 use http::StatusCode;
24 use std::{fmt, fmt::Display, time::Duration};
25 use tracing_error::SpanTrace;
26
27 pub type ConnectionId = usize;
28
29 pub const REQWEST_TIMEOUT: Duration = Duration::from_secs(10);
30
31 #[derive(PartialEq, Eq, Hash, Debug, Clone)]
32 pub struct IpAddr(pub String);
33
34 impl fmt::Display for IpAddr {
35   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
36     write!(f, "{}", self.0)
37   }
38 }
39
40 #[macro_export]
41 macro_rules! location_info {
42   () => {
43     format!(
44       "None value at {}:{}, column {}",
45       file!(),
46       line!(),
47       column!()
48     )
49   };
50 }
51
52 #[derive(serde::Serialize)]
53 struct ApiError {
54   error: &'static str,
55 }
56
57 pub struct LemmyError {
58   pub message: Option<&'static str>,
59   pub inner: anyhow::Error,
60   pub context: SpanTrace,
61 }
62
63 impl LemmyError {
64   /// Create LemmyError from a message, including stack trace
65   pub fn from_message(message: &'static str) -> Self {
66     let inner = anyhow::anyhow!("{}", message);
67     LemmyError {
68       message: Some(message),
69       inner,
70       context: SpanTrace::capture(),
71     }
72   }
73
74   /// Create a LemmyError from error and message, including stack trace
75   pub fn from_error_message<E>(error: E, message: &'static str) -> Self
76   where
77     E: Into<anyhow::Error>,
78   {
79     LemmyError {
80       message: Some(message),
81       inner: error.into(),
82       context: SpanTrace::capture(),
83     }
84   }
85
86   /// Add message to existing LemmyError (or overwrite existing error)
87   pub fn with_message(self, message: &'static str) -> Self {
88     LemmyError {
89       message: Some(message),
90       ..self
91     }
92   }
93
94   pub fn to_json(&self) -> Result<String, Self> {
95     let api_error = match self.message {
96       Some(error) => ApiError { error },
97       None => ApiError { error: "Unknown" },
98     };
99
100     Ok(serde_json::to_string(&api_error)?)
101   }
102 }
103
104 impl<T> From<T> for LemmyError
105 where
106   T: Into<anyhow::Error>,
107 {
108   fn from(t: T) -> Self {
109     LemmyError {
110       message: None,
111       inner: t.into(),
112       context: SpanTrace::capture(),
113     }
114   }
115 }
116
117 impl std::fmt::Debug for LemmyError {
118   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
119     f.debug_struct("LemmyError")
120       .field("message", &self.message)
121       .field("inner", &self.inner)
122       .field("context", &"SpanTrace")
123       .finish()
124   }
125 }
126
127 impl Display for LemmyError {
128   fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
129     if let Some(message) = self.message {
130       write!(f, "{}: ", message)?;
131     }
132     writeln!(f, "{}", self.inner)?;
133     self.context.fmt(f)
134   }
135 }
136
137 impl actix_web::error::ResponseError for LemmyError {
138   fn status_code(&self) -> StatusCode {
139     match self.inner.downcast_ref::<diesel::result::Error>() {
140       Some(diesel::result::Error::NotFound) => StatusCode::NOT_FOUND,
141       _ => StatusCode::BAD_REQUEST,
142     }
143   }
144
145   fn error_response(&self) -> HttpResponse {
146     if let Some(message) = &self.message {
147       HttpResponse::build(self.status_code()).json(ApiError { error: message })
148     } else {
149       HttpResponse::build(self.status_code())
150         .content_type("text/plain")
151         .body(self.inner.to_string())
152     }
153   }
154 }