diff --git a/docs/08_receiving_activities.md b/docs/08_receiving_activities.md index 7e0cd03..5e1b750 100644 --- a/docs/08_receiving_activities.md +++ b/docs/08_receiving_activities.md @@ -1,6 +1,6 @@ ## Sending and receiving activities -Activitypub propagates actions across servers using `Activities`. For this each actor has an inbox and a public/private key pair. We already defined a `Person` actor with keypair. Whats left is to define an activity. This is similar to the way we defined `Person` and `Note` structs before. In this case we need to implement the [ActivityHandler](trait@crate::traits::ActivityHandler) trait. +Activitypub propagates actions across servers using `Activities`. For this each actor has an inbox and a public/private key pair. We already defined a `Person` actor with keypair. Whats left is to define an activity. This is similar to the way we defined `Person` and `Note` structs before. In this case we need to implement the [Activity](trait@crate::traits::Activity) trait. ``` # use serde::{Deserialize, Serialize}; @@ -10,7 +10,7 @@ Activitypub propagates actions across servers using `Activities`. For this each # use activitypub_federation::fetch::object_id::ObjectId; # use activitypub_federation::traits::tests::{DbConnection, DbUser}; # use activitystreams_kinds::activity::FollowType; -# use activitypub_federation::traits::ActivityHandler; +# use activitypub_federation::traits::Activity; # use activitypub_federation::config::Data; # async fn send_accept() -> Result<(), Error> { Ok(()) } @@ -25,7 +25,7 @@ pub struct Follow { } #[async_trait] -impl ActivityHandler for Follow { +impl Activity for Follow { type DataType = DbConnection; type Error = Error; @@ -59,14 +59,14 @@ Next its time to setup the actual HTTP handler for the inbox. For this we first # use activitypub_federation::axum::inbox::{ActivityData, receive_activity}; # use activitypub_federation::config::Data; # use activitypub_federation::protocol::context::WithContext; -# use activitypub_federation::traits::ActivityHandler; +# use activitypub_federation::traits::Activity; # use activitypub_federation::traits::tests::{DbConnection, DbUser, Follow}; # use serde::{Deserialize, Serialize}; # use url::Url; #[derive(Deserialize, Serialize, Debug)] #[serde(untagged)] -#[enum_delegate::implement(ActivityHandler)] +#[enum_delegate::implement(Activity)] pub enum PersonAcceptedActivities { Follow(Follow), } diff --git a/examples/live_federation/activities/create_post.rs b/examples/live_federation/activities/create_post.rs index 51ee5e5..0e7d559 100644 --- a/examples/live_federation/activities/create_post.rs +++ b/examples/live_federation/activities/create_post.rs @@ -11,7 +11,7 @@ use activitypub_federation::{ fetch::object_id::ObjectId, kinds::activity::CreateType, protocol::{context::WithContext, helpers::deserialize_one_or_many}, - traits::{ActivityHandler, Object}, + traits::{Activity, Object}, }; use serde::{Deserialize, Serialize}; use url::Url; @@ -50,7 +50,7 @@ impl CreatePost { } #[async_trait::async_trait] -impl ActivityHandler for CreatePost { +impl Activity for CreatePost { type DataType = DatabaseHandle; type Error = crate::error::Error; diff --git a/examples/live_federation/objects/person.rs b/examples/live_federation/objects/person.rs index 43005f4..44d0844 100644 --- a/examples/live_federation/objects/person.rs +++ b/examples/live_federation/objects/person.rs @@ -5,7 +5,7 @@ use activitypub_federation::{ http_signatures::generate_actor_keypair, kinds::actor::PersonType, protocol::{public_key::PublicKey, verification::verify_domains_match}, - traits::{ActivityHandler, Actor, Object}, + traits::{Activity, Actor, Object}, }; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; @@ -29,7 +29,7 @@ pub struct DbUser { /// List of all activities which this actor can receive. #[derive(Deserialize, Serialize, Debug)] #[serde(untagged)] -#[enum_delegate::implement(ActivityHandler)] +#[enum_delegate::implement(Activity)] pub enum PersonAcceptedActivities { CreateNote(CreatePost), } diff --git a/examples/local_federation/activities/accept.rs b/examples/local_federation/activities/accept.rs index c18945f..888c530 100644 --- a/examples/local_federation/activities/accept.rs +++ b/examples/local_federation/activities/accept.rs @@ -3,7 +3,7 @@ use activitypub_federation::{ config::Data, fetch::object_id::ObjectId, kinds::activity::AcceptType, - traits::ActivityHandler, + traits::Activity, }; use serde::{Deserialize, Serialize}; use url::Url; @@ -30,7 +30,7 @@ impl Accept { } #[async_trait::async_trait] -impl ActivityHandler for Accept { +impl Activity for Accept { type DataType = DatabaseHandle; type Error = crate::error::Error; diff --git a/examples/local_federation/activities/create_post.rs b/examples/local_federation/activities/create_post.rs index 6f85e2d..62ef005 100644 --- a/examples/local_federation/activities/create_post.rs +++ b/examples/local_federation/activities/create_post.rs @@ -8,7 +8,7 @@ use activitypub_federation::{ fetch::object_id::ObjectId, kinds::activity::CreateType, protocol::helpers::deserialize_one_or_many, - traits::{ActivityHandler, Object}, + traits::{Activity, Object}, }; use serde::{Deserialize, Serialize}; use url::Url; @@ -38,7 +38,7 @@ impl CreatePost { } #[async_trait::async_trait] -impl ActivityHandler for CreatePost { +impl Activity for CreatePost { type DataType = DatabaseHandle; type Error = crate::error::Error; diff --git a/examples/local_federation/activities/follow.rs b/examples/local_federation/activities/follow.rs index 02879d4..68bba5c 100644 --- a/examples/local_federation/activities/follow.rs +++ b/examples/local_federation/activities/follow.rs @@ -8,7 +8,7 @@ use activitypub_federation::{ config::Data, fetch::object_id::ObjectId, kinds::activity::FollowType, - traits::{ActivityHandler, Actor}, + traits::{Activity, Actor}, }; use serde::{Deserialize, Serialize}; use url::Url; @@ -35,7 +35,7 @@ impl Follow { } #[async_trait::async_trait] -impl ActivityHandler for Follow { +impl Activity for Follow { type DataType = DatabaseHandle; type Error = crate::error::Error; diff --git a/examples/local_federation/objects/person.rs b/examples/local_federation/objects/person.rs index 5497897..7dd6165 100644 --- a/examples/local_federation/objects/person.rs +++ b/examples/local_federation/objects/person.rs @@ -13,7 +13,7 @@ use activitypub_federation::{ http_signatures::generate_actor_keypair, kinds::actor::PersonType, protocol::{context::WithContext, public_key::PublicKey, verification::verify_domains_match}, - traits::{ActivityHandler, Actor, Object}, + traits::{Activity, Actor, Object}, }; use chrono::{DateTime, Utc}; use serde::{Deserialize, Serialize}; @@ -37,7 +37,7 @@ pub struct DbUser { /// List of all activities which this actor can receive. #[derive(Deserialize, Serialize, Debug)] #[serde(untagged)] -#[enum_delegate::implement(ActivityHandler)] +#[enum_delegate::implement(Activity)] pub enum PersonAcceptedActivities { Follow(Follow), Accept(Accept), @@ -103,16 +103,16 @@ impl DbUser { Ok(()) } - pub(crate) async fn send( + pub(crate) async fn send( &self, - activity: Activity, + activity: A, recipients: Vec, use_queue: bool, data: &Data, ) -> Result<(), Error> where - Activity: ActivityHandler + Serialize + Debug + Send + Sync, - ::Error: From + From, + A: Activity + Serialize + Debug + Send + Sync, + ::Error: From + From, { let activity = WithContext::new_default(activity); // Send through queue in some cases and bypass it in others to test both code paths diff --git a/src/activity_queue.rs b/src/activity_queue.rs index c666e7a..8f17d4f 100644 --- a/src/activity_queue.rs +++ b/src/activity_queue.rs @@ -6,7 +6,7 @@ use crate::{ activity_sending::{build_tasks, SendActivityTask}, config::Data, error::Error, - traits::{ActivityHandler, Actor}, + traits::{Activity, Actor}, }; use futures_core::Future; @@ -37,14 +37,14 @@ use url::Url; /// - `inboxes`: List of remote actor inboxes that should receive the activity. Ignores local actor /// inboxes. Should be built by calling [crate::traits::Actor::shared_inbox_or_inbox] /// for each target actor. -pub async fn queue_activity( - activity: &Activity, +pub async fn queue_activity( + activity: &A, actor: &ActorType, inboxes: Vec, data: &Data, ) -> Result<(), Error> where - Activity: ActivityHandler + Serialize + Debug, + A: Activity + Serialize + Debug, Datatype: Clone, ActorType: Actor, { diff --git a/src/activity_sending.rs b/src/activity_sending.rs index 7ee7ea0..b734088 100644 --- a/src/activity_sending.rs +++ b/src/activity_sending.rs @@ -7,7 +7,7 @@ use crate::{ error::Error, http_signatures::sign_request, reqwest_shim::ResponseExt, - traits::{ActivityHandler, Actor}, + traits::{Activity, Actor}, FEDERATION_CONTENT_TYPE, }; use bytes::Bytes; @@ -54,14 +54,14 @@ impl SendActivityTask { /// - `inboxes`: List of remote actor inboxes that should receive the activity. Ignores local actor /// inboxes. Should be built by calling [crate::traits::Actor::shared_inbox_or_inbox] /// for each target actor. - pub async fn prepare( - activity: &Activity, + pub async fn prepare( + activity: &A, actor: &ActorType, inboxes: Vec, data: &Data, ) -> Result, Error> where - Activity: ActivityHandler + Serialize + Debug, + A: Activity + Serialize + Debug, Datatype: Clone, ActorType: Actor, { @@ -136,14 +136,14 @@ impl SendActivityTask { } } -pub(crate) async fn build_tasks( - activity: &Activity, +pub(crate) async fn build_tasks( + activity: &A, actor: &ActorType, inboxes: Vec, data: &Data, ) -> Result, Error> where - Activity: ActivityHandler + Serialize + Debug, + A: Activity + Serialize + Debug, Datatype: Clone, ActorType: Actor, { diff --git a/src/actix_web/inbox.rs b/src/actix_web/inbox.rs index b441055..d14983c 100644 --- a/src/actix_web/inbox.rs +++ b/src/actix_web/inbox.rs @@ -6,7 +6,7 @@ use crate::{ error::Error, http_signatures::{verify_body_hash, verify_signature}, parse_received_activity, - traits::{ActivityHandler, Actor, Object}, + traits::{Activity, Actor, Object}, }; use actix_web::{web::Bytes, HttpRequest, HttpResponse}; use serde::de::DeserializeOwned; @@ -14,77 +14,77 @@ use tracing::debug; /// Handles incoming activities, verifying HTTP signatures and other checks /// -/// After successful validation, activities are passed to respective [trait@ActivityHandler]. -pub async fn receive_activity( +/// After successful validation, activities are passed to respective [trait@Activity]. +pub async fn receive_activity( request: HttpRequest, body: Bytes, data: &Data, -) -> Result::Error> +) -> Result::Error> where - Activity: ActivityHandler + DeserializeOwned + Send + 'static, + A: Activity + DeserializeOwned + Send + 'static, ActorT: Object + Actor + Send + 'static, for<'de2> ::Kind: serde::Deserialize<'de2>, - ::Error: From + From<::Error>, + ::Error: From + From<::Error>, ::Error: From, Datatype: Clone, { - let (activity, _) = do_stuff::(request, body, data).await?; + let (activity, _) = do_stuff::(request, body, data).await?; do_more_stuff(activity, data).await } /// Workaround required so we can use references for the hook, instead of cloning data. -pub trait ReceiveActivityHook +pub trait ReceiveActivityHook where - Activity: ActivityHandler + DeserializeOwned + Send + Clone + 'static, + A: Activity + DeserializeOwned + Send + Clone + 'static, ActorT: Object + Actor + Send + Clone + 'static, for<'de2> ::Kind: serde::Deserialize<'de2>, - ::Error: From + From<::Error>, + ::Error: From + From<::Error>, ::Error: From, Datatype: Clone, { /// Called when a new activity is recived fn hook( self, - activity: &Activity, + activity: &A, actor: &ActorT, data: &Data, - ) -> impl std::future::Future::Error>>; + ) -> impl std::future::Future::Error>>; } /// Same as [receive_activity], only that it calls the provided hook function before /// calling activity verify and receive functions. -pub async fn receive_activity_with_hook( +pub async fn receive_activity_with_hook( request: HttpRequest, body: Bytes, - hook: impl ReceiveActivityHook, + hook: impl ReceiveActivityHook, data: &Data, -) -> Result::Error> +) -> Result::Error> where - Activity: ActivityHandler + DeserializeOwned + Send + Clone + 'static, + A: Activity + DeserializeOwned + Send + Clone + 'static, ActorT: Object + Actor + Send + Clone + 'static, for<'de2> ::Kind: serde::Deserialize<'de2>, - ::Error: From + From<::Error>, + ::Error: From + From<::Error>, ::Error: From, Datatype: Clone, { - let (activity, actor) = do_stuff::(request, body, data).await?; + let (activity, actor) = do_stuff::(request, body, data).await?; hook.hook(&activity, &actor, data).await?; do_more_stuff(activity, data).await } -async fn do_stuff( +async fn do_stuff( request: HttpRequest, body: Bytes, data: &Data, -) -> Result<(Activity, ActorT), ::Error> +) -> Result<(A, ActorT), ::Error> where - Activity: ActivityHandler + DeserializeOwned + Send + 'static, + A: Activity + DeserializeOwned + Send + 'static, ActorT: Object + Actor + Send + 'static, for<'de2> ::Kind: serde::Deserialize<'de2>, - ::Error: From + From<::Error>, + ::Error: From + From<::Error>, ::Error: From, Datatype: Clone, { @@ -94,7 +94,7 @@ where .map(http_compat::header_value); verify_body_hash(digest_header.as_ref(), &body)?; - let (activity, actor) = parse_received_activity::(&body, data).await?; + let (activity, actor) = parse_received_activity::(&body, data).await?; let headers = http_compat::header_map(request.headers()); let method = http_compat::method(request.method()); @@ -104,12 +104,12 @@ where Ok((activity, actor)) } -async fn do_more_stuff( - activity: Activity, +async fn do_more_stuff( + activity: A, data: &Data, -) -> Result::Error> +) -> Result::Error> where - Activity: ActivityHandler + DeserializeOwned + Send + 'static, + A: Activity + DeserializeOwned + Send + 'static, Datatype: Clone, { debug!("Receiving activity {}", activity.id().to_string()); @@ -160,21 +160,21 @@ mod test { struct Dummy; - impl ReceiveActivityHook for Dummy + impl ReceiveActivityHook for Dummy where - Activity: ActivityHandler + DeserializeOwned + Send + Clone + 'static, + A: Activity + DeserializeOwned + Send + Clone + 'static, ActorT: Object + Actor + Send + Clone + 'static, for<'de2> ::Kind: serde::Deserialize<'de2>, - ::Error: From + From<::Error>, + ::Error: From + From<::Error>, ::Error: From, Datatype: Clone, { async fn hook( self, - _activity: &Activity, + _activity: &A, _actor: &ActorT, _data: &Data, - ) -> Result<(), ::Error> { + ) -> Result<(), ::Error> { // ensure that hook gets called by returning this value Err(Error::Other("test-error".to_string()).into()) } diff --git a/src/axum/inbox.rs b/src/axum/inbox.rs index dfa981c..5b49791 100644 --- a/src/axum/inbox.rs +++ b/src/axum/inbox.rs @@ -7,7 +7,7 @@ use crate::{ error::Error, http_signatures::verify_signature, parse_received_activity, - traits::{ActivityHandler, Actor, Object}, + traits::{Activity, Actor, Object}, }; use axum::{ body::Body, @@ -20,20 +20,20 @@ use serde::de::DeserializeOwned; use tracing::debug; /// Handles incoming activities, verifying HTTP signatures and other checks -pub async fn receive_activity( +pub async fn receive_activity( activity_data: ActivityData, data: &Data, -) -> Result<(), ::Error> +) -> Result<(), ::Error> where - Activity: ActivityHandler + DeserializeOwned + Send + 'static, + A: Activity + DeserializeOwned + Send + 'static, ActorT: Object + Actor + Send + 'static, for<'de2> ::Kind: serde::Deserialize<'de2>, - ::Error: From + From<::Error>, + ::Error: From + From<::Error>, ::Error: From, Datatype: Clone, { let (activity, actor) = - parse_received_activity::(&activity_data.body, data).await?; + parse_received_activity::(&activity_data.body, data).await?; verify_signature( &activity_data.headers, diff --git a/src/config.rs b/src/config.rs index bdb731f..9eb0b97 100644 --- a/src/config.rs +++ b/src/config.rs @@ -19,7 +19,7 @@ use crate::{ error::Error, http_signatures::sign_request, protocol::verification::verify_domains_match, - traits::{ActivityHandler, Actor}, + traits::{Activity, Actor}, }; use async_trait::async_trait; use bytes::Bytes; @@ -125,12 +125,9 @@ impl FederationConfig { FederationConfigBuilder::default() } - pub(crate) async fn verify_url_and_domain( - &self, - activity: &Activity, - ) -> Result<(), Error> + pub(crate) async fn verify_url_and_domain(&self, activity: &A) -> Result<(), Error> where - Activity: ActivityHandler + DeserializeOwned + Send + 'static, + A: Activity + DeserializeOwned + Send + 'static, { verify_domains_match(activity.id(), activity.actor())?; self.verify_url_valid(activity.id()).await?; diff --git a/src/lib.rs b/src/lib.rs index b7fe013..6dec179 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,7 +28,7 @@ use crate::{ config::Data, error::Error, fetch::object_id::ObjectId, - traits::{ActivityHandler, Actor, Object}, + traits::{Activity, Actor, Object}, }; pub use activitystreams_kinds as kinds; @@ -40,19 +40,19 @@ pub const FEDERATION_CONTENT_TYPE: &str = "application/activity+json"; /// Deserialize incoming inbox activity to the given type, perform basic /// validation and extract the actor. -async fn parse_received_activity( +async fn parse_received_activity( body: &[u8], data: &Data, -) -> Result<(Activity, ActorT), ::Error> +) -> Result<(A, ActorT), ::Error> where - Activity: ActivityHandler + DeserializeOwned + Send + 'static, + A: Activity + DeserializeOwned + Send + 'static, ActorT: Object + Actor + Send + 'static, for<'de2> ::Kind: serde::Deserialize<'de2>, - ::Error: From + From<::Error>, + ::Error: From + From<::Error>, ::Error: From, Datatype: Clone, { - let activity: Activity = serde_json::from_slice(body).map_err(|err| { + let activity: A = serde_json::from_slice(body).map_err(|err| { // Attempt to include activity id in error message let id = extract_id(body).ok(); Error::ParseReceivedActivity { err, id } diff --git a/src/protocol/context.rs b/src/protocol/context.rs index 027ff15..4934c10 100644 --- a/src/protocol/context.rs +++ b/src/protocol/context.rs @@ -19,7 +19,7 @@ //! Ok::<(), serde_json::error::Error>(()) //! ``` -use crate::{config::Data, traits::ActivityHandler}; +use crate::{config::Data, traits::Activity}; use serde::{Deserialize, Serialize}; use serde_json::Value; use url::Url; @@ -55,12 +55,12 @@ impl WithContext { } #[async_trait::async_trait] -impl ActivityHandler for WithContext +impl Activity for WithContext where - T: ActivityHandler + Send + Sync, + T: Activity + Send + Sync, { - type DataType = ::DataType; - type Error = ::Error; + type DataType = ::DataType; + type Error = ::Error; fn id(&self) -> &Url { self.inner.id() diff --git a/src/traits/mod.rs b/src/traits/mod.rs index 3bba24b..b255b48 100644 --- a/src/traits/mod.rs +++ b/src/traits/mod.rs @@ -210,7 +210,7 @@ pub trait Object: Sized + Debug { /// # use url::Url; /// # use activitypub_federation::fetch::object_id::ObjectId; /// # use activitypub_federation::config::Data; -/// # use activitypub_federation::traits::ActivityHandler; +/// # use activitypub_federation::traits::Activity; /// # use activitypub_federation::traits::tests::{DbConnection, DbUser}; /// #[derive(serde::Deserialize)] /// struct Follow { @@ -222,7 +222,7 @@ pub trait Object: Sized + Debug { /// } /// /// #[async_trait::async_trait] -/// impl ActivityHandler for Follow { +/// impl Activity for Follow { /// type DataType = DbConnection; /// type Error = anyhow::Error; /// @@ -248,7 +248,7 @@ pub trait Object: Sized + Debug { /// ``` #[async_trait] #[enum_delegate::register] -pub trait ActivityHandler { +pub trait Activity { /// App data type passed to handlers. Must be identical to /// [crate::config::FederationConfigBuilder::app_data] type. type DataType: Clone + Send + Sync; @@ -309,9 +309,9 @@ pub trait Actor: Object + Send + 'static { /// Allow for boxing of enum variants #[async_trait] -impl ActivityHandler for Box +impl Activity for Box where - T: ActivityHandler + Send + Sync, + T: Activity + Send + Sync, { type DataType = T::DataType; type Error = T::Error; diff --git a/src/traits/tests.rs b/src/traits/tests.rs index ec29a38..ae2ee84 100644 --- a/src/traits/tests.rs +++ b/src/traits/tests.rs @@ -4,7 +4,7 @@ //! //! TODO: Should be using `cfg[doctest]` but blocked by -use super::{async_trait, ActivityHandler, Actor, Data, Debug, Object, PublicKey, Url}; +use super::{async_trait, Activity, Actor, Data, Debug, Object, PublicKey, Url}; use crate::{ error::Error, fetch::object_id::ObjectId, @@ -144,7 +144,7 @@ pub struct Follow { } #[async_trait] -impl ActivityHandler for Follow { +impl Activity for Follow { type DataType = DbConnection; type Error = Error;