diff --git a/examples/federation/activities/follow.rs b/examples/federation/activities/follow.rs index 270dff3..da9f04c 100644 --- a/examples/federation/activities/follow.rs +++ b/examples/federation/activities/follow.rs @@ -4,7 +4,11 @@ use crate::{ instance::InstanceHandle, objects::person::MyUser, }; -use activitypub_federation::{core::object_id::ObjectId, data::Data, traits::ActivityHandler}; +use activitypub_federation::{ + core::object_id::ObjectId, + data::Data, + traits::{ActivityHandler, Actor}, +}; use activitystreams_kinds::activity::FollowType; use serde::{Deserialize, Serialize}; use url::Url; @@ -73,7 +77,11 @@ impl ActivityHandler for Follow { let id = generate_object_id(data.local_instance().hostname())?; let accept = Accept::new(local_user.ap_id.clone(), self, id.clone()); local_user - .send(accept, &[follower], data.local_instance()) + .send( + accept, + vec![follower.shared_inbox_or_inbox()], + data.local_instance(), + ) .await?; Ok(()) } diff --git a/examples/federation/objects/person.rs b/examples/federation/objects/person.rs index 55d1316..bca0b4b 100644 --- a/examples/federation/objects/person.rs +++ b/examples/federation/objects/person.rs @@ -84,35 +84,38 @@ impl MyUser { pub async fn follow(&self, other: &MyUser, instance: &InstanceHandle) -> Result<(), Error> { let id = generate_object_id(instance.local_instance().hostname())?; let follow = Follow::new(self.ap_id.clone(), other.ap_id.clone(), id.clone()); - self.send(follow, &[other.clone()], instance.local_instance()) - .await?; + self.send( + follow, + vec![other.shared_inbox_or_inbox()], + instance.local_instance(), + ) + .await?; Ok(()) } pub async fn post(&self, post: MyPost, instance: &InstanceHandle) -> Result<(), Error> { let id = generate_object_id(instance.local_instance().hostname())?; let create = CreateNote::new(post.into_apub(instance).await?, id.clone()); - let mut recipients = vec![]; + let mut inboxes = vec![]; for f in self.followers.clone() { let user: MyUser = ObjectId::new(f) .dereference(instance, instance.local_instance(), &mut 0) .await?; - recipients.push(user); + inboxes.push(user.shared_inbox_or_inbox()); } - self.send(create, &recipients, instance.local_instance()) + self.send(create, inboxes, instance.local_instance()) .await?; Ok(()) } - pub(crate) async fn send( + pub(crate) async fn send( &self, activity: Activity, - recipients: &[ActorT], + recipients: Vec, local_instance: &LocalInstance, ) -> Result<(), ::Error> where Activity: ActivityHandler + Serialize, - ActorT: Actor, ::Error: From + From, { let activity = WithContext::new_default(activity); diff --git a/src/core/activity_queue.rs b/src/core/activity_queue.rs index 3964158..565b705 100644 --- a/src/core/activity_queue.rs +++ b/src/core/activity_queue.rs @@ -1,6 +1,6 @@ use crate::{ core::signatures::{sign_request, PublicKey}, - traits::{ActivityHandler, Actor}, + traits::ActivityHandler, utils::verify_url_valid, Error, InstanceSettings, @@ -33,23 +33,21 @@ use url::Url; /// - `private_key`: The sending actor's private key for signing HTTP signature /// - `recipients`: List of actors who should receive the activity. This gets deduplicated, and /// local/invalid inbox urls removed -pub async fn send_activity( +pub async fn send_activity( activity: Activity, public_key: PublicKey, private_key: String, - recipients: &[ActorT], + recipients: Vec, instance: &LocalInstance, ) -> Result<(), ::Error> where Activity: ActivityHandler + Serialize, - ActorT: Actor, ::Error: From + From, { let activity_id = activity.id(); let activity_serialized = serde_json::to_string_pretty(&activity)?; let inboxes: Vec = recipients - .iter() - .map(|r| r.inbox()) + .into_iter() .unique() .filter(|i| !instance.is_local_url(i)) .filter(|i| verify_url_valid(i, &instance.settings).is_ok()) diff --git a/src/traits.rs b/src/traits.rs index 3b579bc..42cc00c 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -94,6 +94,15 @@ pub trait Actor: ApubObject { /// Returns the actor's public key for verification of HTTP signatures fn public_key(&self) -> &str; - /// The inbox or shared inbox where activities for this user should be sent to + /// The inbox where activities for this user should be sent to fn inbox(&self) -> Url; + + /// The actor's shared inbox, if any + fn shared_inbox(&self) -> Option { + None + } + + fn shared_inbox_or_inbox(&self) -> Url { + self.shared_inbox().unwrap_or_else(|| self.inbox()) + } }