]> Untitled Git - lemmy.git/blob - crates/utils/src/lib.rs
04c60e3fca5854360ac4eb34ccd338f5f948b61a
[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};
25 use tracing_error::SpanTrace;
26
27 pub type ConnectionId = usize;
28
29 #[derive(PartialEq, Eq, Hash, Debug, Clone)]
30 pub struct IpAddr(pub String);
31
32 impl fmt::Display for IpAddr {
33   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
34     write!(f, "{}", self.0)
35   }
36 }
37
38 #[macro_export]
39 macro_rules! location_info {
40   () => {
41     format!(
42       "None value at {}:{}, column {}",
43       file!(),
44       line!(),
45       column!()
46     )
47   };
48 }
49
50 #[derive(serde::Serialize)]
51 struct ApiError {
52   error: &'static str,
53 }
54
55 pub struct LemmyError {
56   pub message: Option<&'static str>,
57   pub inner: anyhow::Error,
58   pub context: SpanTrace,
59 }
60
61 impl LemmyError {
62   pub fn from_message(message: &'static str) -> Self {
63     let inner = anyhow::anyhow!("{}", message);
64     LemmyError {
65       message: Some(message),
66       inner,
67       context: SpanTrace::capture(),
68     }
69   }
70   pub fn with_message(self, message: &'static str) -> Self {
71     LemmyError {
72       message: Some(message),
73       ..self
74     }
75   }
76   pub fn to_json(&self) -> Result<String, Self> {
77     let api_error = match self.message {
78       Some(error) => ApiError { error },
79       None => ApiError { error: "Unknown" },
80     };
81
82     Ok(serde_json::to_string(&api_error)?)
83   }
84 }
85
86 impl<T> From<T> for LemmyError
87 where
88   T: Into<anyhow::Error>,
89 {
90   fn from(t: T) -> Self {
91     LemmyError {
92       message: None,
93       inner: t.into(),
94       context: SpanTrace::capture(),
95     }
96   }
97 }
98
99 impl std::fmt::Debug for LemmyError {
100   fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
101     f.debug_struct("LemmyError")
102       .field("message", &self.message)
103       .field("inner", &self.inner)
104       .field("context", &"SpanTrace")
105       .finish()
106   }
107 }
108
109 impl Display for LemmyError {
110   fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
111     if let Some(message) = self.message {
112       write!(f, "{}: ", message)?;
113     }
114     writeln!(f, "{}", self.inner)?;
115     self.context.fmt(f)
116   }
117 }
118
119 impl actix_web::error::ResponseError for LemmyError {
120   fn status_code(&self) -> StatusCode {
121     match self.inner.downcast_ref::<diesel::result::Error>() {
122       Some(diesel::result::Error::NotFound) => StatusCode::NOT_FOUND,
123       _ => StatusCode::BAD_REQUEST,
124     }
125   }
126
127   fn error_response(&self) -> HttpResponse {
128     if let Some(message) = &self.message {
129       HttpResponse::build(self.status_code()).json(ApiError { error: message })
130     } else {
131       HttpResponse::build(self.status_code())
132         .content_type("text/plain")
133         .body(self.inner.to_string())
134     }
135   }
136 }