Rename ActivityHandler to Activity

This commit is contained in:
Felix Ableitner 2025-07-09 14:24:14 +02:00
parent ffdb202a72
commit f0e5149922
16 changed files with 91 additions and 94 deletions

View file

@ -1,6 +1,6 @@
## Sending and receiving activities ## 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}; # 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::fetch::object_id::ObjectId;
# use activitypub_federation::traits::tests::{DbConnection, DbUser}; # use activitypub_federation::traits::tests::{DbConnection, DbUser};
# use activitystreams_kinds::activity::FollowType; # use activitystreams_kinds::activity::FollowType;
# use activitypub_federation::traits::ActivityHandler; # use activitypub_federation::traits::Activity;
# use activitypub_federation::config::Data; # use activitypub_federation::config::Data;
# async fn send_accept() -> Result<(), Error> { Ok(()) } # async fn send_accept() -> Result<(), Error> { Ok(()) }
@ -25,7 +25,7 @@ pub struct Follow {
} }
#[async_trait] #[async_trait]
impl ActivityHandler for Follow { impl Activity for Follow {
type DataType = DbConnection; type DataType = DbConnection;
type Error = Error; 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::axum::inbox::{ActivityData, receive_activity};
# use activitypub_federation::config::Data; # use activitypub_federation::config::Data;
# use activitypub_federation::protocol::context::WithContext; # 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 activitypub_federation::traits::tests::{DbConnection, DbUser, Follow};
# use serde::{Deserialize, Serialize}; # use serde::{Deserialize, Serialize};
# use url::Url; # use url::Url;
#[derive(Deserialize, Serialize, Debug)] #[derive(Deserialize, Serialize, Debug)]
#[serde(untagged)] #[serde(untagged)]
#[enum_delegate::implement(ActivityHandler)] #[enum_delegate::implement(Activity)]
pub enum PersonAcceptedActivities { pub enum PersonAcceptedActivities {
Follow(Follow), Follow(Follow),
} }

View file

@ -11,7 +11,7 @@ use activitypub_federation::{
fetch::object_id::ObjectId, fetch::object_id::ObjectId,
kinds::activity::CreateType, kinds::activity::CreateType,
protocol::{context::WithContext, helpers::deserialize_one_or_many}, protocol::{context::WithContext, helpers::deserialize_one_or_many},
traits::{ActivityHandler, Object}, traits::{Activity, Object},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use url::Url; use url::Url;
@ -50,7 +50,7 @@ impl CreatePost {
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl ActivityHandler for CreatePost { impl Activity for CreatePost {
type DataType = DatabaseHandle; type DataType = DatabaseHandle;
type Error = crate::error::Error; type Error = crate::error::Error;

View file

@ -5,7 +5,7 @@ use activitypub_federation::{
http_signatures::generate_actor_keypair, http_signatures::generate_actor_keypair,
kinds::actor::PersonType, kinds::actor::PersonType,
protocol::{public_key::PublicKey, verification::verify_domains_match}, protocol::{public_key::PublicKey, verification::verify_domains_match},
traits::{ActivityHandler, Actor, Object}, traits::{Activity, Actor, Object},
}; };
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -29,7 +29,7 @@ pub struct DbUser {
/// List of all activities which this actor can receive. /// List of all activities which this actor can receive.
#[derive(Deserialize, Serialize, Debug)] #[derive(Deserialize, Serialize, Debug)]
#[serde(untagged)] #[serde(untagged)]
#[enum_delegate::implement(ActivityHandler)] #[enum_delegate::implement(Activity)]
pub enum PersonAcceptedActivities { pub enum PersonAcceptedActivities {
CreateNote(CreatePost), CreateNote(CreatePost),
} }

View file

@ -3,7 +3,7 @@ use activitypub_federation::{
config::Data, config::Data,
fetch::object_id::ObjectId, fetch::object_id::ObjectId,
kinds::activity::AcceptType, kinds::activity::AcceptType,
traits::ActivityHandler, traits::Activity,
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use url::Url; use url::Url;
@ -30,7 +30,7 @@ impl Accept {
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl ActivityHandler for Accept { impl Activity for Accept {
type DataType = DatabaseHandle; type DataType = DatabaseHandle;
type Error = crate::error::Error; type Error = crate::error::Error;

View file

@ -8,7 +8,7 @@ use activitypub_federation::{
fetch::object_id::ObjectId, fetch::object_id::ObjectId,
kinds::activity::CreateType, kinds::activity::CreateType,
protocol::helpers::deserialize_one_or_many, protocol::helpers::deserialize_one_or_many,
traits::{ActivityHandler, Object}, traits::{Activity, Object},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use url::Url; use url::Url;
@ -38,7 +38,7 @@ impl CreatePost {
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl ActivityHandler for CreatePost { impl Activity for CreatePost {
type DataType = DatabaseHandle; type DataType = DatabaseHandle;
type Error = crate::error::Error; type Error = crate::error::Error;

View file

@ -8,7 +8,7 @@ use activitypub_federation::{
config::Data, config::Data,
fetch::object_id::ObjectId, fetch::object_id::ObjectId,
kinds::activity::FollowType, kinds::activity::FollowType,
traits::{ActivityHandler, Actor}, traits::{Activity, Actor},
}; };
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use url::Url; use url::Url;
@ -35,7 +35,7 @@ impl Follow {
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl ActivityHandler for Follow { impl Activity for Follow {
type DataType = DatabaseHandle; type DataType = DatabaseHandle;
type Error = crate::error::Error; type Error = crate::error::Error;

View file

@ -13,7 +13,7 @@ use activitypub_federation::{
http_signatures::generate_actor_keypair, http_signatures::generate_actor_keypair,
kinds::actor::PersonType, kinds::actor::PersonType,
protocol::{context::WithContext, public_key::PublicKey, verification::verify_domains_match}, protocol::{context::WithContext, public_key::PublicKey, verification::verify_domains_match},
traits::{ActivityHandler, Actor, Object}, traits::{Activity, Actor, Object},
}; };
use chrono::{DateTime, Utc}; use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -37,7 +37,7 @@ pub struct DbUser {
/// List of all activities which this actor can receive. /// List of all activities which this actor can receive.
#[derive(Deserialize, Serialize, Debug)] #[derive(Deserialize, Serialize, Debug)]
#[serde(untagged)] #[serde(untagged)]
#[enum_delegate::implement(ActivityHandler)] #[enum_delegate::implement(Activity)]
pub enum PersonAcceptedActivities { pub enum PersonAcceptedActivities {
Follow(Follow), Follow(Follow),
Accept(Accept), Accept(Accept),
@ -103,16 +103,16 @@ impl DbUser {
Ok(()) Ok(())
} }
pub(crate) async fn send<Activity>( pub(crate) async fn send<A>(
&self, &self,
activity: Activity, activity: A,
recipients: Vec<Url>, recipients: Vec<Url>,
use_queue: bool, use_queue: bool,
data: &Data<DatabaseHandle>, data: &Data<DatabaseHandle>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
Activity: ActivityHandler + Serialize + Debug + Send + Sync, A: Activity + Serialize + Debug + Send + Sync,
<Activity as ActivityHandler>::Error: From<anyhow::Error> + From<serde_json::Error>, <A as Activity>::Error: From<anyhow::Error> + From<serde_json::Error>,
{ {
let activity = WithContext::new_default(activity); let activity = WithContext::new_default(activity);
// Send through queue in some cases and bypass it in others to test both code paths // Send through queue in some cases and bypass it in others to test both code paths

View file

@ -6,7 +6,7 @@ use crate::{
activity_sending::{build_tasks, SendActivityTask}, activity_sending::{build_tasks, SendActivityTask},
config::Data, config::Data,
error::Error, error::Error,
traits::{ActivityHandler, Actor}, traits::{Activity, Actor},
}; };
use futures_core::Future; 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`: 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] /// inboxes. Should be built by calling [crate::traits::Actor::shared_inbox_or_inbox]
/// for each target actor. /// for each target actor.
pub async fn queue_activity<Activity, Datatype, ActorType>( pub async fn queue_activity<A, Datatype, ActorType>(
activity: &Activity, activity: &A,
actor: &ActorType, actor: &ActorType,
inboxes: Vec<Url>, inboxes: Vec<Url>,
data: &Data<Datatype>, data: &Data<Datatype>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
Activity: ActivityHandler + Serialize + Debug, A: Activity + Serialize + Debug,
Datatype: Clone, Datatype: Clone,
ActorType: Actor, ActorType: Actor,
{ {

View file

@ -7,7 +7,7 @@ use crate::{
error::Error, error::Error,
http_signatures::sign_request, http_signatures::sign_request,
reqwest_shim::ResponseExt, reqwest_shim::ResponseExt,
traits::{ActivityHandler, Actor}, traits::{Activity, Actor},
FEDERATION_CONTENT_TYPE, FEDERATION_CONTENT_TYPE,
}; };
use bytes::Bytes; use bytes::Bytes;
@ -54,14 +54,14 @@ impl SendActivityTask {
/// - `inboxes`: List of remote actor inboxes that should receive the activity. Ignores local actor /// - `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] /// inboxes. Should be built by calling [crate::traits::Actor::shared_inbox_or_inbox]
/// for each target actor. /// for each target actor.
pub async fn prepare<Activity, Datatype, ActorType>( pub async fn prepare<A, Datatype, ActorType>(
activity: &Activity, activity: &A,
actor: &ActorType, actor: &ActorType,
inboxes: Vec<Url>, inboxes: Vec<Url>,
data: &Data<Datatype>, data: &Data<Datatype>,
) -> Result<Vec<SendActivityTask>, Error> ) -> Result<Vec<SendActivityTask>, Error>
where where
Activity: ActivityHandler + Serialize + Debug, A: Activity + Serialize + Debug,
Datatype: Clone, Datatype: Clone,
ActorType: Actor, ActorType: Actor,
{ {
@ -136,14 +136,14 @@ impl SendActivityTask {
} }
} }
pub(crate) async fn build_tasks<Activity, Datatype, ActorType>( pub(crate) async fn build_tasks<A, Datatype, ActorType>(
activity: &Activity, activity: &A,
actor: &ActorType, actor: &ActorType,
inboxes: Vec<Url>, inboxes: Vec<Url>,
data: &Data<Datatype>, data: &Data<Datatype>,
) -> Result<Vec<SendActivityTask>, Error> ) -> Result<Vec<SendActivityTask>, Error>
where where
Activity: ActivityHandler + Serialize + Debug, A: Activity + Serialize + Debug,
Datatype: Clone, Datatype: Clone,
ActorType: Actor, ActorType: Actor,
{ {

View file

@ -6,7 +6,7 @@ use crate::{
error::Error, error::Error,
http_signatures::{verify_body_hash, verify_signature}, http_signatures::{verify_body_hash, verify_signature},
parse_received_activity, parse_received_activity,
traits::{ActivityHandler, Actor, Object}, traits::{Activity, Actor, Object},
}; };
use actix_web::{web::Bytes, HttpRequest, HttpResponse}; use actix_web::{web::Bytes, HttpRequest, HttpResponse};
use serde::de::DeserializeOwned; use serde::de::DeserializeOwned;
@ -14,77 +14,77 @@ use tracing::debug;
/// Handles incoming activities, verifying HTTP signatures and other checks /// Handles incoming activities, verifying HTTP signatures and other checks
/// ///
/// After successful validation, activities are passed to respective [trait@ActivityHandler]. /// After successful validation, activities are passed to respective [trait@Activity].
pub async fn receive_activity<Activity, ActorT, Datatype>( pub async fn receive_activity<A, ActorT, Datatype>(
request: HttpRequest, request: HttpRequest,
body: Bytes, body: Bytes,
data: &Data<Datatype>, data: &Data<Datatype>,
) -> Result<HttpResponse, <Activity as ActivityHandler>::Error> ) -> Result<HttpResponse, <A as Activity>::Error>
where where
Activity: ActivityHandler<DataType = Datatype> + DeserializeOwned + Send + 'static, A: Activity<DataType = Datatype> + DeserializeOwned + Send + 'static,
ActorT: Object<DataType = Datatype> + Actor + Send + 'static, ActorT: Object<DataType = Datatype> + Actor + Send + 'static,
for<'de2> <ActorT as Object>::Kind: serde::Deserialize<'de2>, for<'de2> <ActorT as Object>::Kind: serde::Deserialize<'de2>,
<Activity as ActivityHandler>::Error: From<Error> + From<<ActorT as Object>::Error>, <A as Activity>::Error: From<Error> + From<<ActorT as Object>::Error>,
<ActorT as Object>::Error: From<Error>, <ActorT as Object>::Error: From<Error>,
Datatype: Clone, Datatype: Clone,
{ {
let (activity, _) = do_stuff::<Activity, ActorT, Datatype>(request, body, data).await?; let (activity, _) = do_stuff::<A, ActorT, Datatype>(request, body, data).await?;
do_more_stuff(activity, data).await do_more_stuff(activity, data).await
} }
/// Workaround required so we can use references for the hook, instead of cloning data. /// Workaround required so we can use references for the hook, instead of cloning data.
pub trait ReceiveActivityHook<Activity, ActorT, Datatype> pub trait ReceiveActivityHook<A, ActorT, Datatype>
where where
Activity: ActivityHandler<DataType = Datatype> + DeserializeOwned + Send + Clone + 'static, A: Activity<DataType = Datatype> + DeserializeOwned + Send + Clone + 'static,
ActorT: Object<DataType = Datatype> + Actor + Send + Clone + 'static, ActorT: Object<DataType = Datatype> + Actor + Send + Clone + 'static,
for<'de2> <ActorT as Object>::Kind: serde::Deserialize<'de2>, for<'de2> <ActorT as Object>::Kind: serde::Deserialize<'de2>,
<Activity as ActivityHandler>::Error: From<Error> + From<<ActorT as Object>::Error>, <A as Activity>::Error: From<Error> + From<<ActorT as Object>::Error>,
<ActorT as Object>::Error: From<Error>, <ActorT as Object>::Error: From<Error>,
Datatype: Clone, Datatype: Clone,
{ {
/// Called when a new activity is recived /// Called when a new activity is recived
fn hook( fn hook(
self, self,
activity: &Activity, activity: &A,
actor: &ActorT, actor: &ActorT,
data: &Data<Datatype>, data: &Data<Datatype>,
) -> impl std::future::Future<Output = Result<(), <Activity as ActivityHandler>::Error>>; ) -> impl std::future::Future<Output = Result<(), <A as Activity>::Error>>;
} }
/// Same as [receive_activity], only that it calls the provided hook function before /// Same as [receive_activity], only that it calls the provided hook function before
/// calling activity verify and receive functions. /// calling activity verify and receive functions.
pub async fn receive_activity_with_hook<Activity, ActorT, Datatype>( pub async fn receive_activity_with_hook<A, ActorT, Datatype>(
request: HttpRequest, request: HttpRequest,
body: Bytes, body: Bytes,
hook: impl ReceiveActivityHook<Activity, ActorT, Datatype>, hook: impl ReceiveActivityHook<A, ActorT, Datatype>,
data: &Data<Datatype>, data: &Data<Datatype>,
) -> Result<HttpResponse, <Activity as ActivityHandler>::Error> ) -> Result<HttpResponse, <A as Activity>::Error>
where where
Activity: ActivityHandler<DataType = Datatype> + DeserializeOwned + Send + Clone + 'static, A: Activity<DataType = Datatype> + DeserializeOwned + Send + Clone + 'static,
ActorT: Object<DataType = Datatype> + Actor + Send + Clone + 'static, ActorT: Object<DataType = Datatype> + Actor + Send + Clone + 'static,
for<'de2> <ActorT as Object>::Kind: serde::Deserialize<'de2>, for<'de2> <ActorT as Object>::Kind: serde::Deserialize<'de2>,
<Activity as ActivityHandler>::Error: From<Error> + From<<ActorT as Object>::Error>, <A as Activity>::Error: From<Error> + From<<ActorT as Object>::Error>,
<ActorT as Object>::Error: From<Error>, <ActorT as Object>::Error: From<Error>,
Datatype: Clone, Datatype: Clone,
{ {
let (activity, actor) = do_stuff::<Activity, ActorT, Datatype>(request, body, data).await?; let (activity, actor) = do_stuff::<A, ActorT, Datatype>(request, body, data).await?;
hook.hook(&activity, &actor, data).await?; hook.hook(&activity, &actor, data).await?;
do_more_stuff(activity, data).await do_more_stuff(activity, data).await
} }
async fn do_stuff<Activity, ActorT, Datatype>( async fn do_stuff<A, ActorT, Datatype>(
request: HttpRequest, request: HttpRequest,
body: Bytes, body: Bytes,
data: &Data<Datatype>, data: &Data<Datatype>,
) -> Result<(Activity, ActorT), <Activity as ActivityHandler>::Error> ) -> Result<(A, ActorT), <A as Activity>::Error>
where where
Activity: ActivityHandler<DataType = Datatype> + DeserializeOwned + Send + 'static, A: Activity<DataType = Datatype> + DeserializeOwned + Send + 'static,
ActorT: Object<DataType = Datatype> + Actor + Send + 'static, ActorT: Object<DataType = Datatype> + Actor + Send + 'static,
for<'de2> <ActorT as Object>::Kind: serde::Deserialize<'de2>, for<'de2> <ActorT as Object>::Kind: serde::Deserialize<'de2>,
<Activity as ActivityHandler>::Error: From<Error> + From<<ActorT as Object>::Error>, <A as Activity>::Error: From<Error> + From<<ActorT as Object>::Error>,
<ActorT as Object>::Error: From<Error>, <ActorT as Object>::Error: From<Error>,
Datatype: Clone, Datatype: Clone,
{ {
@ -94,7 +94,7 @@ where
.map(http_compat::header_value); .map(http_compat::header_value);
verify_body_hash(digest_header.as_ref(), &body)?; verify_body_hash(digest_header.as_ref(), &body)?;
let (activity, actor) = parse_received_activity::<Activity, ActorT, _>(&body, data).await?; let (activity, actor) = parse_received_activity::<A, ActorT, _>(&body, data).await?;
let headers = http_compat::header_map(request.headers()); let headers = http_compat::header_map(request.headers());
let method = http_compat::method(request.method()); let method = http_compat::method(request.method());
@ -104,12 +104,12 @@ where
Ok((activity, actor)) Ok((activity, actor))
} }
async fn do_more_stuff<Activity, Datatype>( async fn do_more_stuff<A, Datatype>(
activity: Activity, activity: A,
data: &Data<Datatype>, data: &Data<Datatype>,
) -> Result<HttpResponse, <Activity as ActivityHandler>::Error> ) -> Result<HttpResponse, <A as Activity>::Error>
where where
Activity: ActivityHandler<DataType = Datatype> + DeserializeOwned + Send + 'static, A: Activity<DataType = Datatype> + DeserializeOwned + Send + 'static,
Datatype: Clone, Datatype: Clone,
{ {
debug!("Receiving activity {}", activity.id().to_string()); debug!("Receiving activity {}", activity.id().to_string());
@ -160,21 +160,21 @@ mod test {
struct Dummy; struct Dummy;
impl<Activity, ActorT, Datatype> ReceiveActivityHook<Activity, ActorT, Datatype> for Dummy impl<A, ActorT, Datatype> ReceiveActivityHook<A, ActorT, Datatype> for Dummy
where where
Activity: ActivityHandler<DataType = Datatype> + DeserializeOwned + Send + Clone + 'static, A: Activity<DataType = Datatype> + DeserializeOwned + Send + Clone + 'static,
ActorT: Object<DataType = Datatype> + Actor + Send + Clone + 'static, ActorT: Object<DataType = Datatype> + Actor + Send + Clone + 'static,
for<'de2> <ActorT as Object>::Kind: serde::Deserialize<'de2>, for<'de2> <ActorT as Object>::Kind: serde::Deserialize<'de2>,
<Activity as ActivityHandler>::Error: From<Error> + From<<ActorT as Object>::Error>, <A as Activity>::Error: From<Error> + From<<ActorT as Object>::Error>,
<ActorT as Object>::Error: From<Error>, <ActorT as Object>::Error: From<Error>,
Datatype: Clone, Datatype: Clone,
{ {
async fn hook( async fn hook(
self, self,
_activity: &Activity, _activity: &A,
_actor: &ActorT, _actor: &ActorT,
_data: &Data<Datatype>, _data: &Data<Datatype>,
) -> Result<(), <Activity as ActivityHandler>::Error> { ) -> Result<(), <A as Activity>::Error> {
// ensure that hook gets called by returning this value // ensure that hook gets called by returning this value
Err(Error::Other("test-error".to_string()).into()) Err(Error::Other("test-error".to_string()).into())
} }

View file

@ -7,7 +7,7 @@ use crate::{
error::Error, error::Error,
http_signatures::verify_signature, http_signatures::verify_signature,
parse_received_activity, parse_received_activity,
traits::{ActivityHandler, Actor, Object}, traits::{Activity, Actor, Object},
}; };
use axum::{ use axum::{
body::Body, body::Body,
@ -20,20 +20,20 @@ use serde::de::DeserializeOwned;
use tracing::debug; use tracing::debug;
/// Handles incoming activities, verifying HTTP signatures and other checks /// Handles incoming activities, verifying HTTP signatures and other checks
pub async fn receive_activity<Activity, ActorT, Datatype>( pub async fn receive_activity<A, ActorT, Datatype>(
activity_data: ActivityData, activity_data: ActivityData,
data: &Data<Datatype>, data: &Data<Datatype>,
) -> Result<(), <Activity as ActivityHandler>::Error> ) -> Result<(), <A as Activity>::Error>
where where
Activity: ActivityHandler<DataType = Datatype> + DeserializeOwned + Send + 'static, A: Activity<DataType = Datatype> + DeserializeOwned + Send + 'static,
ActorT: Object<DataType = Datatype> + Actor + Send + 'static, ActorT: Object<DataType = Datatype> + Actor + Send + 'static,
for<'de2> <ActorT as Object>::Kind: serde::Deserialize<'de2>, for<'de2> <ActorT as Object>::Kind: serde::Deserialize<'de2>,
<Activity as ActivityHandler>::Error: From<Error> + From<<ActorT as Object>::Error>, <A as Activity>::Error: From<Error> + From<<ActorT as Object>::Error>,
<ActorT as Object>::Error: From<Error>, <ActorT as Object>::Error: From<Error>,
Datatype: Clone, Datatype: Clone,
{ {
let (activity, actor) = let (activity, actor) =
parse_received_activity::<Activity, ActorT, _>(&activity_data.body, data).await?; parse_received_activity::<A, ActorT, _>(&activity_data.body, data).await?;
verify_signature( verify_signature(
&activity_data.headers, &activity_data.headers,

View file

@ -19,7 +19,7 @@ use crate::{
error::Error, error::Error,
http_signatures::sign_request, http_signatures::sign_request,
protocol::verification::verify_domains_match, protocol::verification::verify_domains_match,
traits::{ActivityHandler, Actor}, traits::{Activity, Actor},
}; };
use async_trait::async_trait; use async_trait::async_trait;
use bytes::Bytes; use bytes::Bytes;
@ -125,12 +125,9 @@ impl<T: Clone> FederationConfig<T> {
FederationConfigBuilder::default() FederationConfigBuilder::default()
} }
pub(crate) async fn verify_url_and_domain<Activity, Datatype>( pub(crate) async fn verify_url_and_domain<A, Datatype>(&self, activity: &A) -> Result<(), Error>
&self,
activity: &Activity,
) -> Result<(), Error>
where where
Activity: ActivityHandler<DataType = Datatype> + DeserializeOwned + Send + 'static, A: Activity<DataType = Datatype> + DeserializeOwned + Send + 'static,
{ {
verify_domains_match(activity.id(), activity.actor())?; verify_domains_match(activity.id(), activity.actor())?;
self.verify_url_valid(activity.id()).await?; self.verify_url_valid(activity.id()).await?;

View file

@ -28,7 +28,7 @@ use crate::{
config::Data, config::Data,
error::Error, error::Error,
fetch::object_id::ObjectId, fetch::object_id::ObjectId,
traits::{ActivityHandler, Actor, Object}, traits::{Activity, Actor, Object},
}; };
pub use activitystreams_kinds as kinds; 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 /// Deserialize incoming inbox activity to the given type, perform basic
/// validation and extract the actor. /// validation and extract the actor.
async fn parse_received_activity<Activity, ActorT, Datatype>( async fn parse_received_activity<A, ActorT, Datatype>(
body: &[u8], body: &[u8],
data: &Data<Datatype>, data: &Data<Datatype>,
) -> Result<(Activity, ActorT), <Activity as ActivityHandler>::Error> ) -> Result<(A, ActorT), <A as Activity>::Error>
where where
Activity: ActivityHandler<DataType = Datatype> + DeserializeOwned + Send + 'static, A: Activity<DataType = Datatype> + DeserializeOwned + Send + 'static,
ActorT: Object<DataType = Datatype> + Actor + Send + 'static, ActorT: Object<DataType = Datatype> + Actor + Send + 'static,
for<'de2> <ActorT as Object>::Kind: serde::Deserialize<'de2>, for<'de2> <ActorT as Object>::Kind: serde::Deserialize<'de2>,
<Activity as ActivityHandler>::Error: From<Error> + From<<ActorT as Object>::Error>, <A as Activity>::Error: From<Error> + From<<ActorT as Object>::Error>,
<ActorT as Object>::Error: From<Error>, <ActorT as Object>::Error: From<Error>,
Datatype: Clone, 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 // Attempt to include activity id in error message
let id = extract_id(body).ok(); let id = extract_id(body).ok();
Error::ParseReceivedActivity { err, id } Error::ParseReceivedActivity { err, id }

View file

@ -19,7 +19,7 @@
//! Ok::<(), serde_json::error::Error>(()) //! Ok::<(), serde_json::error::Error>(())
//! ``` //! ```
use crate::{config::Data, traits::ActivityHandler}; use crate::{config::Data, traits::Activity};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serde_json::Value; use serde_json::Value;
use url::Url; use url::Url;
@ -55,12 +55,12 @@ impl<T> WithContext<T> {
} }
#[async_trait::async_trait] #[async_trait::async_trait]
impl<T> ActivityHandler for WithContext<T> impl<T> Activity for WithContext<T>
where where
T: ActivityHandler + Send + Sync, T: Activity + Send + Sync,
{ {
type DataType = <T as ActivityHandler>::DataType; type DataType = <T as Activity>::DataType;
type Error = <T as ActivityHandler>::Error; type Error = <T as Activity>::Error;
fn id(&self) -> &Url { fn id(&self) -> &Url {
self.inner.id() self.inner.id()

View file

@ -210,7 +210,7 @@ pub trait Object: Sized + Debug {
/// # use url::Url; /// # use url::Url;
/// # use activitypub_federation::fetch::object_id::ObjectId; /// # use activitypub_federation::fetch::object_id::ObjectId;
/// # use activitypub_federation::config::Data; /// # use activitypub_federation::config::Data;
/// # use activitypub_federation::traits::ActivityHandler; /// # use activitypub_federation::traits::Activity;
/// # use activitypub_federation::traits::tests::{DbConnection, DbUser}; /// # use activitypub_federation::traits::tests::{DbConnection, DbUser};
/// #[derive(serde::Deserialize)] /// #[derive(serde::Deserialize)]
/// struct Follow { /// struct Follow {
@ -222,7 +222,7 @@ pub trait Object: Sized + Debug {
/// } /// }
/// ///
/// #[async_trait::async_trait] /// #[async_trait::async_trait]
/// impl ActivityHandler for Follow { /// impl Activity for Follow {
/// type DataType = DbConnection; /// type DataType = DbConnection;
/// type Error = anyhow::Error; /// type Error = anyhow::Error;
/// ///
@ -248,7 +248,7 @@ pub trait Object: Sized + Debug {
/// ``` /// ```
#[async_trait] #[async_trait]
#[enum_delegate::register] #[enum_delegate::register]
pub trait ActivityHandler { pub trait Activity {
/// App data type passed to handlers. Must be identical to /// App data type passed to handlers. Must be identical to
/// [crate::config::FederationConfigBuilder::app_data] type. /// [crate::config::FederationConfigBuilder::app_data] type.
type DataType: Clone + Send + Sync; type DataType: Clone + Send + Sync;
@ -309,9 +309,9 @@ pub trait Actor: Object + Send + 'static {
/// Allow for boxing of enum variants /// Allow for boxing of enum variants
#[async_trait] #[async_trait]
impl<T> ActivityHandler for Box<T> impl<T> Activity for Box<T>
where where
T: ActivityHandler + Send + Sync, T: Activity + Send + Sync,
{ {
type DataType = T::DataType; type DataType = T::DataType;
type Error = T::Error; type Error = T::Error;

View file

@ -4,7 +4,7 @@
//! //!
//! TODO: Should be using `cfg[doctest]` but blocked by <https://github.com/rust-lang/rust/issues/67295> //! TODO: Should be using `cfg[doctest]` but blocked by <https://github.com/rust-lang/rust/issues/67295>
use super::{async_trait, ActivityHandler, Actor, Data, Debug, Object, PublicKey, Url}; use super::{async_trait, Activity, Actor, Data, Debug, Object, PublicKey, Url};
use crate::{ use crate::{
error::Error, error::Error,
fetch::object_id::ObjectId, fetch::object_id::ObjectId,
@ -144,7 +144,7 @@ pub struct Follow {
} }
#[async_trait] #[async_trait]
impl ActivityHandler for Follow { impl Activity for Follow {
type DataType = DbConnection; type DataType = DbConnection;
type Error = Error; type Error = Error;