apub-core 0.2.0

Utilities for building activitypub servers
Documentation
//! Extensions to the ActivityPub traits

use crate::{
    activitypub::{Activity, Actor},
    ingest::Ingest,
    repo::{Dereference, Repo},
    session::Session,
};
use std::{rc::Rc, sync::Arc};
use url::Url;

/// Simplification for <Blah as Dereference>::Output
pub type Out<D> = <D as Dereference>::Output;

/// An extension of Activity that is aware of it's Actor and Object types
#[async_trait::async_trait(?Send)]
pub trait ActivityExt: Activity {
    /// The Actor ID type for dereferencing an Actor
    type ActorId: Dereference + From<Url>;

    /// The Object ID type for dereferencing an Object
    type ObjectId: Dereference + From<Url>;

    /// Attempt to pull the actor off the activity
    fn actor(&self) -> Option<Out<Self::ActorId>>;

    /// Attempt to pull the object off the activity
    fn object(&self) -> Option<Out<Self::ObjectId>>;

    /// Pull the actor off the activity, or fetch it from a repo if it isn't present
    async fn dereference_actor<I: Ingest<Out<Self::ActorId>>, R: Repo, S: Session>(
        &self,
        actor_id: I::ActorId,
        ingest: I,
        remote_repo: R,
        session: S,
    ) -> Result<Option<Out<Self::ActorId>>, I::Error>
    where
        I::Error: From<R::Error>,
        I::ActorId: From<Url> + 'static,
    {
        dereference::<Self::ActorId, I, R, S>(
            actor_id,
            ingest,
            remote_repo,
            session,
            self.actor(),
            self.actor_id(),
        )
        .await
    }

    /// Pull the object off the activity, or fetch it from a repo if it isn't present
    async fn dereference_object<I: Ingest<Out<Self::ObjectId>>, R: Repo, S: Session>(
        &self,
        actor_id: I::ActorId,
        ingest: I,
        remote_repo: R,
        session: S,
    ) -> Result<Option<Out<Self::ObjectId>>, I::Error>
    where
        I::Error: From<R::Error>,
        I::ActorId: From<Url> + 'static,
    {
        dereference::<Self::ObjectId, I, R, S>(
            actor_id,
            ingest,
            remote_repo,
            session,
            self.object(),
            self.object_id(),
        )
        .await
    }
}

/// An extension of Actor that is aware of the PublicKey type
#[async_trait::async_trait(?Send)]
pub trait ActorExt: Actor {
    /// The Public Key ID for dereferencing a Public key
    type PublicKeyId: Dereference + From<Url>;

    /// Attempt to pull the public key off the actor
    fn public_key(&self) -> Option<Out<Self::PublicKeyId>>;

    /// Pull the public key off the acctor, or fetch it from a repo if it isn't present
    async fn dereference_public_key<I: Ingest<Out<Self::PublicKeyId>>, R: Repo, S: Session>(
        &self,
        actor_id: I::ActorId,
        ingest: I,
        remote_repo: R,
        session: S,
    ) -> Result<Option<Out<Self::PublicKeyId>>, I::Error>
    where
        I::Error: From<R::Error>,
        I::ActorId: From<Url> + 'static,
    {
        dereference::<Self::PublicKeyId, I, R, S>(
            actor_id,
            ingest,
            remote_repo,
            session,
            self.public_key(),
            self.public_key_id(),
        )
        .await
    }
}

/// implementation to dereference an object through Ingest if needed
pub async fn dereference<D: Dereference + From<Url>, I: Ingest<Out<D>>, R: Repo, S: Session>(
    actor_id: I::ActorId,
    ingest: I,
    remote_repo: R,
    session: S,
    output: Option<D::Output>,
    id: &Url,
) -> Result<Option<D::Output>, I::Error>
where
    I::ActorId: From<Url> + 'static,
    I::Error: From<R::Error>,
{
    if let Some(item) = output {
        return Ok(Some(item));
    }

    ingest
        .fetch(D::from(id.clone()), actor_id, remote_repo, session)
        .await
}

impl<'a, T> ActivityExt for &'a T
where
    T: ActivityExt,
{
    type ActorId = T::ActorId;
    type ObjectId = T::ObjectId;

    fn actor(&self) -> Option<<Self::ActorId as Dereference>::Output> {
        T::actor(self)
    }

    fn object(&self) -> Option<<Self::ObjectId as Dereference>::Output> {
        T::object(self)
    }
}

impl<'a, T> ActivityExt for &'a mut T
where
    T: ActivityExt,
{
    type ActorId = T::ActorId;
    type ObjectId = T::ObjectId;

    fn actor(&self) -> Option<<Self::ActorId as Dereference>::Output> {
        T::actor(self)
    }

    fn object(&self) -> Option<<Self::ObjectId as Dereference>::Output> {
        T::object(self)
    }
}

impl<T> ActivityExt for Box<T>
where
    T: ActivityExt,
{
    type ActorId = T::ActorId;
    type ObjectId = T::ObjectId;

    fn actor(&self) -> Option<<Self::ActorId as Dereference>::Output> {
        T::actor(self)
    }

    fn object(&self) -> Option<<Self::ObjectId as Dereference>::Output> {
        T::object(self)
    }
}

impl<T> ActivityExt for Rc<T>
where
    T: ActivityExt,
{
    type ActorId = T::ActorId;
    type ObjectId = T::ObjectId;

    fn actor(&self) -> Option<<Self::ActorId as Dereference>::Output> {
        T::actor(self)
    }

    fn object(&self) -> Option<<Self::ObjectId as Dereference>::Output> {
        T::object(self)
    }
}

impl<T> ActivityExt for Arc<T>
where
    T: ActivityExt,
{
    type ActorId = T::ActorId;
    type ObjectId = T::ObjectId;

    fn actor(&self) -> Option<<Self::ActorId as Dereference>::Output> {
        T::actor(self)
    }

    fn object(&self) -> Option<<Self::ObjectId as Dereference>::Output> {
        T::object(self)
    }
}