use crate::{config::Data, protocol::public_key::PublicKey};
use async_trait::async_trait;
use chrono::{DateTime, Utc};
use serde::Deserialize;
use std::{fmt::Debug, ops::Deref};
use url::Url;
pub mod either;
pub mod tests;
#[async_trait]
pub trait Object: Sized + Debug {
type DataType: Clone + Send + Sync;
type Kind;
type Error;
fn id(&self) -> &Url;
fn last_refreshed_at(&self) -> Option<DateTime<Utc>> {
None
}
async fn read_from_id(
object_id: Url,
data: &Data<Self::DataType>,
) -> Result<Option<Self>, Self::Error>;
async fn delete(&self, _data: &Data<Self::DataType>) -> Result<(), Self::Error> {
Ok(())
}
fn is_deleted(&self) -> bool {
false
}
async fn into_json(self, data: &Data<Self::DataType>) -> Result<Self::Kind, Self::Error>;
async fn verify(
json: &Self::Kind,
expected_domain: &Url,
data: &Data<Self::DataType>,
) -> Result<(), Self::Error>;
async fn from_json(json: Self::Kind, data: &Data<Self::DataType>) -> Result<Self, Self::Error>;
#[cfg(feature = "actix-web")]
async fn http_response(
self,
federation_context: &serde_json::Value,
data: &Data<Self::DataType>,
) -> Result<actix_web::HttpResponse, Self::Error>
where
Self::Error: From<serde_json::Error>,
Self::Kind: serde::Serialize + Send,
{
use crate::actix_web::response::{
create_http_response,
create_tombstone_response,
redirect_remote_object,
};
let id = self.id();
let res = if !data.config.is_local_url(id) {
redirect_remote_object(id)
} else if !self.is_deleted() {
let json = self.into_json(data).await?;
create_http_response(json, federation_context)?
} else {
create_tombstone_response(id.clone(), federation_context)?
};
Ok(res)
}
}
#[async_trait]
#[enum_delegate::register]
pub trait Activity {
type DataType: Clone + Send + Sync;
type Error;
fn id(&self) -> &Url;
fn actor(&self) -> &Url;
async fn verify(&self, data: &Data<Self::DataType>) -> Result<(), Self::Error>;
async fn receive(self, data: &Data<Self::DataType>) -> Result<(), Self::Error>;
}
pub trait Actor: Object + Send + 'static {
fn public_key_pem(&self) -> &str;
fn private_key_pem(&self) -> Option<String>;
fn inbox(&self) -> Url;
fn public_key(&self) -> PublicKey {
PublicKey::new(self.id().clone(), self.public_key_pem().to_string())
}
fn shared_inbox(&self) -> Option<Url> {
None
}
fn shared_inbox_or_inbox(&self) -> Url {
self.shared_inbox().unwrap_or_else(|| self.inbox())
}
}
#[async_trait]
impl<T> Activity for Box<T>
where
T: Activity + Send + Sync,
{
type DataType = T::DataType;
type Error = T::Error;
fn id(&self) -> &Url {
self.deref().id()
}
fn actor(&self) -> &Url {
self.deref().actor()
}
async fn verify(&self, data: &Data<Self::DataType>) -> Result<(), Self::Error> {
self.deref().verify(data).await
}
async fn receive(self, data: &Data<Self::DataType>) -> Result<(), Self::Error> {
(*self).receive(data).await
}
}
#[async_trait]
pub trait Collection: Sized {
type Owner;
type DataType: Clone + Send + Sync;
type Kind: for<'de2> Deserialize<'de2>;
type Error;
async fn read_local(
owner: &Self::Owner,
data: &Data<Self::DataType>,
) -> Result<Self::Kind, Self::Error>;
async fn verify(
json: &Self::Kind,
expected_domain: &Url,
data: &Data<Self::DataType>,
) -> Result<(), Self::Error>;
async fn from_json(
json: Self::Kind,
owner: &Self::Owner,
data: &Data<Self::DataType>,
) -> Result<Self, Self::Error>;
}