#[macro_use] extern crate strum_macros; #[macro_use] extern crate smart_default; pub mod apub; pub mod email; pub mod rate_limit; pub mod settings; pub mod claims; pub mod request; #[cfg(test)] mod test; pub mod utils; pub mod version; use actix_web::HttpResponse; use http::StatusCode; use std::{fmt, fmt::Display, time::Duration}; use tracing_error::SpanTrace; pub type ConnectionId = usize; pub const REQWEST_TIMEOUT: Duration = Duration::from_secs(10); #[derive(PartialEq, Eq, Hash, Debug, Clone)] pub struct IpAddr(pub String); impl fmt::Display for IpAddr { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.0) } } #[macro_export] macro_rules! location_info { () => { format!( "None value at {}:{}, column {}", file!(), line!(), column!() ) }; } #[derive(serde::Serialize)] struct ApiError { error: String, } pub struct LemmyError { pub message: Option, pub inner: anyhow::Error, pub context: SpanTrace, } impl LemmyError { /// Create LemmyError from a message, including stack trace pub fn from_message(message: &str) -> Self { let inner = anyhow::anyhow!("{}", message); LemmyError { message: Some(message.into()), inner, context: SpanTrace::capture(), } } /// Create a LemmyError from error and message, including stack trace pub fn from_error_message(error: E, message: &str) -> Self where E: Into, { LemmyError { message: Some(message.into()), inner: error.into(), context: SpanTrace::capture(), } } /// Add message to existing LemmyError (or overwrite existing error) pub fn with_message(self, message: &str) -> Self { LemmyError { message: Some(message.into()), ..self } } pub fn to_json(&self) -> Result { let api_error = match &self.message { Some(error) => ApiError { error: error.into(), }, None => ApiError { error: "Unknown".into(), }, }; Ok(serde_json::to_string(&api_error)?) } } impl From for LemmyError where T: Into, { fn from(t: T) -> Self { LemmyError { message: None, inner: t.into(), context: SpanTrace::capture(), } } } impl std::fmt::Debug for LemmyError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("LemmyError") .field("message", &self.message) .field("inner", &self.inner) .field("context", &"SpanTrace") .finish() } } impl Display for LemmyError { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { if let Some(message) = &self.message { write!(f, "{}: ", message)?; } writeln!(f, "{}", self.inner)?; self.context.fmt(f) } } impl actix_web::error::ResponseError for LemmyError { fn status_code(&self) -> StatusCode { match self.inner.downcast_ref::() { Some(diesel::result::Error::NotFound) => StatusCode::NOT_FOUND, _ => StatusCode::BAD_REQUEST, } } fn error_response(&self) -> HttpResponse { if let Some(message) = &self.message { HttpResponse::build(self.status_code()).json(ApiError { error: message.into(), }) } else { HttpResponse::build(self.status_code()) .content_type("text/plain") .body(self.inner.to_string()) } } }