Serde errors
This commit is contained in:
parent
6968a4e449
commit
aacb8caaa3
5 changed files with 47 additions and 27 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
|
@ -811,6 +811,7 @@ dependencies = [
|
||||||
"dht",
|
"dht",
|
||||||
"futures",
|
"futures",
|
||||||
"hex 0.4.3",
|
"hex 0.4.3",
|
||||||
|
"http",
|
||||||
"librqbit_core",
|
"librqbit_core",
|
||||||
"log",
|
"log",
|
||||||
"openssl",
|
"openssl",
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ serde_json = "1"
|
||||||
serde_urlencoded = "*"
|
serde_urlencoded = "*"
|
||||||
anyhow = "1"
|
anyhow = "1"
|
||||||
|
|
||||||
|
http = "0.2"
|
||||||
regex = "1"
|
regex = "1"
|
||||||
reqwest = {version="0.11", default-features=false}
|
reqwest = {version="0.11", default-features=false}
|
||||||
urlencoding = "2"
|
urlencoding = "2"
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use anyhow::Context;
|
use anyhow::Context;
|
||||||
use axum::extract::{Path, Query, State};
|
use axum::extract::{Path, Query, State};
|
||||||
use axum::http::StatusCode;
|
|
||||||
use buffers::ByteString;
|
use buffers::ByteString;
|
||||||
use dht::{Dht, DhtStats};
|
use dht::{Dht, DhtStats};
|
||||||
|
use http::StatusCode;
|
||||||
use librqbit_core::id20::Id20;
|
use librqbit_core::id20::Id20;
|
||||||
use librqbit_core::torrent_metainfo::TorrentMetaV1Info;
|
use librqbit_core::torrent_metainfo::TorrentMetaV1Info;
|
||||||
use log::warn;
|
use log::warn;
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,18 @@ async fn check_response(r: reqwest::Response) -> anyhow::Result<reqwest::Respons
|
||||||
.text()
|
.text()
|
||||||
.await
|
.await
|
||||||
.with_context(|| format!("cannot read response body for request to {url} ({status})"))?;
|
.with_context(|| format!("cannot read response body for request to {url} ({status})"))?;
|
||||||
anyhow::bail!("{} -> {}: {}", url, status, body)
|
|
||||||
|
#[derive(Deserialize)]
|
||||||
|
struct HumanReadableError<'a> {
|
||||||
|
human_readable: Option<&'a str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
let human_readable_internal_error = serde_json::from_str::<HumanReadableError<'_>>(&body)
|
||||||
|
.ok()
|
||||||
|
.and_then(|e| e.human_readable);
|
||||||
|
let body_display = human_readable_internal_error.unwrap_or(&body);
|
||||||
|
|
||||||
|
anyhow::bail!("{} -> {}: {}", url, status, body_display)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,7 @@
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
|
|
||||||
use axum::{
|
use axum::response::{IntoResponse, Response};
|
||||||
http::StatusCode,
|
use http::StatusCode;
|
||||||
response::{IntoResponse, Response},
|
|
||||||
};
|
|
||||||
use serde::{ser::SerializeMap, Serialize, Serializer};
|
use serde::{ser::SerializeMap, Serialize, Serializer};
|
||||||
|
|
||||||
// Convenience error type.
|
// Convenience error type.
|
||||||
|
|
@ -60,31 +58,40 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for ApiErrorKind {
|
impl Serialize for ApiError {
|
||||||
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
where
|
where
|
||||||
S: Serializer,
|
S: Serializer,
|
||||||
{
|
{
|
||||||
match self {
|
#[derive(Serialize, Default)]
|
||||||
ApiErrorKind::TorrentNotFound(id) => {
|
struct SerializedError<'a> {
|
||||||
let mut m = serializer.serialize_map(None)?;
|
error_kind: &'a str,
|
||||||
m.serialize_entry("error_kind", "torrent_not_found")?;
|
human_readable: String,
|
||||||
m.serialize_entry("id", id)?;
|
status: u16,
|
||||||
m.end()
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
}
|
id: Option<usize>,
|
||||||
ApiErrorKind::DhtDisabled => {
|
#[serde(skip_serializing_if = "Option::is_none")]
|
||||||
let mut m = serializer.serialize_map(None)?;
|
error_chain: Option<ErrWrap<'a, dyn std::error::Error>>,
|
||||||
m.serialize_entry("error_kind", "dht_disabled")?;
|
|
||||||
m.end()
|
|
||||||
}
|
|
||||||
ApiErrorKind::Other(err) => {
|
|
||||||
let mut m = serializer.serialize_map(None)?;
|
|
||||||
m.serialize_entry("error_kind", "internal_error")?;
|
|
||||||
m.serialize_entry("human_readable", &format!("{err:#}"))?;
|
|
||||||
m.serialize_entry("error_chain", &ErrWrap(err.deref()))?;
|
|
||||||
m.end()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
let mut serr: SerializedError = SerializedError {
|
||||||
|
error_kind: match self.kind {
|
||||||
|
ApiErrorKind::TorrentNotFound(_) => "torrent_not_found",
|
||||||
|
ApiErrorKind::DhtDisabled => "dht_disabled",
|
||||||
|
ApiErrorKind::Other(_) => "internal_error",
|
||||||
|
},
|
||||||
|
human_readable: format!("{self}"),
|
||||||
|
status: self
|
||||||
|
.status
|
||||||
|
.unwrap_or(StatusCode::INTERNAL_SERVER_ERROR)
|
||||||
|
.as_u16(),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
match &self.kind {
|
||||||
|
ApiErrorKind::TorrentNotFound(id) => serr.id = Some(*id),
|
||||||
|
ApiErrorKind::Other(err) => serr.error_chain = Some(ErrWrap(err.deref())),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
serr.serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -118,7 +125,7 @@ impl std::fmt::Display for ApiError {
|
||||||
|
|
||||||
impl IntoResponse for ApiError {
|
impl IntoResponse for ApiError {
|
||||||
fn into_response(self) -> Response {
|
fn into_response(self) -> Response {
|
||||||
let mut response = axum::Json(&self.kind).into_response();
|
let mut response = axum::Json(&self).into_response();
|
||||||
*response.status_mut() = match self.status {
|
*response.status_mut() = match self.status {
|
||||||
Some(s) => s,
|
Some(s) => s,
|
||||||
None => StatusCode::INTERNAL_SERVER_ERROR,
|
None => StatusCode::INTERNAL_SERVER_ERROR,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue