apub_core/
activitypub_ext.rs

1//! Extensions to the ActivityPub traits
2
3use crate::{
4    activitypub::{Activity, Actor},
5    ingest::Ingest,
6    repo::{Dereference, Repo},
7    session::Session,
8};
9use std::{rc::Rc, sync::Arc};
10use url::Url;
11
12/// Simplification for <Blah as Dereference>::Output
13pub type Out<D> = <D as Dereference>::Output;
14
15/// An extension of Activity that is aware of it's Actor and Object types
16#[async_trait::async_trait(?Send)]
17pub trait ActivityExt: Activity {
18    /// The Actor ID type for dereferencing an Actor
19    type ActorId: Dereference + From<Url>;
20
21    /// The Object ID type for dereferencing an Object
22    type ObjectId: Dereference + From<Url>;
23
24    /// Attempt to pull the actor off the activity
25    fn actor(&self) -> Option<Out<Self::ActorId>>;
26
27    /// Attempt to pull the object off the activity
28    fn object(&self) -> Option<Out<Self::ObjectId>>;
29
30    /// Pull the actor off the activity, or fetch it from a repo if it isn't present
31    async fn dereference_actor<I: Ingest<Out<Self::ActorId>>, R: Repo, S: Session>(
32        &self,
33        actor_id: I::ActorId,
34        ingest: I,
35        remote_repo: R,
36        session: S,
37    ) -> Result<Option<Out<Self::ActorId>>, I::Error>
38    where
39        I::Error: From<R::Error>,
40        I::ActorId: From<Url> + 'static,
41    {
42        dereference::<Self::ActorId, I, R, S>(
43            actor_id,
44            ingest,
45            remote_repo,
46            session,
47            self.actor(),
48            self.actor_id(),
49        )
50        .await
51    }
52
53    /// Pull the object off the activity, or fetch it from a repo if it isn't present
54    async fn dereference_object<I: Ingest<Out<Self::ObjectId>>, R: Repo, S: Session>(
55        &self,
56        actor_id: I::ActorId,
57        ingest: I,
58        remote_repo: R,
59        session: S,
60    ) -> Result<Option<Out<Self::ObjectId>>, I::Error>
61    where
62        I::Error: From<R::Error>,
63        I::ActorId: From<Url> + 'static,
64    {
65        dereference::<Self::ObjectId, I, R, S>(
66            actor_id,
67            ingest,
68            remote_repo,
69            session,
70            self.object(),
71            self.object_id(),
72        )
73        .await
74    }
75}
76
77/// An extension of Actor that is aware of the PublicKey type
78#[async_trait::async_trait(?Send)]
79pub trait ActorExt: Actor {
80    /// The Public Key ID for dereferencing a Public key
81    type PublicKeyId: Dereference + From<Url>;
82
83    /// Attempt to pull the public key off the actor
84    fn public_key(&self) -> Option<Out<Self::PublicKeyId>>;
85
86    /// Pull the public key off the acctor, or fetch it from a repo if it isn't present
87    async fn dereference_public_key<I: Ingest<Out<Self::PublicKeyId>>, R: Repo, S: Session>(
88        &self,
89        actor_id: I::ActorId,
90        ingest: I,
91        remote_repo: R,
92        session: S,
93    ) -> Result<Option<Out<Self::PublicKeyId>>, I::Error>
94    where
95        I::Error: From<R::Error>,
96        I::ActorId: From<Url> + 'static,
97    {
98        dereference::<Self::PublicKeyId, I, R, S>(
99            actor_id,
100            ingest,
101            remote_repo,
102            session,
103            self.public_key(),
104            self.public_key_id(),
105        )
106        .await
107    }
108}
109
110/// implementation to dereference an object through Ingest if needed
111pub async fn dereference<D: Dereference + From<Url>, I: Ingest<Out<D>>, R: Repo, S: Session>(
112    actor_id: I::ActorId,
113    ingest: I,
114    remote_repo: R,
115    session: S,
116    output: Option<D::Output>,
117    id: &Url,
118) -> Result<Option<D::Output>, I::Error>
119where
120    I::ActorId: From<Url> + 'static,
121    I::Error: From<R::Error>,
122{
123    if let Some(item) = output {
124        return Ok(Some(item));
125    }
126
127    ingest
128        .fetch(D::from(id.clone()), actor_id, remote_repo, session)
129        .await
130}
131
132impl<'a, T> ActivityExt for &'a T
133where
134    T: ActivityExt,
135{
136    type ActorId = T::ActorId;
137    type ObjectId = T::ObjectId;
138
139    fn actor(&self) -> Option<<Self::ActorId as Dereference>::Output> {
140        T::actor(self)
141    }
142
143    fn object(&self) -> Option<<Self::ObjectId as Dereference>::Output> {
144        T::object(self)
145    }
146}
147
148impl<'a, T> ActivityExt for &'a mut T
149where
150    T: ActivityExt,
151{
152    type ActorId = T::ActorId;
153    type ObjectId = T::ObjectId;
154
155    fn actor(&self) -> Option<<Self::ActorId as Dereference>::Output> {
156        T::actor(self)
157    }
158
159    fn object(&self) -> Option<<Self::ObjectId as Dereference>::Output> {
160        T::object(self)
161    }
162}
163
164impl<T> ActivityExt for Box<T>
165where
166    T: ActivityExt,
167{
168    type ActorId = T::ActorId;
169    type ObjectId = T::ObjectId;
170
171    fn actor(&self) -> Option<<Self::ActorId as Dereference>::Output> {
172        T::actor(self)
173    }
174
175    fn object(&self) -> Option<<Self::ObjectId as Dereference>::Output> {
176        T::object(self)
177    }
178}
179
180impl<T> ActivityExt for Rc<T>
181where
182    T: ActivityExt,
183{
184    type ActorId = T::ActorId;
185    type ObjectId = T::ObjectId;
186
187    fn actor(&self) -> Option<<Self::ActorId as Dereference>::Output> {
188        T::actor(self)
189    }
190
191    fn object(&self) -> Option<<Self::ObjectId as Dereference>::Output> {
192        T::object(self)
193    }
194}
195
196impl<T> ActivityExt for Arc<T>
197where
198    T: ActivityExt,
199{
200    type ActorId = T::ActorId;
201    type ObjectId = T::ObjectId;
202
203    fn actor(&self) -> Option<<Self::ActorId as Dereference>::Output> {
204        T::actor(self)
205    }
206
207    fn object(&self) -> Option<<Self::ObjectId as Dereference>::Output> {
208        T::object(self)
209    }
210}