211 lines
7.2 KiB
Rust
211 lines
7.2 KiB
Rust
use crate::{Action, Context, Error, RecoverableError, Required};
|
|
use activitystreams::{base::AnyBase, prelude::*};
|
|
|
|
mod block;
|
|
mod follow;
|
|
mod like;
|
|
mod note;
|
|
mod person;
|
|
|
|
use block::{block, undo_block};
|
|
use follow::{accept_follow, follow, reject_follow, undo_accept_follow, undo_follow};
|
|
use like::{like, undo_like};
|
|
use note::{announce_note, create_note, delete_note, note, update_note};
|
|
use person::{create_person, delete_person, person, update_person};
|
|
|
|
pub(crate) fn ingest(
|
|
any_base: AnyBase,
|
|
context: &Context,
|
|
mut stack: Vec<AnyBase>,
|
|
) -> Result<(), Error> {
|
|
// Don't double-ingest
|
|
if context.apub.object(any_base.id().req()?)?.is_some() {
|
|
return Ok(());
|
|
}
|
|
|
|
match parse(any_base.clone(), context)? {
|
|
Ok(action) => {
|
|
action.perform(context)?;
|
|
if let Some(any_base) = stack.pop() {
|
|
context.spawner.process(any_base, stack);
|
|
}
|
|
}
|
|
Err(RecoverableError::MissingApub(url)) => {
|
|
stack.push(any_base);
|
|
context.spawner.download_apub(url, stack);
|
|
}
|
|
Err(RecoverableError::MissingImages(urls)) => {
|
|
stack.push(any_base);
|
|
context.spawner.download_images(urls, stack);
|
|
}
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
fn get_obj<T, Kind>(
|
|
any_base: AnyBase,
|
|
context: &Context,
|
|
f: impl FnOnce(T, &Context, AnyBase) -> Result<Result<Box<dyn Action>, RecoverableError>, Error>,
|
|
) -> Result<Result<Box<dyn Action>, RecoverableError>, Error>
|
|
where
|
|
T: ActorAndObjectRefExt + ExtendsExt<Kind>,
|
|
<T as activitystreams::base::Extends<Kind>>::Error: From<serde_json::Error>,
|
|
Error: From<<T as activitystreams::base::Extends<Kind>>::Error>,
|
|
for<'de> Kind: serde::Deserialize<'de>,
|
|
Kind: serde::Serialize,
|
|
{
|
|
wrap(any_base, context, |activity: T, context| {
|
|
let object = activity.object().as_one().req()?;
|
|
let any_base = if object.kind_str().is_none() {
|
|
let id = object.id().req()?;
|
|
match context.apub.object(id)? {
|
|
Some(any_base) => any_base,
|
|
None => return Ok(Err(RecoverableError::MissingApub(id.to_owned()))),
|
|
}
|
|
} else {
|
|
object.clone()
|
|
};
|
|
|
|
(f)(activity, context, any_base.clone())
|
|
})
|
|
}
|
|
|
|
fn wrap<T, Kind>(
|
|
any_base: AnyBase,
|
|
context: &Context,
|
|
f: impl FnOnce(T, &Context) -> Result<Result<Box<dyn Action>, RecoverableError>, Error>,
|
|
) -> Result<Result<Box<dyn Action>, RecoverableError>, Error>
|
|
where
|
|
T: ExtendsExt<Kind>,
|
|
<T as activitystreams::base::Extends<Kind>>::Error: From<serde_json::Error>,
|
|
Error: From<<T as activitystreams::base::Extends<Kind>>::Error>,
|
|
for<'de> Kind: serde::Deserialize<'de>,
|
|
Kind: serde::Serialize,
|
|
{
|
|
let activity: T = any_base.clone().extend()?.req()?;
|
|
|
|
let res = (f)(activity, context);
|
|
if res.as_ref().map(|r| r.is_ok()).unwrap_or(false) {
|
|
context.apub.store_object(&any_base)?;
|
|
}
|
|
res
|
|
}
|
|
|
|
fn parse(
|
|
any_base: AnyBase,
|
|
context: &Context,
|
|
) -> Result<Result<Box<dyn Action>, RecoverableError>, Error> {
|
|
match any_base.kind_str().req()? {
|
|
"Accept" => get_obj(
|
|
any_base,
|
|
context,
|
|
|accept, context, any_base| match any_base.kind_str().req()? {
|
|
"Follow" => wrap(any_base, context, |follow, context| {
|
|
accept_follow(&accept, &follow, context)
|
|
}),
|
|
_ => Err(Error::Invalid),
|
|
},
|
|
),
|
|
"Announce" => get_obj(
|
|
any_base,
|
|
context,
|
|
|announce, context, any_base| match any_base.kind_str().req()? {
|
|
"Note" => wrap(any_base, context, |note, context| {
|
|
announce_note(&announce, ¬e, context)
|
|
}),
|
|
_ => Err(Error::Invalid),
|
|
},
|
|
),
|
|
"Block" => wrap(any_base, context, |block_obj, context| {
|
|
block(&block_obj, context)
|
|
}),
|
|
"Create" => get_obj(
|
|
any_base,
|
|
context,
|
|
|create, context, any_base| match any_base.kind_str().req()? {
|
|
"Note" => wrap(any_base, context, |note, context| {
|
|
create_note(&create, ¬e, context)
|
|
}),
|
|
"Person" => wrap(any_base, context, |person, context| {
|
|
create_person(&create, &person, context)
|
|
}),
|
|
_ => Err(Error::Invalid),
|
|
},
|
|
),
|
|
"Delete" => get_obj(
|
|
any_base,
|
|
context,
|
|
|delete, context, any_base| match any_base.kind_str().req()? {
|
|
"Note" => wrap(any_base, context, |note, context| {
|
|
delete_note(&delete, ¬e, context)
|
|
}),
|
|
"Person" => wrap(any_base, context, |person, context| {
|
|
delete_person(&delete, &person, context)
|
|
}),
|
|
_ => Err(Error::Invalid),
|
|
},
|
|
),
|
|
"Follow" => wrap(any_base, context, |follow_obj, context| {
|
|
follow(&follow_obj, context)
|
|
}),
|
|
"Like" => wrap(any_base, context, |like_obj, context| {
|
|
like(&like_obj, context)
|
|
}),
|
|
"Note" => wrap(any_base, context, |note_obj, context| {
|
|
note(¬e_obj, context)
|
|
}),
|
|
"Person" => wrap(any_base, context, |person_obj, context| {
|
|
person(&person_obj, context)
|
|
}),
|
|
"Reject" => get_obj(
|
|
any_base,
|
|
context,
|
|
|reject, context, any_base| match any_base.kind_str().req()? {
|
|
"Follow" => wrap(any_base, context, |follow, context| {
|
|
reject_follow(&reject, &follow, context)
|
|
}),
|
|
_ => Err(Error::Invalid),
|
|
},
|
|
),
|
|
"Undo" => get_obj(any_base, context, |undo, context, any_base| match any_base
|
|
.kind_str()
|
|
.req()?
|
|
{
|
|
"Block" => wrap(any_base, context, |block, context| {
|
|
undo_block(&undo, &block, context)
|
|
}),
|
|
"Accept" => get_obj(
|
|
any_base,
|
|
context,
|
|
|accept, context, any_base| match any_base.kind_str().req()? {
|
|
"Follow" => wrap(any_base, context, |follow, context| {
|
|
undo_accept_follow(&undo, &accept, &follow, context)
|
|
}),
|
|
_ => Err(Error::Invalid),
|
|
},
|
|
),
|
|
"Follow" => wrap(any_base, context, |follow, context| {
|
|
undo_follow(&undo, &follow, context)
|
|
}),
|
|
"Like" => wrap(any_base, context, |like, context| {
|
|
undo_like(&undo, &like, context)
|
|
}),
|
|
_ => Err(Error::Invalid),
|
|
}),
|
|
"Update" => get_obj(
|
|
any_base,
|
|
context,
|
|
|update, context, any_base| match any_base.kind_str().req()? {
|
|
"Note" => wrap(any_base, context, |note, context| {
|
|
update_note(&update, ¬e, context)
|
|
}),
|
|
"Person" => wrap(any_base, context, |person, context| {
|
|
update_person(&update, &person, context)
|
|
}),
|
|
_ => Err(Error::Invalid),
|
|
},
|
|
),
|
|
_ => Err(Error::Invalid),
|
|
}
|
|
}
|