Better JSON error messages (#91)
This commit is contained in:
parent
709f29b7f8
commit
9e8d466b40
6 changed files with 29 additions and 52 deletions
|
@ -56,14 +56,16 @@ impl SendActivityTask<'_> {
|
|||
data: &Data<Datatype>,
|
||||
) -> Result<Vec<SendActivityTask<'a>>, Error>
|
||||
where
|
||||
Activity: ActivityHandler + Serialize,
|
||||
Activity: ActivityHandler + Serialize + Debug,
|
||||
Datatype: Clone,
|
||||
ActorType: Actor,
|
||||
{
|
||||
let config = &data.config;
|
||||
let actor_id = activity.actor();
|
||||
let activity_id = activity.id();
|
||||
let activity_serialized: Bytes = serde_json::to_vec(&activity).map_err(Error::Json)?.into();
|
||||
let activity_serialized: Bytes = serde_json::to_vec(&activity)
|
||||
.map_err(|e| Error::SerializeOutgoingActivity(e, format!("{:?}", activity)))?
|
||||
.into();
|
||||
let private_key = get_pkey_cached(data, actor).await?;
|
||||
|
||||
Ok(futures::stream::iter(
|
||||
|
|
|
@ -130,8 +130,8 @@ mod test {
|
|||
.await;
|
||||
|
||||
match res {
|
||||
Err(Error::ParseReceivedActivity(url, _)) => {
|
||||
assert_eq!(id, url.as_str());
|
||||
Err(Error::ParseReceivedActivity(_, url)) => {
|
||||
assert_eq!(id, url.expect("has url").as_str());
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
|
|
16
src/error.rs
16
src/error.rs
|
@ -35,12 +35,18 @@ pub enum Error {
|
|||
/// Failed to resolve actor via webfinger
|
||||
#[error("Failed to resolve actor via webfinger")]
|
||||
WebfingerResolveFailed(#[from] WebFingerError),
|
||||
/// JSON Error
|
||||
#[error(transparent)]
|
||||
Json(#[from] serde_json::Error),
|
||||
/// Failed to serialize outgoing activity
|
||||
#[error("Failed to serialize outgoing activity {1}: {0}")]
|
||||
SerializeOutgoingActivity(serde_json::Error, String),
|
||||
/// Failed to parse an object fetched from url
|
||||
#[error("Failed to parse object {1} with content {2}: {0}")]
|
||||
ParseFetchedObject(serde_json::Error, Url, String),
|
||||
/// Failed to parse an activity received from another instance
|
||||
#[error("Failed to parse incoming activity with id {0}: {1}")]
|
||||
ParseReceivedActivity(Url, serde_json::Error),
|
||||
#[error("Failed to parse incoming activity {}: {0}", match .1 {
|
||||
Some(t) => format!("with id {t}"),
|
||||
None => String::new(),
|
||||
})]
|
||||
ParseReceivedActivity(serde_json::Error, Option<Url>),
|
||||
/// Reqwest Middleware Error
|
||||
#[error(transparent)]
|
||||
ReqwestMiddleware(#[from] reqwest_middleware::Error),
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
use crate::{
|
||||
config::Data,
|
||||
error::Error,
|
||||
error::{Error, Error::ParseFetchedObject},
|
||||
http_signatures::sign_request,
|
||||
reqwest_shim::ResponseExt,
|
||||
FEDERATION_CONTENT_TYPE,
|
||||
|
@ -93,8 +93,13 @@ async fn fetch_object_http_with_accept<T: Clone, Kind: DeserializeOwned>(
|
|||
}
|
||||
|
||||
let url = res.url().clone();
|
||||
Ok(FetchObjectResponse {
|
||||
object: res.json_limited().await?,
|
||||
url,
|
||||
})
|
||||
let text = res.bytes_limited().await?;
|
||||
match serde_json::from_slice(&text) {
|
||||
Ok(object) => Ok(FetchObjectResponse { object, url }),
|
||||
Err(e) => Err(ParseFetchedObject(
|
||||
e,
|
||||
url,
|
||||
String::from_utf8(Vec::from(text))?,
|
||||
)),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,10 +57,8 @@ where
|
|||
struct Id {
|
||||
id: Url,
|
||||
}
|
||||
match serde_json::from_slice::<Id>(body) {
|
||||
Ok(id) => Error::ParseReceivedActivity(id.id, e),
|
||||
Err(e) => Error::Json(e),
|
||||
}
|
||||
let id = serde_json::from_slice::<Id>(body).ok();
|
||||
Error::ParseReceivedActivity(e, id.map(|i| i.id))
|
||||
})?;
|
||||
data.config.verify_url_and_domain(&activity).await?;
|
||||
let actor = ObjectId::<ActorT>::from(activity.actor().clone())
|
||||
|
|
|
@ -3,10 +3,8 @@ use bytes::{BufMut, Bytes, BytesMut};
|
|||
use futures_core::{ready, stream::BoxStream, Stream};
|
||||
use pin_project_lite::pin_project;
|
||||
use reqwest::Response;
|
||||
use serde::de::DeserializeOwned;
|
||||
use std::{
|
||||
future::Future,
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
pin::Pin,
|
||||
task::{Context, Poll},
|
||||
|
@ -46,27 +44,6 @@ impl Future for BytesFuture {
|
|||
}
|
||||
}
|
||||
|
||||
pin_project! {
|
||||
pub struct JsonFuture<T> {
|
||||
_t: PhantomData<T>,
|
||||
#[pin]
|
||||
future: BytesFuture,
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Future for JsonFuture<T>
|
||||
where
|
||||
T: DeserializeOwned,
|
||||
{
|
||||
type Output = Result<T, Error>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
let this = self.project();
|
||||
let bytes = ready!(this.future.poll(cx))?;
|
||||
Poll::Ready(serde_json::from_slice(&bytes).map_err(Error::Json))
|
||||
}
|
||||
}
|
||||
|
||||
pin_project! {
|
||||
pub struct TextFuture {
|
||||
#[pin]
|
||||
|
@ -94,20 +71,16 @@ impl Future for TextFuture {
|
|||
/// TODO: Remove this shim as soon as reqwest gets support for size-limited bodies.
|
||||
pub trait ResponseExt {
|
||||
type BytesFuture;
|
||||
type JsonFuture<T>;
|
||||
type TextFuture;
|
||||
|
||||
/// Size limited version of `bytes` to work around a reqwest issue. Check [`ResponseExt`] docs for details.
|
||||
fn bytes_limited(self) -> Self::BytesFuture;
|
||||
/// Size limited version of `json` to work around a reqwest issue. Check [`ResponseExt`] docs for details.
|
||||
fn json_limited<T>(self) -> Self::JsonFuture<T>;
|
||||
/// Size limited version of `text` to work around a reqwest issue. Check [`ResponseExt`] docs for details.
|
||||
fn text_limited(self) -> Self::TextFuture;
|
||||
}
|
||||
|
||||
impl ResponseExt for Response {
|
||||
type BytesFuture = BytesFuture;
|
||||
type JsonFuture<T> = JsonFuture<T>;
|
||||
type TextFuture = TextFuture;
|
||||
|
||||
fn bytes_limited(self) -> Self::BytesFuture {
|
||||
|
@ -118,13 +91,6 @@ impl ResponseExt for Response {
|
|||
}
|
||||
}
|
||||
|
||||
fn json_limited<T>(self) -> Self::JsonFuture<T> {
|
||||
JsonFuture {
|
||||
_t: PhantomData,
|
||||
future: self.bytes_limited(),
|
||||
}
|
||||
}
|
||||
|
||||
fn text_limited(self) -> Self::TextFuture {
|
||||
TextFuture {
|
||||
future: self.bytes_limited(),
|
||||
|
|
Loading…
Reference in a new issue