almost everything working
This commit is contained in:
parent
b83640ae60
commit
471f113dbe
4 changed files with 57 additions and 31 deletions
|
|
@ -56,7 +56,9 @@ where
|
||||||
let actor_id = activity.actor();
|
let actor_id = activity.actor();
|
||||||
let activity_id = activity.id();
|
let activity_id = activity.id();
|
||||||
let activity_serialized = serde_json::to_string_pretty(&activity)?;
|
let activity_serialized = serde_json::to_string_pretty(&activity)?;
|
||||||
let private_key = actor.private_key_pem().unwrap();
|
let private_key = actor
|
||||||
|
.private_key_pem()
|
||||||
|
.expect("Actor for sending activity has private key");
|
||||||
let inboxes: Vec<Url> = inboxes
|
let inboxes: Vec<Url> = inboxes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.unique()
|
.unique()
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use crate::{error::Error, traits::ApubCollection};
|
use crate::{config::Data, error::Error, fetch::fetch_object_http, traits::ApubCollection};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::{
|
use std::{
|
||||||
fmt::{Debug, Display, Formatter},
|
fmt::{Debug, Display, Formatter},
|
||||||
|
|
@ -6,16 +6,19 @@ use std::{
|
||||||
};
|
};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
/// TODO: implement and document this, update trait docs
|
/// Typed wrapper for Activitypub Collection ID which helps with dereferencing.
|
||||||
/// TODO: which handlers need to receive owner, and should it be simply an url or what?
|
|
||||||
/// TODO: current trait impl without read_from_apub_id() method wont work for http handlers
|
|
||||||
/// -> maybe remove method into_apub() and instead add read_local() (reads from db and
|
|
||||||
/// directly returns serialized collection)
|
|
||||||
#[derive(Serialize, Deserialize)]
|
#[derive(Serialize, Deserialize)]
|
||||||
#[serde(transparent)]
|
#[serde(transparent)]
|
||||||
pub struct CollectionId<Kind>(Box<Url>, PhantomData<Kind>);
|
pub struct CollectionId<Kind>(Box<Url>, PhantomData<Kind>)
|
||||||
|
where
|
||||||
|
Kind: ApubCollection,
|
||||||
|
for<'de2> <Kind as ApubCollection>::ApubType: Deserialize<'de2>;
|
||||||
|
|
||||||
impl<Kind> CollectionId<Kind> {
|
impl<Kind> CollectionId<Kind>
|
||||||
|
where
|
||||||
|
Kind: ApubCollection,
|
||||||
|
for<'de2> <Kind as ApubCollection>::ApubType: Deserialize<'de2>,
|
||||||
|
{
|
||||||
/// Construct a new CollectionId instance
|
/// Construct a new CollectionId instance
|
||||||
pub fn parse<T>(url: T) -> Result<Self, url::ParseError>
|
pub fn parse<T>(url: T) -> Result<Self, url::ParseError>
|
||||||
where
|
where
|
||||||
|
|
@ -25,14 +28,30 @@ impl<Kind> CollectionId<Kind> {
|
||||||
Ok(Self(Box::new(url.try_into()?), PhantomData::<Kind>))
|
Ok(Self(Box::new(url.try_into()?), PhantomData::<Kind>))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// TODO
|
/// Fetches collection over HTTP
|
||||||
pub async fn dereference<T>(&self, _: T) -> Result<Kind, Error> {
|
///
|
||||||
todo!()
|
/// Unlike [ObjectId::fetch](crate::fetch::object_id::ObjectId::fetch) this method doesn't do
|
||||||
|
/// any caching.
|
||||||
|
pub async fn dereference(
|
||||||
|
&self,
|
||||||
|
owner: &<Kind as ApubCollection>::Owner,
|
||||||
|
data: &Data<<Kind as ApubCollection>::DataType>,
|
||||||
|
) -> Result<Kind, <Kind as ApubCollection>::Error>
|
||||||
|
where
|
||||||
|
<Kind as ApubCollection>::Error: From<Error>,
|
||||||
|
{
|
||||||
|
let apub = fetch_object_http(&self.0, data).await?;
|
||||||
|
Kind::verify(&apub, &self.0, data).await?;
|
||||||
|
Kind::from_apub(apub, owner, data).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Need to implement clone manually, to avoid requiring Kind to be Clone
|
/// Need to implement clone manually, to avoid requiring Kind to be Clone
|
||||||
impl<Kind> Clone for CollectionId<Kind> {
|
impl<Kind> Clone for CollectionId<Kind>
|
||||||
|
where
|
||||||
|
Kind: ApubCollection,
|
||||||
|
for<'de2> <Kind as ApubCollection>::ApubType: serde::Deserialize<'de2>,
|
||||||
|
{
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
CollectionId(self.0.clone(), self.1)
|
CollectionId(self.0.clone(), self.1)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -79,3 +79,15 @@ where
|
||||||
self.inner.receive(data).await
|
self.inner.receive(data).await
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> Clone for WithContext<T>
|
||||||
|
where
|
||||||
|
T: Clone,
|
||||||
|
{
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
Self {
|
||||||
|
context: self.context.clone(),
|
||||||
|
inner: self.inner.clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
use crate::{config::Data, protocol::public_key::PublicKey};
|
use crate::{config::Data, protocol::public_key::PublicKey};
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
|
use serde::Deserialize;
|
||||||
use std::{fmt::Debug, ops::Deref};
|
use std::{fmt::Debug, ops::Deref};
|
||||||
use url::Url;
|
use url::Url;
|
||||||
|
|
||||||
|
|
@ -151,8 +152,8 @@ pub trait ApubObject: Sized {
|
||||||
/// Convert object from ActivityPub type to database type.
|
/// Convert object from ActivityPub type to database type.
|
||||||
///
|
///
|
||||||
/// Called when an object is received from HTTP fetch or as part of an activity. This method
|
/// Called when an object is received from HTTP fetch or as part of an activity. This method
|
||||||
/// should do verification and write the received object to database. Note that there is no
|
/// should write the received object to database. Note that there is no distinction between
|
||||||
/// distinction between create and update, so an `upsert` operation should be used.
|
/// create and update, so an `upsert` operation should be used.
|
||||||
async fn from_apub(
|
async fn from_apub(
|
||||||
apub: Self::ApubType,
|
apub: Self::ApubType,
|
||||||
data: &Data<Self::DataType>,
|
data: &Data<Self::DataType>,
|
||||||
|
|
@ -252,7 +253,7 @@ pub trait Actor: ApubObject + Send + 'static {
|
||||||
|
|
||||||
/// Generates a public key struct for use in the actor json representation
|
/// Generates a public key struct for use in the actor json representation
|
||||||
fn public_key(&self) -> PublicKey {
|
fn public_key(&self) -> PublicKey {
|
||||||
PublicKey::new(self.id().clone(), self.public_key_pem().to_string())
|
PublicKey::new(self.id(), self.public_key_pem().to_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The actor's shared inbox, if any
|
/// The actor's shared inbox, if any
|
||||||
|
|
@ -301,17 +302,13 @@ pub trait ApubCollection: Sized {
|
||||||
/// [crate::config::FederationConfigBuilder::app_data] type.
|
/// [crate::config::FederationConfigBuilder::app_data] type.
|
||||||
type DataType: Clone + Send + Sync;
|
type DataType: Clone + Send + Sync;
|
||||||
/// The type of protocol struct which gets sent over network to federate this database struct.
|
/// The type of protocol struct which gets sent over network to federate this database struct.
|
||||||
type ApubType;
|
type ApubType: for<'de2> Deserialize<'de2>;
|
||||||
/// Error type returned by handler methods
|
/// Error type returned by handler methods
|
||||||
type Error;
|
type Error;
|
||||||
|
|
||||||
/// Convert database type to Activitypub type.
|
/// Reads local collection from database and returns it as Activitypub JSON.
|
||||||
///
|
async fn read_local(
|
||||||
/// Called when a local object gets fetched by another instance over HTTP, or when an object
|
owner: &Self::Owner,
|
||||||
/// gets sent in an activity.
|
|
||||||
async fn into_apub(
|
|
||||||
self,
|
|
||||||
owner: Self::Owner,
|
|
||||||
data: &Data<Self::DataType>,
|
data: &Data<Self::DataType>,
|
||||||
) -> Result<Self::ApubType, Self::Error>;
|
) -> Result<Self::ApubType, Self::Error>;
|
||||||
|
|
||||||
|
|
@ -319,12 +316,8 @@ pub trait ApubCollection: Sized {
|
||||||
///
|
///
|
||||||
/// You should check here that the domain of id matches `expected_domain`. Additionally you
|
/// You should check here that the domain of id matches `expected_domain`. Additionally you
|
||||||
/// should perform any application specific checks.
|
/// should perform any application specific checks.
|
||||||
///
|
|
||||||
/// It is necessary to use a separate method for this, because it might be used for activities
|
|
||||||
/// like `Delete/Note`, which shouldn't perform any database write for the inner `Note`.
|
|
||||||
async fn verify(
|
async fn verify(
|
||||||
apub: &Self::ApubType,
|
apub: &Self::ApubType,
|
||||||
owner: Self::Owner,
|
|
||||||
expected_domain: &Url,
|
expected_domain: &Url,
|
||||||
data: &Data<Self::DataType>,
|
data: &Data<Self::DataType>,
|
||||||
) -> Result<(), Self::Error>;
|
) -> Result<(), Self::Error>;
|
||||||
|
|
@ -332,11 +325,11 @@ pub trait ApubCollection: Sized {
|
||||||
/// Convert object from ActivityPub type to database type.
|
/// Convert object from ActivityPub type to database type.
|
||||||
///
|
///
|
||||||
/// Called when an object is received from HTTP fetch or as part of an activity. This method
|
/// Called when an object is received from HTTP fetch or as part of an activity. This method
|
||||||
/// should do verification and write the received object to database. Note that there is no
|
/// should also write the received object to database. Note that there is no distinction
|
||||||
/// distinction between create and update, so an `upsert` operation should be used.
|
/// between create and update, so an `upsert` operation should be used.
|
||||||
async fn from_apub(
|
async fn from_apub(
|
||||||
apub: Self::ApubType,
|
apub: Self::ApubType,
|
||||||
owner: Self::Owner,
|
owner: &Self::Owner,
|
||||||
data: &Data<Self::DataType>,
|
data: &Data<Self::DataType>,
|
||||||
) -> Result<Self, Self::Error>;
|
) -> Result<Self, Self::Error>;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue