mirror of
https://github.com/LemmyNet/lemmy.git
synced 2024-11-22 20:31:19 +00:00
Expose LemmyErrorType in lemmy_api_common (#4439)
* Expose LemmyErrorType in lemmy_api_common * Make conditional compilation gates for utils * Make it so api_common doesn't pull in unnecessary deps * Make error type non exhaustive * Fix formatting * Format toml * Add some convenience derives to LemmyError * Simplify features * Fix CI compile error --------- Co-authored-by: SleeplessOne1917 <insomnia-void@protonmail.com>
This commit is contained in:
parent
f56b84615c
commit
f42420809b
17 changed files with 225 additions and 169 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -2875,6 +2875,7 @@ version = "0.19.3"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"actix-web",
|
"actix-web",
|
||||||
"anyhow",
|
"anyhow",
|
||||||
|
"cfg-if",
|
||||||
"deser-hjson",
|
"deser-hjson",
|
||||||
"diesel",
|
"diesel",
|
||||||
"doku",
|
"doku",
|
||||||
|
|
|
@ -89,7 +89,7 @@ unwrap_used = "deny"
|
||||||
lemmy_api = { version = "=0.19.3", path = "./crates/api" }
|
lemmy_api = { version = "=0.19.3", path = "./crates/api" }
|
||||||
lemmy_api_crud = { version = "=0.19.3", path = "./crates/api_crud" }
|
lemmy_api_crud = { version = "=0.19.3", path = "./crates/api_crud" }
|
||||||
lemmy_apub = { version = "=0.19.3", path = "./crates/apub" }
|
lemmy_apub = { version = "=0.19.3", path = "./crates/apub" }
|
||||||
lemmy_utils = { version = "=0.19.3", path = "./crates/utils" }
|
lemmy_utils = { version = "=0.19.3", path = "./crates/utils", default-features = false }
|
||||||
lemmy_db_schema = { version = "=0.19.3", path = "./crates/db_schema" }
|
lemmy_db_schema = { version = "=0.19.3", path = "./crates/db_schema" }
|
||||||
lemmy_api_common = { version = "=0.19.3", path = "./crates/api_common" }
|
lemmy_api_common = { version = "=0.19.3", path = "./crates/api_common" }
|
||||||
lemmy_routes = { version = "=0.19.3", path = "./crates/routes" }
|
lemmy_routes = { version = "=0.19.3", path = "./crates/routes" }
|
||||||
|
|
|
@ -18,7 +18,7 @@ doctest = false
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lemmy_utils = { workspace = true }
|
lemmy_utils = { workspace = true, features = ["default"] }
|
||||||
lemmy_db_schema = { workspace = true, features = ["full"] }
|
lemmy_db_schema = { workspace = true, features = ["full"] }
|
||||||
lemmy_db_views = { workspace = true, features = ["full"] }
|
lemmy_db_views = { workspace = true, features = ["full"] }
|
||||||
lemmy_db_views_moderator = { workspace = true, features = ["full"] }
|
lemmy_db_views_moderator = { workspace = true, features = ["full"] }
|
||||||
|
|
|
@ -20,10 +20,10 @@ workspace = true
|
||||||
full = [
|
full = [
|
||||||
"tracing",
|
"tracing",
|
||||||
"rosetta-i18n",
|
"rosetta-i18n",
|
||||||
"lemmy_utils",
|
|
||||||
"lemmy_db_views/full",
|
"lemmy_db_views/full",
|
||||||
"lemmy_db_views_actor/full",
|
"lemmy_db_views_actor/full",
|
||||||
"lemmy_db_views_moderator/full",
|
"lemmy_db_views_moderator/full",
|
||||||
|
"lemmy_utils/default",
|
||||||
"activitypub_federation",
|
"activitypub_federation",
|
||||||
"encoding",
|
"encoding",
|
||||||
"reqwest-middleware",
|
"reqwest-middleware",
|
||||||
|
@ -44,7 +44,7 @@ lemmy_db_views = { workspace = true }
|
||||||
lemmy_db_views_moderator = { workspace = true }
|
lemmy_db_views_moderator = { workspace = true }
|
||||||
lemmy_db_views_actor = { workspace = true }
|
lemmy_db_views_actor = { workspace = true }
|
||||||
lemmy_db_schema = { workspace = true }
|
lemmy_db_schema = { workspace = true }
|
||||||
lemmy_utils = { workspace = true, optional = true }
|
lemmy_utils = { workspace = true, features = ["error-type"] }
|
||||||
activitypub_federation = { workspace = true, optional = true }
|
activitypub_federation = { workspace = true, optional = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true }
|
||||||
serde_with = { workspace = true }
|
serde_with = { workspace = true }
|
||||||
|
|
|
@ -23,7 +23,9 @@ pub extern crate lemmy_db_schema;
|
||||||
pub extern crate lemmy_db_views;
|
pub extern crate lemmy_db_views;
|
||||||
pub extern crate lemmy_db_views_actor;
|
pub extern crate lemmy_db_views_actor;
|
||||||
pub extern crate lemmy_db_views_moderator;
|
pub extern crate lemmy_db_views_moderator;
|
||||||
|
pub extern crate lemmy_utils;
|
||||||
|
|
||||||
|
pub use lemmy_utils::LemmyErrorType;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ repository.workspace = true
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lemmy_utils = { workspace = true }
|
lemmy_utils = { workspace = true, features = ["default"] }
|
||||||
lemmy_db_schema = { workspace = true, features = ["full"] }
|
lemmy_db_schema = { workspace = true, features = ["full"] }
|
||||||
lemmy_db_views = { workspace = true, features = ["full"] }
|
lemmy_db_views = { workspace = true, features = ["full"] }
|
||||||
lemmy_db_views_actor = { workspace = true, features = ["full"] }
|
lemmy_db_views_actor = { workspace = true, features = ["full"] }
|
||||||
|
|
|
@ -18,7 +18,7 @@ doctest = false
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lemmy_utils = { workspace = true }
|
lemmy_utils = { workspace = true, features = ["default"] }
|
||||||
lemmy_db_schema = { workspace = true, features = ["full"] }
|
lemmy_db_schema = { workspace = true, features = ["full"] }
|
||||||
lemmy_db_views = { workspace = true, features = ["full"] }
|
lemmy_db_views = { workspace = true, features = ["full"] }
|
||||||
lemmy_db_views_actor = { workspace = true, features = ["full"] }
|
lemmy_db_views_actor = { workspace = true, features = ["full"] }
|
||||||
|
|
|
@ -19,6 +19,6 @@ diesel = { workspace = true }
|
||||||
diesel-async = { workspace = true }
|
diesel-async = { workspace = true }
|
||||||
lemmy_db_schema = { workspace = true }
|
lemmy_db_schema = { workspace = true }
|
||||||
lemmy_db_views = { workspace = true, features = ["full"] }
|
lemmy_db_views = { workspace = true, features = ["full"] }
|
||||||
lemmy_utils = { workspace = true }
|
lemmy_utils = { workspace = true, features = ["default"] }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true }
|
||||||
url = { workspace = true }
|
url = { workspace = true }
|
||||||
|
|
|
@ -48,7 +48,7 @@ strum = { workspace = true }
|
||||||
strum_macros = { workspace = true }
|
strum_macros = { workspace = true }
|
||||||
serde_json = { workspace = true, optional = true }
|
serde_json = { workspace = true, optional = true }
|
||||||
activitypub_federation = { workspace = true, optional = true }
|
activitypub_federation = { workspace = true, optional = true }
|
||||||
lemmy_utils = { workspace = true, optional = true }
|
lemmy_utils = { workspace = true, optional = true, features = ["default"] }
|
||||||
bcrypt = { workspace = true, optional = true }
|
bcrypt = { workspace = true, optional = true }
|
||||||
diesel = { workspace = true, features = [
|
diesel = { workspace = true, features = [
|
||||||
"postgres",
|
"postgres",
|
||||||
|
|
|
@ -29,7 +29,7 @@ full = [
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lemmy_db_schema = { workspace = true }
|
lemmy_db_schema = { workspace = true }
|
||||||
lemmy_utils = { workspace = true, optional = true }
|
lemmy_utils = { workspace = true, optional = true, features = ["default"] }
|
||||||
diesel = { workspace = true, optional = true }
|
diesel = { workspace = true, optional = true }
|
||||||
diesel-async = { workspace = true, optional = true }
|
diesel-async = { workspace = true, optional = true }
|
||||||
diesel_ltree = { workspace = true, optional = true }
|
diesel_ltree = { workspace = true, optional = true }
|
||||||
|
|
|
@ -16,7 +16,7 @@ doctest = false
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
lemmy_utils = { workspace = true }
|
lemmy_utils = { workspace = true, features = ["default"] }
|
||||||
lemmy_db_views = { workspace = true }
|
lemmy_db_views = { workspace = true }
|
||||||
lemmy_db_views_actor = { workspace = true }
|
lemmy_db_views_actor = { workspace = true }
|
||||||
lemmy_db_schema = { workspace = true }
|
lemmy_db_schema = { workspace = true }
|
||||||
|
|
|
@ -13,42 +13,82 @@ name = "lemmy_utils"
|
||||||
path = "src/lib.rs"
|
path = "src/lib.rs"
|
||||||
doctest = false
|
doctest = false
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "lemmy_util_bin"
|
||||||
|
path = "src/main.rs"
|
||||||
|
required-features = ["default"]
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
full = ["ts-rs"]
|
default = [
|
||||||
|
"error-type",
|
||||||
|
"dep:serde_json",
|
||||||
|
"dep:anyhow",
|
||||||
|
"dep:tracing-error",
|
||||||
|
"dep:diesel",
|
||||||
|
"dep:http",
|
||||||
|
"dep:actix-web",
|
||||||
|
"dep:reqwest-middleware",
|
||||||
|
"dep:tracing",
|
||||||
|
"dep:actix-web",
|
||||||
|
"dep:deser-hjson",
|
||||||
|
"dep:regex",
|
||||||
|
"dep:urlencoding",
|
||||||
|
"dep:doku",
|
||||||
|
"dep:url",
|
||||||
|
"dep:once_cell",
|
||||||
|
"dep:smart-default",
|
||||||
|
"dep:enum-map",
|
||||||
|
"dep:futures",
|
||||||
|
"dep:tokio",
|
||||||
|
"dep:openssl",
|
||||||
|
"dep:html2text",
|
||||||
|
"dep:lettre",
|
||||||
|
"dep:uuid",
|
||||||
|
"dep:rosetta-i18n",
|
||||||
|
"dep:itertools",
|
||||||
|
"dep:markdown-it",
|
||||||
|
|
||||||
|
]
|
||||||
|
full = ["default", "dep:ts-rs"]
|
||||||
|
error-type = ["dep:serde", "dep:strum"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
regex = { workspace = true }
|
regex = { workspace = true, optional = true }
|
||||||
tracing = { workspace = true }
|
tracing = { workspace = true, optional = true }
|
||||||
tracing-error = { workspace = true }
|
tracing-error = { workspace = true, optional = true }
|
||||||
itertools = { workspace = true }
|
itertools = { workspace = true, optional = true }
|
||||||
serde = { workspace = true }
|
serde = { workspace = true, optional = true }
|
||||||
serde_json = { workspace = true }
|
serde_json = { workspace = true, optional = true }
|
||||||
once_cell = { workspace = true }
|
once_cell = { workspace = true, optional = true }
|
||||||
url = { workspace = true }
|
url = { workspace = true, optional = true }
|
||||||
actix-web = { workspace = true }
|
actix-web = { workspace = true, optional = true }
|
||||||
anyhow = { workspace = true }
|
anyhow = { workspace = true, optional = true }
|
||||||
reqwest-middleware = { workspace = true }
|
reqwest-middleware = { workspace = true, optional = true }
|
||||||
strum = { workspace = true }
|
strum = { workspace = true, optional = true }
|
||||||
strum_macros = { workspace = true }
|
strum_macros = { workspace = true }
|
||||||
futures = { workspace = true }
|
futures = { workspace = true, optional = true }
|
||||||
diesel = { workspace = true, features = ["chrono"] }
|
diesel = { workspace = true, features = ["chrono"], optional = true }
|
||||||
http = { workspace = true }
|
http = { workspace = true, optional = true }
|
||||||
doku = { workspace = true, features = ["url-2"] }
|
doku = { workspace = true, features = ["url-2"], optional = true }
|
||||||
uuid = { workspace = true, features = ["serde", "v4"] }
|
uuid = { workspace = true, features = ["serde", "v4"], optional = true }
|
||||||
rosetta-i18n = { workspace = true }
|
rosetta-i18n = { workspace = true, optional = true }
|
||||||
tokio = { workspace = true }
|
tokio = { workspace = true, optional = true }
|
||||||
urlencoding = { workspace = true }
|
urlencoding = { workspace = true, optional = true }
|
||||||
openssl = "0.10.63"
|
openssl = { version = "0.10.63", optional = true }
|
||||||
html2text = "0.6.0"
|
html2text = { version = "0.6.0", optional = true }
|
||||||
deser-hjson = "2.2.4"
|
deser-hjson = { version = "2.2.4", optional = true }
|
||||||
smart-default = "0.7.1"
|
smart-default = { version = "0.7.1", optional = true }
|
||||||
lettre = { version = "0.11.3", features = ["tokio1", "tokio1-native-tls"] }
|
lettre = { version = "0.11.3", features = [
|
||||||
markdown-it = "0.6.0"
|
"tokio1",
|
||||||
|
"tokio1-native-tls",
|
||||||
|
], optional = true }
|
||||||
|
markdown-it = { version = "0.6.0", optional = true }
|
||||||
ts-rs = { workspace = true, optional = true }
|
ts-rs = { workspace = true, optional = true }
|
||||||
enum-map = { workspace = true }
|
enum-map = { workspace = true, optional = true }
|
||||||
|
cfg-if = "1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
reqwest = { workspace = true }
|
reqwest = { workspace = true }
|
||||||
|
|
|
@ -1,79 +1,15 @@
|
||||||
|
use cfg_if::cfg_if;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::fmt::Debug;
|
||||||
fmt,
|
use strum_macros::{Display, EnumIter};
|
||||||
fmt::{Debug, Display},
|
|
||||||
};
|
|
||||||
use tracing_error::SpanTrace;
|
|
||||||
#[cfg(feature = "full")]
|
#[cfg(feature = "full")]
|
||||||
use ts_rs::TS;
|
use ts_rs::TS;
|
||||||
|
|
||||||
pub type LemmyResult<T> = Result<T, LemmyError>;
|
#[derive(Display, Debug, Serialize, Deserialize, Clone, PartialEq, Eq, EnumIter, Hash)]
|
||||||
|
#[cfg_attr(feature = "ts-rs", derive(TS))]
|
||||||
pub struct LemmyError {
|
#[cfg_attr(feature = "ts-rs", ts(export))]
|
||||||
pub error_type: LemmyErrorType,
|
|
||||||
pub inner: anyhow::Error,
|
|
||||||
pub context: SpanTrace,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Maximum number of items in an array passed as API parameter. See [[LemmyErrorType::TooManyItems]]
|
|
||||||
pub const MAX_API_PARAM_ELEMENTS: usize = 10_000;
|
|
||||||
|
|
||||||
impl<T> From<T> for LemmyError
|
|
||||||
where
|
|
||||||
T: Into<anyhow::Error>,
|
|
||||||
{
|
|
||||||
fn from(t: T) -> Self {
|
|
||||||
let cause = t.into();
|
|
||||||
LemmyError {
|
|
||||||
error_type: LemmyErrorType::Unknown(format!("{}", &cause)),
|
|
||||||
inner: cause,
|
|
||||||
context: SpanTrace::capture(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for LemmyError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
f.debug_struct("LemmyError")
|
|
||||||
.field("message", &self.error_type)
|
|
||||||
.field("inner", &self.inner)
|
|
||||||
.field("context", &self.context)
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for LemmyError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "{}: ", &self.error_type)?;
|
|
||||||
// print anyhow including trace
|
|
||||||
// https://docs.rs/anyhow/latest/anyhow/struct.Error.html#display-representations
|
|
||||||
// this will print the anyhow trace (only if it exists)
|
|
||||||
// and if RUST_BACKTRACE=1, also a full backtrace
|
|
||||||
writeln!(f, "{:?}", self.inner)?;
|
|
||||||
fmt::Display::fmt(&self.context, f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl actix_web::error::ResponseError for LemmyError {
|
|
||||||
fn status_code(&self) -> http::StatusCode {
|
|
||||||
if self.error_type == LemmyErrorType::IncorrectLogin {
|
|
||||||
return http::StatusCode::UNAUTHORIZED;
|
|
||||||
}
|
|
||||||
match self.inner.downcast_ref::<diesel::result::Error>() {
|
|
||||||
Some(diesel::result::Error::NotFound) => http::StatusCode::NOT_FOUND,
|
|
||||||
_ => http::StatusCode::BAD_REQUEST,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn error_response(&self) -> actix_web::HttpResponse {
|
|
||||||
actix_web::HttpResponse::build(self.status_code()).json(&self.error_type)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Display, Debug, Serialize, Deserialize, Clone, PartialEq, EnumIter)]
|
|
||||||
#[cfg_attr(feature = "full", derive(TS))]
|
|
||||||
#[cfg_attr(feature = "full", ts(export))]
|
|
||||||
#[serde(tag = "error", content = "message", rename_all = "snake_case")]
|
#[serde(tag = "error", content = "message", rename_all = "snake_case")]
|
||||||
|
#[non_exhaustive]
|
||||||
// TODO: order these based on the crate they belong to (utils, federation, db, api)
|
// TODO: order these based on the crate they belong to (utils, federation, db, api)
|
||||||
pub enum LemmyErrorType {
|
pub enum LemmyErrorType {
|
||||||
ReportReasonRequired,
|
ReportReasonRequired,
|
||||||
|
@ -231,45 +167,115 @@ pub enum LemmyErrorType {
|
||||||
Unknown(String),
|
Unknown(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<LemmyErrorType> for LemmyError {
|
cfg_if! {
|
||||||
fn from(error_type: LemmyErrorType) -> Self {
|
if #[cfg(feature = "default")] {
|
||||||
let inner = anyhow::anyhow!("{}", error_type);
|
|
||||||
LemmyError {
|
use tracing_error::SpanTrace;
|
||||||
error_type,
|
use std::fmt;
|
||||||
inner,
|
pub type LemmyResult<T> = Result<T, LemmyError>;
|
||||||
context: SpanTrace::capture(),
|
|
||||||
|
pub struct LemmyError {
|
||||||
|
pub error_type: LemmyErrorType,
|
||||||
|
pub inner: anyhow::Error,
|
||||||
|
pub context: SpanTrace,
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait LemmyErrorExt<T, E: Into<anyhow::Error>> {
|
/// Maximum number of items in an array passed as API parameter. See [[LemmyErrorType::TooManyItems]]
|
||||||
fn with_lemmy_type(self, error_type: LemmyErrorType) -> Result<T, LemmyError>;
|
pub const MAX_API_PARAM_ELEMENTS: usize = 10_000;
|
||||||
}
|
|
||||||
|
|
||||||
impl<T, E: Into<anyhow::Error>> LemmyErrorExt<T, E> for Result<T, E> {
|
impl<T> From<T> for LemmyError
|
||||||
fn with_lemmy_type(self, error_type: LemmyErrorType) -> Result<T, LemmyError> {
|
where
|
||||||
self.map_err(|error| LemmyError {
|
T: Into<anyhow::Error>,
|
||||||
error_type,
|
{
|
||||||
inner: error.into(),
|
fn from(t: T) -> Self {
|
||||||
context: SpanTrace::capture(),
|
let cause = t.into();
|
||||||
})
|
LemmyError {
|
||||||
}
|
error_type: LemmyErrorType::Unknown(format!("{}", &cause)),
|
||||||
}
|
inner: cause,
|
||||||
pub trait LemmyErrorExt2<T> {
|
context: SpanTrace::capture(),
|
||||||
fn with_lemmy_type(self, error_type: LemmyErrorType) -> Result<T, LemmyError>;
|
}
|
||||||
fn into_anyhow(self) -> Result<T, anyhow::Error>;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> LemmyErrorExt2<T> for Result<T, LemmyError> {
|
impl Debug for LemmyError {
|
||||||
fn with_lemmy_type(self, error_type: LemmyErrorType) -> Result<T, LemmyError> {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
self.map_err(|mut e| {
|
f.debug_struct("LemmyError")
|
||||||
e.error_type = error_type;
|
.field("message", &self.error_type)
|
||||||
e
|
.field("inner", &self.inner)
|
||||||
})
|
.field("context", &self.context)
|
||||||
}
|
.finish()
|
||||||
// this function can't be an impl From or similar because it would conflict with one of the other broad Into<> implementations
|
}
|
||||||
fn into_anyhow(self) -> Result<T, anyhow::Error> {
|
}
|
||||||
self.map_err(|e| e.inner)
|
|
||||||
|
impl fmt::Display for LemmyError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{}: ", &self.error_type)?;
|
||||||
|
// print anyhow including trace
|
||||||
|
// https://docs.rs/anyhow/latest/anyhow/struct.Error.html#display-representations
|
||||||
|
// this will print the anyhow trace (only if it exists)
|
||||||
|
// and if RUST_BACKTRACE=1, also a full backtrace
|
||||||
|
writeln!(f, "{:?}", self.inner)?;
|
||||||
|
fmt::Display::fmt(&self.context, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl actix_web::error::ResponseError for LemmyError {
|
||||||
|
fn status_code(&self) -> http::StatusCode {
|
||||||
|
if self.error_type == LemmyErrorType::IncorrectLogin {
|
||||||
|
return http::StatusCode::UNAUTHORIZED;
|
||||||
|
}
|
||||||
|
match self.inner.downcast_ref::<diesel::result::Error>() {
|
||||||
|
Some(diesel::result::Error::NotFound) => http::StatusCode::NOT_FOUND,
|
||||||
|
_ => http::StatusCode::BAD_REQUEST,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn error_response(&self) -> actix_web::HttpResponse {
|
||||||
|
actix_web::HttpResponse::build(self.status_code()).json(&self.error_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<LemmyErrorType> for LemmyError {
|
||||||
|
fn from(error_type: LemmyErrorType) -> Self {
|
||||||
|
let inner = anyhow::anyhow!("{}", error_type);
|
||||||
|
LemmyError {
|
||||||
|
error_type,
|
||||||
|
inner,
|
||||||
|
context: SpanTrace::capture(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait LemmyErrorExt<T, E: Into<anyhow::Error>> {
|
||||||
|
fn with_lemmy_type(self, error_type: LemmyErrorType) -> Result<T, LemmyError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, E: Into<anyhow::Error>> LemmyErrorExt<T, E> for Result<T, E> {
|
||||||
|
fn with_lemmy_type(self, error_type: LemmyErrorType) -> Result<T, LemmyError> {
|
||||||
|
self.map_err(|error| LemmyError {
|
||||||
|
error_type,
|
||||||
|
inner: error.into(),
|
||||||
|
context: SpanTrace::capture(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub trait LemmyErrorExt2<T> {
|
||||||
|
fn with_lemmy_type(self, error_type: LemmyErrorType) -> Result<T, LemmyError>;
|
||||||
|
fn into_anyhow(self) -> Result<T, anyhow::Error>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> LemmyErrorExt2<T> for Result<T, LemmyError> {
|
||||||
|
fn with_lemmy_type(self, error_type: LemmyErrorType) -> Result<T, LemmyError> {
|
||||||
|
self.map_err(|mut e| {
|
||||||
|
e.error_type = error_type;
|
||||||
|
e
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// this function can't be an impl From or similar because it would conflict with one of the other broad Into<> implementations
|
||||||
|
fn into_anyhow(self) -> Result<T, anyhow::Error> {
|
||||||
|
self.map_err(|e| e.inner)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,23 +1,29 @@
|
||||||
#[macro_use]
|
use cfg_if::cfg_if;
|
||||||
extern crate strum_macros;
|
|
||||||
#[macro_use]
|
|
||||||
extern crate smart_default;
|
|
||||||
|
|
||||||
pub mod apub;
|
cfg_if! {
|
||||||
pub mod cache_header;
|
if #[cfg(feature = "default")] {
|
||||||
pub mod email;
|
pub mod apub;
|
||||||
pub mod error;
|
pub mod cache_header;
|
||||||
pub mod rate_limit;
|
pub mod email;
|
||||||
pub mod request;
|
pub mod error;
|
||||||
pub mod response;
|
pub mod rate_limit;
|
||||||
pub mod settings;
|
pub mod request;
|
||||||
pub mod utils;
|
pub mod response;
|
||||||
pub mod version;
|
pub mod settings;
|
||||||
|
pub mod utils;
|
||||||
|
pub mod version;
|
||||||
|
} else {
|
||||||
|
mod error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "error-type")] {
|
||||||
|
pub use error::LemmyErrorType;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
use error::LemmyError;
|
|
||||||
use futures::Future;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tracing::Instrument;
|
|
||||||
|
|
||||||
pub type ConnectionId = usize;
|
pub type ConnectionId = usize;
|
||||||
|
|
||||||
|
@ -35,10 +41,14 @@ macro_rules! location_info {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "default")]
|
||||||
/// tokio::spawn, but accepts a future that may fail and also
|
/// tokio::spawn, but accepts a future that may fail and also
|
||||||
/// * logs errors
|
/// * logs errors
|
||||||
/// * attaches the spawned task to the tracing span of the caller for better logging
|
/// * attaches the spawned task to the tracing span of the caller for better logging
|
||||||
pub fn spawn_try_task(task: impl Future<Output = Result<(), LemmyError>> + Send + 'static) {
|
pub fn spawn_try_task(
|
||||||
|
task: impl futures::Future<Output = Result<(), error::LemmyError>> + Send + 'static,
|
||||||
|
) {
|
||||||
|
use tracing::Instrument;
|
||||||
tokio::spawn(
|
tokio::spawn(
|
||||||
async {
|
async {
|
||||||
if let Err(e) = task.await {
|
if let Err(e) = task.await {
|
||||||
|
|
|
@ -6,6 +6,7 @@ use std::{
|
||||||
net::{IpAddr, Ipv4Addr, Ipv6Addr},
|
net::{IpAddr, Ipv4Addr, Ipv6Addr},
|
||||||
time::Instant,
|
time::Instant,
|
||||||
};
|
};
|
||||||
|
use strum_macros::AsRefStr;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
static START_TIME: Lazy<Instant> = Lazy::new(Instant::now);
|
static START_TIME: Lazy<Instant> = Lazy::new(Instant::now);
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
use crate::{
|
use crate::{error::LemmyError, location_info};
|
||||||
error::LemmyError,
|
|
||||||
location_info,
|
|
||||||
settings::structs::{PictrsConfig, Settings},
|
|
||||||
};
|
|
||||||
use anyhow::{anyhow, Context};
|
use anyhow::{anyhow, Context};
|
||||||
use deser_hjson::from_str;
|
use deser_hjson::from_str;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
|
@ -12,8 +8,7 @@ use urlencoding::encode;
|
||||||
|
|
||||||
pub mod structs;
|
pub mod structs;
|
||||||
|
|
||||||
use crate::settings::structs::PictrsImageMode;
|
use structs::{DatabaseConnection, PictrsConfig, PictrsImageMode, Settings};
|
||||||
use structs::DatabaseConnection;
|
|
||||||
|
|
||||||
static DEFAULT_CONFIG_FILE: &str = "config/config.hjson";
|
static DEFAULT_CONFIG_FILE: &str = "config/config.hjson";
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use doku::Document;
|
use doku::Document;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
use smart_default::SmartDefault;
|
||||||
use std::{
|
use std::{
|
||||||
env,
|
env,
|
||||||
net::{IpAddr, Ipv4Addr},
|
net::{IpAddr, Ipv4Addr},
|
||||||
|
|
Loading…
Reference in a new issue