Use enum_delegate crate (#5)
This commit is contained in:
parent
34a41d327f
commit
da32da5a67
11 changed files with 65 additions and 259 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -1 +1,2 @@
|
|||
/target
|
||||
/.idea
|
||||
|
|
3
.idea/.gitignore
vendored
3
.idea/.gitignore
vendored
|
@ -1,3 +0,0 @@
|
|||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
|
@ -1,14 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/derive/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/examples" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
|
@ -1,8 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/activitypub-federation-rust.iml" filepath="$PROJECT_DIR$/.idea/activitypub-federation-rust.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
91
Cargo.lock
generated
91
Cargo.lock
generated
|
@ -6,7 +6,6 @@ version = 3
|
|||
name = "activitypub_federation"
|
||||
version = "0.2.3"
|
||||
dependencies = [
|
||||
"activitypub_federation_derive",
|
||||
"activitystreams-kinds",
|
||||
"actix-rt",
|
||||
"actix-web",
|
||||
|
@ -17,6 +16,7 @@ dependencies = [
|
|||
"chrono",
|
||||
"derive_builder",
|
||||
"dyn-clone",
|
||||
"enum_delegate",
|
||||
"env_logger",
|
||||
"http",
|
||||
"http-signature-normalization-actix",
|
||||
|
@ -36,16 +36,6 @@ dependencies = [
|
|||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "activitypub_federation_derive"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"trybuild",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "activitystreams-kinds"
|
||||
version = "0.2.1"
|
||||
|
@ -525,12 +515,6 @@ dependencies = [
|
|||
"crypto-common",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dissimilar"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8c97b9233581d84b8e1e689cdd3a47b6f69770084fc246e86a7f78b0d9c1d4a5"
|
||||
|
||||
[[package]]
|
||||
name = "dyn-clone"
|
||||
version = "1.0.9"
|
||||
|
@ -552,6 +536,30 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enum_delegate"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8ea75f31022cba043afe037940d73684327e915f88f62478e778c3de914cd0a"
|
||||
dependencies = [
|
||||
"enum_delegate_lib",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "enum_delegate_lib"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2e1f6c3800b304a6be0012039e2a45a322a093539c45ab818d9e6895a39c90fe"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rand",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "env_logger"
|
||||
version = "0.9.1"
|
||||
|
@ -716,12 +724,6 @@ dependencies = [
|
|||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "glob"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.14"
|
||||
|
@ -1572,15 +1574,6 @@ dependencies = [
|
|||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.37"
|
||||
|
@ -1691,15 +1684,6 @@ dependencies = [
|
|||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.5.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tower-service"
|
||||
version = "0.3.2"
|
||||
|
@ -1776,22 +1760,6 @@ version = "0.2.3"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642"
|
||||
|
||||
[[package]]
|
||||
name = "trybuild"
|
||||
version = "1.0.65"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9e13556ba7dba80b3c76d1331989a341290c77efcf688eca6c307ee3066383dd"
|
||||
dependencies = [
|
||||
"dissimilar",
|
||||
"glob",
|
||||
"once_cell",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"termcolor",
|
||||
"toml",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.15.0"
|
||||
|
@ -1970,15 +1938,6 @@ version = "0.4.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
|
|
|
@ -7,11 +7,7 @@ license = "AGPL-3.0"
|
|||
repository = "https://github.com/LemmyNet/activitypub-federation-rust"
|
||||
documentation = "https://docs.rs/activitypub_federation/"
|
||||
|
||||
[workspace]
|
||||
members = ["derive"]
|
||||
|
||||
[dependencies]
|
||||
activitypub_federation_derive = { version = "0.2.0", path = "derive" }
|
||||
chrono = { version = "0.4.22", features = ["clock"], default-features = false }
|
||||
serde = { version = "1.0.145", features = ["derive"] }
|
||||
async-trait = "0.1.57"
|
||||
|
@ -34,6 +30,7 @@ thiserror = "1.0.37"
|
|||
derive_builder = "0.11.2"
|
||||
itertools = "0.10.5"
|
||||
dyn-clone = "1.0.9"
|
||||
enum_delegate = "0.2.0"
|
||||
|
||||
[dev-dependencies]
|
||||
activitystreams-kinds = "0.2.1"
|
||||
|
|
|
@ -1,18 +0,0 @@
|
|||
[package]
|
||||
name = "activitypub_federation_derive"
|
||||
version = "0.2.0"
|
||||
edition = "2021"
|
||||
description = "High-level Activitypub framework"
|
||||
license = "AGPL-3.0"
|
||||
repository = "https://github.com/LemmyNet/activitypub-federation-rust"
|
||||
|
||||
[lib]
|
||||
proc-macro = true
|
||||
|
||||
[dev-dependencies]
|
||||
trybuild = { version = "1.0.63", features = ["diff"] }
|
||||
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0.39"
|
||||
syn = "1.0.96"
|
||||
quote = "1.0.18"
|
|
@ -1,137 +0,0 @@
|
|||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
use syn::{parse_macro_input, Data, DeriveInput, Fields::Unnamed, Ident, Variant};
|
||||
|
||||
/// Generates implementation ActivityHandler for an enum, which looks like the following (handling
|
||||
/// all enum variants).
|
||||
///
|
||||
/// Based on this code:
|
||||
/// ```ignore
|
||||
/// #[derive(serde::Deserialize, serde::Serialize)]
|
||||
/// #[serde(untagged)]
|
||||
/// #[activity_handler(LemmyContext, LemmyError)]
|
||||
/// pub enum PersonInboxActivities {
|
||||
/// CreateNote(CreateNote),
|
||||
/// UpdateNote(UpdateNote),
|
||||
/// }
|
||||
/// ```
|
||||
/// It will generate this:
|
||||
/// ```ignore
|
||||
/// impl ActivityHandler for PersonInboxActivities {
|
||||
/// type DataType = LemmyContext;
|
||||
/// type Error = LemmyError;
|
||||
///
|
||||
/// async fn verify(
|
||||
/// &self,
|
||||
/// data: &Self::DataType,
|
||||
/// request_counter: &mut i32,
|
||||
/// ) -> Result<(), Self::Error> {
|
||||
/// match self {
|
||||
/// PersonInboxActivities::CreateNote(a) => a.verify(data, request_counter).await,
|
||||
/// PersonInboxActivities::UpdateNote(a) => a.verify(context, request_counter).await,
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// async fn receive(
|
||||
/// &self,
|
||||
/// data: &Self::DataType,
|
||||
/// request_counter: &mut i32,
|
||||
/// ) -> Result<(), Self::Error> {
|
||||
/// match self {
|
||||
/// PersonInboxActivities::CreateNote(a) => a.receive(data, request_counter).await,
|
||||
/// PersonInboxActivities::UpdateNote(a) => a.receive(data, request_counter).await,
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
#[proc_macro_attribute]
|
||||
pub fn activity_handler(
|
||||
attr: proc_macro::TokenStream,
|
||||
input: proc_macro::TokenStream,
|
||||
) -> proc_macro::TokenStream {
|
||||
let derive_input = parse_macro_input!(input as DeriveInput);
|
||||
let derive_input2 = derive_input.clone();
|
||||
let attr = proc_macro2::TokenStream::from(attr);
|
||||
let mut attr = attr.into_iter();
|
||||
let data_type = attr.next().expect("data type input");
|
||||
let _delimiter = attr.next();
|
||||
let error = attr.next().expect("error type input");
|
||||
|
||||
let enum_name = derive_input2.ident;
|
||||
|
||||
let (impl_generics, ty_generics, where_clause) = derive_input2.generics.split_for_impl();
|
||||
|
||||
let enum_variants = if let Data::Enum(d) = derive_input2.data {
|
||||
d.variants
|
||||
} else {
|
||||
unimplemented!()
|
||||
};
|
||||
|
||||
let impl_id = enum_variants
|
||||
.iter()
|
||||
.map(|v| generate_match_arm(&enum_name, v, "e! {a.id()}));
|
||||
let impl_actor = enum_variants
|
||||
.iter()
|
||||
.map(|v| generate_match_arm(&enum_name, v, "e! {a.actor()}));
|
||||
let body_verify = quote! {a.verify(context, request_counter).await};
|
||||
let impl_verify = enum_variants
|
||||
.iter()
|
||||
.map(|v| generate_match_arm(&enum_name, v, &body_verify));
|
||||
let body_receive = quote! {a.receive(context, request_counter).await};
|
||||
let impl_receive = enum_variants
|
||||
.iter()
|
||||
.map(|v| generate_match_arm(&enum_name, v, &body_receive));
|
||||
|
||||
let expanded = quote! {
|
||||
#derive_input
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl #impl_generics activitypub_federation::traits::ActivityHandler for #enum_name #ty_generics #where_clause {
|
||||
type DataType = #data_type;
|
||||
type Error = #error;
|
||||
fn id(
|
||||
&self,
|
||||
) -> &Url {
|
||||
match self {
|
||||
#(#impl_id)*
|
||||
}
|
||||
}
|
||||
fn actor(
|
||||
&self,
|
||||
) -> &Url {
|
||||
match self {
|
||||
#(#impl_actor)*
|
||||
}
|
||||
}
|
||||
async fn verify(
|
||||
&self,
|
||||
context: &activitypub_federation::data::Data<Self::DataType>,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), Self::Error> {
|
||||
match self {
|
||||
#(#impl_verify)*
|
||||
}
|
||||
}
|
||||
async fn receive(
|
||||
self,
|
||||
context: &activitypub_federation::data::Data<Self::DataType>,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), Self::Error> {
|
||||
match self {
|
||||
#(#impl_receive)*
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
expanded.into()
|
||||
}
|
||||
|
||||
fn generate_match_arm(enum_name: &Ident, variant: &Variant, body: &TokenStream) -> TokenStream {
|
||||
let id = &variant.ident;
|
||||
match &variant.fields {
|
||||
Unnamed(_) => {
|
||||
quote! {
|
||||
#enum_name::#id(a) => #body,
|
||||
}
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
|
@ -11,11 +11,11 @@ use activitypub_federation::{
|
|||
object_id::ObjectId,
|
||||
signatures::{Keypair, PublicKey},
|
||||
},
|
||||
data::Data,
|
||||
deser::context::WithContext,
|
||||
traits::{ActivityHandler, Actor, ApubObject},
|
||||
LocalInstance,
|
||||
};
|
||||
use activitypub_federation_derive::activity_handler;
|
||||
use activitystreams_kinds::actor::PersonType;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use url::Url;
|
||||
|
@ -33,9 +33,9 @@ pub struct MyUser {
|
|||
}
|
||||
|
||||
/// List of all activities which this actor can receive.
|
||||
#[activity_handler(InstanceHandle, Error)]
|
||||
#[derive(Deserialize, Serialize, Debug)]
|
||||
#[serde(untagged)]
|
||||
#[enum_delegate::implement(ActivityHandler)]
|
||||
pub enum PersonAcceptedActivities {
|
||||
Follow(Follow),
|
||||
Accept(Accept),
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
use crate::data::Data;
|
||||
pub use activitypub_federation_derive::*;
|
||||
use chrono::NaiveDateTime;
|
||||
use std::ops::Deref;
|
||||
use url::Url;
|
||||
|
||||
/// Trait which allows verification and reception of incoming activities.
|
||||
#[async_trait::async_trait(?Send)]
|
||||
#[enum_delegate::register]
|
||||
pub trait ActivityHandler {
|
||||
type DataType;
|
||||
type Error;
|
||||
|
@ -32,6 +33,40 @@ pub trait ActivityHandler {
|
|||
) -> Result<(), Self::Error>;
|
||||
}
|
||||
|
||||
/// Allow for boxing of enum variants
|
||||
#[async_trait::async_trait(?Send)]
|
||||
impl<T> ActivityHandler for Box<T>
|
||||
where
|
||||
T: ActivityHandler,
|
||||
{
|
||||
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>,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), Self::Error> {
|
||||
self.verify(data, request_counter).await
|
||||
}
|
||||
|
||||
async fn receive(
|
||||
self,
|
||||
data: &Data<Self::DataType>,
|
||||
request_counter: &mut i32,
|
||||
) -> Result<(), Self::Error> {
|
||||
self.receive(data, request_counter).await
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait(?Send)]
|
||||
pub trait ApubObject {
|
||||
type DataType;
|
||||
|
|
Loading…
Reference in a new issue