Initial AP commit
This commit is contained in:
parent
2ffb82895c
commit
59f1d834d4
|
@ -584,6 +584,16 @@ version = "0.9.4"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "795bc6e66a8e340f075fcf6227e417a2dc976b92b91f3cdc778bb858778b6747"
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation"
|
||||
version = "0.9.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.4"
|
||||
|
@ -742,6 +752,15 @@ dependencies = [
|
|||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.33"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "equivalent"
|
||||
version = "1.0.1"
|
||||
|
@ -818,6 +837,21 @@ version = "1.0.7"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1"
|
||||
dependencies = [
|
||||
"foreign-types-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "foreign-types-shared"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
|
||||
|
||||
[[package]]
|
||||
name = "form_urlencoded"
|
||||
version = "1.2.0"
|
||||
|
@ -1188,6 +1222,19 @@ dependencies = [
|
|||
"want",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hyper-tls"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d6183ddfa99b85da61a140bea0efc93fdf56ceaa041b37d553518030827f9905"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"hyper",
|
||||
"native-tls",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.57"
|
||||
|
@ -1284,6 +1331,12 @@ dependencies = [
|
|||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "28b29a3cd74f0f4598934efe3aeba42bae0eb4680554128851ebbecb02af14e6"
|
||||
|
||||
[[package]]
|
||||
name = "is-terminal"
|
||||
version = "0.4.9"
|
||||
|
@ -1377,13 +1430,16 @@ checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4"
|
|||
name = "magnetar"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"axum",
|
||||
"cached",
|
||||
"cfg-if",
|
||||
"chrono",
|
||||
"dotenvy",
|
||||
"futures-util",
|
||||
"headers",
|
||||
"hyper",
|
||||
"magnetar_activity_pub",
|
||||
"magnetar_calckey_model",
|
||||
"magnetar_common",
|
||||
"magnetar_core",
|
||||
|
@ -1392,6 +1448,7 @@ dependencies = [
|
|||
"magnetar_webfinger",
|
||||
"miette",
|
||||
"percent-encoding",
|
||||
"reqwest",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"strum",
|
||||
|
@ -1403,6 +1460,20 @@ dependencies = [
|
|||
"tracing",
|
||||
"tracing-subscriber",
|
||||
"unicode-segmentation",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "magnetar_activity_pub"
|
||||
version = "0.2.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"chrono",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"url",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -1603,6 +1674,24 @@ dependencies = [
|
|||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "native-tls"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "07226173c32f2926027b63cce4bcd8076c3552846cbe7925f3aaffeac0a3b92e"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
"openssl",
|
||||
"openssl-probe",
|
||||
"openssl-sys",
|
||||
"schannel",
|
||||
"security-framework",
|
||||
"security-framework-sys",
|
||||
"tempfile",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "nom"
|
||||
version = "7.1.3"
|
||||
|
@ -1707,6 +1796,50 @@ version = "1.18.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.57"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c"
|
||||
dependencies = [
|
||||
"bitflags 2.3.3",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-macros"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-probe"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
|
||||
|
||||
[[package]]
|
||||
name = "openssl-sys"
|
||||
version = "0.9.93"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ordered-float"
|
||||
version = "3.7.0"
|
||||
|
@ -2139,6 +2272,43 @@ dependencies = [
|
|||
"bytecheck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1"
|
||||
dependencies = [
|
||||
"base64 0.21.2",
|
||||
"bytes",
|
||||
"encoding_rs",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"hyper",
|
||||
"hyper-tls",
|
||||
"ipnet",
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"native-tls",
|
||||
"once_cell",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_urlencoded",
|
||||
"tokio",
|
||||
"tokio-native-tls",
|
||||
"tower-service",
|
||||
"url",
|
||||
"wasm-bindgen",
|
||||
"wasm-bindgen-futures",
|
||||
"web-sys",
|
||||
"winreg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ring"
|
||||
version = "0.16.20"
|
||||
|
@ -2291,6 +2461,15 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c3733bf4cf7ea0880754e19cb5a462007c4a8c1914bff372ccc95b464f1df88"
|
||||
dependencies = [
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.2.0"
|
||||
|
@ -2472,6 +2651,29 @@ version = "4.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b"
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.9.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.180"
|
||||
|
@ -3132,6 +3334,16 @@ dependencies = [
|
|||
"syn 2.0.28",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bbae76ab933c85776efabc971569dd6119c580d8f5d448769dec1764bf796ef2"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-stream"
|
||||
version = "0.1.14"
|
||||
|
@ -3480,6 +3692,7 @@ dependencies = [
|
|||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
@ -3571,6 +3784,18 @@ dependencies = [
|
|||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c02dbc21516f9f1f04f187958890d7e6026df8d16540b7ad9492bc34a67cea03"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.87"
|
||||
|
@ -3740,6 +3965,16 @@ dependencies = [
|
|||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.50.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wyz"
|
||||
version = "0.5.1"
|
||||
|
|
|
@ -8,6 +8,7 @@ license = "AGPL-3.0-only"
|
|||
[workspace]
|
||||
members = [
|
||||
".",
|
||||
"ext_activity_pub",
|
||||
"ext_nodeinfo",
|
||||
"ext_webfinger",
|
||||
"ext_calckey_model",
|
||||
|
@ -62,6 +63,7 @@ wasm-bindgen-futures = "0.4"
|
|||
web-sys = "0.3"
|
||||
|
||||
[dependencies]
|
||||
magnetar_activity_pub = { path = "./ext_activity_pub" }
|
||||
magnetar_core = { path = "./core" }
|
||||
magnetar_common = { path = "./magnetar_common" }
|
||||
magnetar_webfinger = { path = "./ext_webfinger" }
|
||||
|
@ -73,12 +75,17 @@ cached = { workspace = true }
|
|||
chrono = { workspace = true }
|
||||
dotenvy = { workspace = true }
|
||||
|
||||
async-trait = { workspace = true }
|
||||
axum = { workspace = true, features = ["macros", "headers"] }
|
||||
futures-util = { workspace = true }
|
||||
headers = { workspace = true }
|
||||
hyper = { workspace = true, features = ["full"] }
|
||||
tokio = { workspace = true, features = ["full"] }
|
||||
tower = { workspace = true }
|
||||
tower-http = { workspace = true, features = ["cors", "trace", "fs"] }
|
||||
url = { workspace = true }
|
||||
|
||||
reqwest = { workspace = true, features = ["json"] }
|
||||
|
||||
tracing-subscriber = { workspace = true, features = ["env-filter"] }
|
||||
tracing = { workspace = true }
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
[package]
|
||||
name = "magnetar_activity_pub"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
license = "MIT OR Apache-2.0"
|
||||
|
||||
[lib]
|
||||
crate-type = ["rlib"]
|
||||
|
||||
[dependencies]
|
||||
async-trait = { workspace = true }
|
||||
serde = { workspace = true, features = ["derive"] }
|
||||
serde_json = { workspace = true }
|
||||
chrono = { workspace = true, features = ["serde"] }
|
||||
thiserror = { workspace = true }
|
||||
url = { workspace = true, features = ["serde"] }
|
||||
|
||||
[dev-dependencies]
|
||||
tokio = { workspace = true, features = ["full"] }
|
|
@ -0,0 +1,237 @@
|
|||
pub mod link;
|
||||
pub mod object;
|
||||
pub mod recipe;
|
||||
|
||||
use crate::link::Link;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
use std::borrow::Cow;
|
||||
use std::fmt::Debug;
|
||||
use std::ops::Deref;
|
||||
use url::Url;
|
||||
|
||||
pub trait ObjectSingle: Clone + Debug + Sized + 'static {
|
||||
fn get_type() -> &'static str;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct ObjectRaw<T> {
|
||||
#[serde(flatten)]
|
||||
data: Box<T>,
|
||||
#[serde(flatten)]
|
||||
raw: Value,
|
||||
}
|
||||
|
||||
impl<T> Deref for ObjectRaw<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ObjectRaw<T> {
|
||||
pub fn into_inner(self) -> Box<T> {
|
||||
self.data
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsRef<T> for ObjectRaw<T> {
|
||||
fn as_ref(&self) -> &T {
|
||||
self.as_data()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> ObjectRaw<T> {
|
||||
pub fn as_data(&self) -> &T {
|
||||
&self.data
|
||||
}
|
||||
|
||||
pub fn as_json(&self) -> &Value {
|
||||
&self.raw
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait Resolver: Send + Sync {
|
||||
type Error: Send + Sync;
|
||||
|
||||
async fn resolve<T: for<'a> Deserialize<'a>>(&self, id: &str) -> Result<T, Self::Error>;
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait Resolvable {
|
||||
type Output: Clone + Send + Sync;
|
||||
|
||||
async fn resolve<R: Resolver>(&self, resolver: &R) -> Result<Cow<Self::Output>, R::Error>;
|
||||
|
||||
fn unresolve(&self) -> Option<&str>;
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! def_ld {
|
||||
($obj_type: expr, $x: ty) => {
|
||||
impl $crate::ObjectSingle for $x {
|
||||
fn get_type() -> &'static str {
|
||||
$obj_type
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! ld_document {
|
||||
($y: ident, $x: ty) => {
|
||||
impl $y {
|
||||
pub async fn resolve<R: $crate::Resolver>(
|
||||
&self,
|
||||
resolver: &R,
|
||||
) -> Result<std::borrow::Cow<ObjectRaw<$x>>, R::Error> {
|
||||
match self {
|
||||
$y::Object(obj) => Ok(std::borrow::Cow::Borrowed(obj)),
|
||||
$y::Remote(Id(link)) => {
|
||||
Ok(std::borrow::Cow::Owned(resolver.resolve(link).await?))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unresolve(&self) -> Option<&str> {
|
||||
match self {
|
||||
$y::Object(obj) => obj.as_data().as_id.as_deref(),
|
||||
$y::Remote(Id(id)) => Some(&id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum $y {
|
||||
Remote(Id),
|
||||
Object(Box<ObjectRaw<$x>>),
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl $crate::Resolvable for $y {
|
||||
type Output = $crate::ObjectRaw<$x>;
|
||||
|
||||
async fn resolve<R: $crate::Resolver>(
|
||||
&self,
|
||||
resolver: &R,
|
||||
) -> Result<std::borrow::Cow<Self::Output>, R::Error> {
|
||||
self.resolve(resolver).await
|
||||
}
|
||||
|
||||
fn unresolve(&self) -> Option<&str> {
|
||||
self.unresolve()
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl ObjectRaw<$x> {
|
||||
pub fn try_cast<T>() -> T {}
|
||||
}
|
||||
|
||||
*/
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! ld_union {
|
||||
($y: ident, $z: ident, $($item_name: ident as $item_type: ty),+) => {
|
||||
impl $y {
|
||||
pub async fn resolve<R: $crate::Resolver>(
|
||||
&self,
|
||||
resolver: &R,
|
||||
) -> Result<std::borrow::Cow<ObjectRaw<$z>>, R::Error> {
|
||||
match self {
|
||||
$y::Object(obj) => Ok(std::borrow::Cow::Borrowed(obj)),
|
||||
$y::Remote(Id(link)) => {
|
||||
Ok(std::borrow::Cow::Owned(resolver.resolve(link).await?))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn unresolve(&self) -> Option<&str> {
|
||||
match self {
|
||||
$y::Object(obj) => obj.as_data().base.as_id.as_deref(),
|
||||
$y::Remote(Id(id)) => Some(&id),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct $z {
|
||||
#[serde(flatten)]
|
||||
pub base: $crate::Base,
|
||||
$(
|
||||
#[serde(flatten)]
|
||||
$item_name: Box<$item_type>,
|
||||
)+
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum $y {
|
||||
Remote(Id),
|
||||
Object(ObjectRaw<$z>),
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl $crate::Resolvable for $y {
|
||||
type Output = $crate::ObjectRaw<$z>;
|
||||
|
||||
async fn resolve<R: $crate::Resolver>(
|
||||
&self,
|
||||
resolver: &R,
|
||||
) -> Result<std::borrow::Cow<Self::Output>, R::Error> {
|
||||
self.resolve(resolver).await
|
||||
}
|
||||
|
||||
fn unresolve(&self) -> Option<&str> {
|
||||
self.unresolve()
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum OneOrMore<T> {
|
||||
One(T),
|
||||
Many(Vec<T>),
|
||||
}
|
||||
|
||||
impl<T> OneOrMore<T> {
|
||||
pub fn into_vec(self) -> Vec<T> {
|
||||
match self {
|
||||
OneOrMore::One(x) => vec![x],
|
||||
OneOrMore::Many(x) => x,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn iter(&self) -> std::slice::Iter<'_, T> {
|
||||
match self {
|
||||
OneOrMore::One(x) => std::slice::from_ref(x).iter(),
|
||||
OneOrMore::Many(x) => x.iter(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
|
||||
pub struct Base {
|
||||
#[serde(rename = "@type")]
|
||||
as_type: Option<OneOrMore<String>>,
|
||||
#[serde(rename = "@id")]
|
||||
as_id: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum LinkOrUrl {
|
||||
Url(Url),
|
||||
Link(Box<Link>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[repr(transparent)]
|
||||
pub struct Id(pub String);
|
|
@ -0,0 +1,8 @@
|
|||
use crate::{def_ld, ld_document, Id, ObjectRaw};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct LinkMention;
|
||||
|
||||
def_ld!("https://www.w3.org/ns/activitystreams#Mention", LinkMention);
|
||||
ld_document!(RefLinkMention, LinkMention);
|
|
@ -0,0 +1,44 @@
|
|||
use crate::object::RefObjectLinkUnion;
|
||||
use crate::OneOrMore;
|
||||
use crate::{def_ld, ld_document, Id, ObjectRaw};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub mod link_types;
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct Link {
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#href")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub href: Option<String>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#hreflang")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub href_lang: Option<String>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#mediaType")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub media_type: Option<String>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#rel")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub rel: Option<OneOrMore<String>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#name")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub name: Option<String>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#width")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub width: Option<u32>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#height")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub height: Option<u32>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#preview")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub preview: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
}
|
||||
|
||||
def_ld!("https://www.w3.org/ns/activitystreams#Link", Link);
|
||||
ld_document!(RefLink, Link);
|
|
@ -0,0 +1,240 @@
|
|||
use crate::object::{Object, RefObjectLinkUnion};
|
||||
use crate::{def_ld, ld_document, Id, ObjectRaw, ObjectSingle, OneOrMore};
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct Activity {
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#actor")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub actor: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#object")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub object: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#target")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub target: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#result")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub result: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#origin")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub origin: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#instrument")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub instrument: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
}
|
||||
|
||||
def_ld!("Activity", Activity, base as Object);
|
||||
ld_document!(RefActivity, Activity);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct IntransitiveActivity;
|
||||
|
||||
def_ld!(
|
||||
"IntransitiveActivity",
|
||||
IntransitiveActivity,
|
||||
base as Activity
|
||||
);
|
||||
ld_document!(RefIntransitiveActivity, IntransitiveActivity);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityAccept;
|
||||
|
||||
def_ld!("Accept", ActivityAccept, base as Activity);
|
||||
ld_document!(RefActivityAccept, ActivityAccept);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityTentativeAccept;
|
||||
|
||||
def_ld!(
|
||||
"TentativeAccept",
|
||||
ActivityTentativeAccept,
|
||||
base as ActivityAccept
|
||||
);
|
||||
ld_document!(RefActivityTentativeAccept, ActivityTentativeAccept);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityAdd;
|
||||
|
||||
def_ld!("Add", ActivityAdd, base as Activity);
|
||||
ld_document!(RefActivityAdd, ActivityAdd);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityArrive;
|
||||
|
||||
def_ld!("Arrive", ActivityArrive, base as Activity);
|
||||
ld_document!(RefActivityArrive, ActivityArrive);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityCreate;
|
||||
|
||||
def_ld!("Create", ActivityCreate, base as Activity);
|
||||
ld_document!(RefActivityCreate, ActivityCreate);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityDelete;
|
||||
|
||||
def_ld!("Delete", ActivityDelete, base as Activity);
|
||||
ld_document!(RefActivityDelete, ActivityDelete);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityFollow;
|
||||
|
||||
def_ld!("Follow", ActivityFollow, base as Activity);
|
||||
ld_document!(RefActivityFollow, ActivityFollow);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityIgnore;
|
||||
|
||||
def_ld!("Ignore", ActivityIgnore, base as Activity);
|
||||
ld_document!(RefActivityIgnore, ActivityIgnore);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityJoin;
|
||||
|
||||
def_ld!("Join", ActivityJoin, base as Activity);
|
||||
ld_document!(RefActivityJoin, ActivityJoin);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityLeave;
|
||||
|
||||
def_ld!("Leave", ActivityLeave, base as Activity);
|
||||
ld_document!(RefActivityLeave, ActivityLeave);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityLike;
|
||||
|
||||
def_ld!("Like", ActivityLike, base as Activity);
|
||||
ld_document!(RefActivityLike, ActivityLike);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityOffer;
|
||||
|
||||
def_ld!("Offer", ActivityOffer, base as Activity);
|
||||
ld_document!(RefActivityOffer, ActivityOffer);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityInvite;
|
||||
|
||||
def_ld!("Invite", ActivityInvite, base as ActivityOffer);
|
||||
ld_document!(RefActivityInvite, ActivityInvite);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityReject;
|
||||
|
||||
def_ld!("Reject", ActivityReject, base as Activity);
|
||||
ld_document!(RefActivityReject, ActivityReject);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityTentativeReject;
|
||||
|
||||
def_ld!(
|
||||
"TentativeReject",
|
||||
ActivityTentativeReject,
|
||||
base as ActivityReject
|
||||
);
|
||||
ld_document!(RefActivityTentativeReject, ActivityTentativeReject);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityRemove;
|
||||
|
||||
def_ld!("Remove", ActivityRemove, base as Activity);
|
||||
ld_document!(RefActivityRemove, ActivityRemove);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityUndo;
|
||||
|
||||
def_ld!("Undo", ActivityUndo, base as Activity);
|
||||
ld_document!(RefActivityUndo, ActivityUndo);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityUpdate;
|
||||
|
||||
def_ld!("Update", ActivityUpdate, base as Activity);
|
||||
ld_document!(RefActivityUpdate, ActivityUpdate);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityView;
|
||||
|
||||
def_ld!("View", ActivityView, base as Activity);
|
||||
ld_document!(RefActivityView, ActivityView);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityListen;
|
||||
|
||||
def_ld!("Listen", ActivityListen, base as Activity);
|
||||
ld_document!(RefActivityListen, ActivityListen);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityRead;
|
||||
|
||||
def_ld!("Read", ActivityRead, base as Activity);
|
||||
ld_document!(RefActivityRead, ActivityRead);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityMove;
|
||||
|
||||
def_ld!("Move", ActivityMove, base as Activity);
|
||||
ld_document!(RefActivityMove, ActivityMove);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityTravel;
|
||||
|
||||
def_ld!("Travel", ActivityTravel, base as IntransitiveActivity);
|
||||
ld_document!(RefActivityTravel, ActivityTravel);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityAnnounce;
|
||||
|
||||
def_ld!("Announce", ActivityAnnounce, base as Activity);
|
||||
ld_document!(RefActivityAnnounce, ActivityAnnounce);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityBlock;
|
||||
|
||||
def_ld!("Block", ActivityBlock, base as ActivityIgnore);
|
||||
ld_document!(RefActivityBlock, ActivityBlock);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityFlag;
|
||||
|
||||
def_ld!("Flag", ActivityFlag, base as Activity);
|
||||
ld_document!(RefActivityFlag, ActivityFlag);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityDislike;
|
||||
|
||||
def_ld!("Dislike", ActivityDislike, base as Activity);
|
||||
ld_document!(RefActivityDislike, ActivityDislike);
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
#[serde(untagged)]
|
||||
pub enum ActivityClosedStatus {
|
||||
Date(DateTime<Utc>),
|
||||
Bool(bool),
|
||||
Other(RefObjectLinkUnion),
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActivityQuestion {
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#oneOf")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub one_of: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#anyOf")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub any_of: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#closed")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub closed: Option<OneOrMore<ActivityClosedStatus>>,
|
||||
}
|
||||
|
||||
def_ld!("Question", ActivityQuestion, base as IntransitiveActivity);
|
||||
ld_document!(RefActivityQuestion, ActivityQuestion);
|
|
@ -0,0 +1,68 @@
|
|||
use crate::object::{RefCollection, RefOrderedCollection};
|
||||
use crate::{def_ld, ld_document, Id, ObjectRaw};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActorActivityPubProps {
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#inbox")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub inbox: Option<RefOrderedCollection>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#outbox")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub outbox: Option<RefOrderedCollection>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#following")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub following: Option<RefCollection>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#followers")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub followers: Option<RefCollection>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#liked")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub liked: Option<RefCollection>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#shares")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub shares: Option<RefCollection>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#preferredUsername")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub preferred_username: Option<String>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#endpoints")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub endpoints: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActorApplication;
|
||||
|
||||
def_ld!("Application", ActorApplication, base as Object);
|
||||
ld_document!(RefActorApplication, ActorApplication);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActorGroup;
|
||||
|
||||
def_ld!("Group", ActorGroup, base as Object);
|
||||
ld_document!(RefActorGroup, ActorGroup);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActorOrganization;
|
||||
|
||||
def_ld!("Organization", ActorOrganization, base as Object);
|
||||
ld_document!(RefActorOrganization, ActorOrganization);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActorPerson;
|
||||
|
||||
def_ld!("Person", ActorPerson, base as Object);
|
||||
ld_document!(RefActorPerson, ActorPerson);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ActorService;
|
||||
|
||||
def_ld!("Service", ActorService, base as Object);
|
||||
ld_document!(RefActorService, ActorService);
|
|
@ -0,0 +1,233 @@
|
|||
use crate::link::Link;
|
||||
use crate::object::object_types::RefObjectImageLinkUnion;
|
||||
use crate::{def_ld, Id};
|
||||
use crate::{ld_document, ld_union, Base, LinkOrUrl, ObjectRaw, ObjectSingle, OneOrMore};
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub mod activity;
|
||||
pub mod actor;
|
||||
pub mod object_types;
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct Object {
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#attachment")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub attachment: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#attributedTo")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub attributed_to: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#audience")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub audience: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#content")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub content: Option<String>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#contentMap")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub content_map: Option<HashMap<String, String>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#context")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub context: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#name")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub name: Option<String>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#nameMap")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub name_map: Option<HashMap<String, String>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#endTime")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub end_time: Option<DateTime<Utc>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#generator")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub generator: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#icon")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub icon: Option<OneOrMore<RefObjectImageLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#image")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub image: Option<OneOrMore<RefObjectImageLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#inReplyTo")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub in_reply_to: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#location")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub location: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#preview")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub preview: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#published")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub published: Option<DateTime<Utc>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#replies")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub replies: Option<RefCollectionLinkUnion>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#startTime")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub start_time: Option<DateTime<Utc>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#summary")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub summary: Option<String>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#summaryMap")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub summary_map: Option<HashMap<String, String>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#tag")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub tag: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#updated")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub updated: Option<DateTime<Utc>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#url")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub url: Option<OneOrMore<LinkOrUrl>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#to")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub to: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#bto")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub bto: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#cc")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub cc: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#bcc")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub bcc: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#mediaType")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub media_type: Option<String>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#duration")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub duration: Option<String>,
|
||||
|
||||
// ActivityPub
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#source")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub source: Option<RefObject>,
|
||||
}
|
||||
|
||||
def_ld!("https://www.w3.org/ns/activitystreams#Object", Object);
|
||||
ld_document!(RefObject, Object);
|
||||
ld_union!(
|
||||
RefObjectLinkUnion,
|
||||
ObjectLinkUnion,
|
||||
object_props as Object,
|
||||
link_props as Link
|
||||
);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct Collection {
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#totalItems")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub total_items: Option<u32>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#current")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub current: Option<RefCollectionPageLinkUnion>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#first")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub first: Option<RefCollectionPageLinkUnion>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#last")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub last: Option<RefCollectionPageLinkUnion>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#items")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub items: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
}
|
||||
|
||||
def_ld!(
|
||||
"https://www.w3.org/ns/activitystreams#Collection",
|
||||
Collection
|
||||
);
|
||||
ld_document!(RefCollection, Collection);
|
||||
ld_union!(
|
||||
RefCollectionLinkUnion,
|
||||
CollectionLinkUnion,
|
||||
collection_props as Collection,
|
||||
link_props as Link
|
||||
);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct OrderedCollection {
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#orderedItems")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub ordered_items: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
}
|
||||
|
||||
def_ld!(
|
||||
"https://www.w3.org/ns/activitystreams#OrderedCollection",
|
||||
OrderedCollection
|
||||
);
|
||||
ld_document!(RefOrderedCollection, OrderedCollection);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct CollectionPage {
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#next")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub next: Option<RefCollectionPageLinkUnion>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#prev")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub prev: Option<RefCollectionPageLinkUnion>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#partOf")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub part_of: Option<RefCollectionLinkUnion>,
|
||||
}
|
||||
|
||||
def_ld!(
|
||||
"https://www.w3.org/ns/activitystreams#CollectionPage",
|
||||
CollectionPage
|
||||
);
|
||||
ld_document!(RefCollectionPage, CollectionPage);
|
||||
|
||||
ld_union!(
|
||||
RefCollectionPageLinkUnion,
|
||||
CollectionPageLinkUnion,
|
||||
page_props as CollectionPage,
|
||||
link_props as Link
|
||||
);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct OrderedCollectionPage {
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#startIndex")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub start_index: Option<u32>,
|
||||
}
|
||||
|
||||
def_ld!(
|
||||
"https://www.w3.org/ns/activitystreams#OrderedCollectionPage",
|
||||
OrderedCollectionPage
|
||||
);
|
||||
ld_document!(RefOrderedCollectionPage, OrderedCollectionPage);
|
|
@ -0,0 +1,131 @@
|
|||
use crate::link::Link;
|
||||
use crate::object::{Object, RefObject, RefObjectLinkUnion};
|
||||
use crate::{def_ld, ld_document, ld_union, Id, ObjectRaw, ObjectSingle, OneOrMore};
|
||||
use chrono::{DateTime, Utc};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ObjectRelationship {
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#object")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub object: Option<OneOrMore<RefObjectLinkUnion>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#subject")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub subject: Option<RefObjectLinkUnion>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#relationship")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub relationship: Option<OneOrMore<RefObject>>,
|
||||
}
|
||||
|
||||
def_ld!("Relationship", ObjectRelationship, base as Object);
|
||||
ld_document!(RefObjectRelationship, ObjectRelationship);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ObjectArticle;
|
||||
|
||||
def_ld!("Article", ObjectArticle, base as Object);
|
||||
ld_document!(RefObjectArticle, ObjectArticle);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ObjectDocument;
|
||||
|
||||
def_ld!("Document", ObjectDocument, base as Object);
|
||||
ld_document!(RefObjectDocument, ObjectDocument);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ObjectAudio;
|
||||
|
||||
def_ld!("Audio", ObjectAudio, base as ObjectDocument);
|
||||
ld_document!(RefObjectAudio, ObjectAudio);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ObjectImage;
|
||||
|
||||
def_ld!("Image", ObjectImage, base as ObjectDocument);
|
||||
ld_document!(RefObjectImage, ObjectImage);
|
||||
ld_union!(
|
||||
RefObjectImageLinkUnion,
|
||||
ObjectImageLinkUnion,
|
||||
image_props as ObjectImage,
|
||||
link_props as Link
|
||||
);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ObjectVideo;
|
||||
|
||||
def_ld!("Video", ObjectVideo, base as ObjectDocument);
|
||||
ld_document!(RefObjectVideo, ObjectVideo);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ObjectNote;
|
||||
|
||||
def_ld!("Note", ObjectNote, base as Object);
|
||||
ld_document!(RefObjectNote, ObjectNote);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ObjectPage;
|
||||
|
||||
def_ld!("Page", ObjectPage, base as ObjectDocument);
|
||||
ld_document!(RefObjectPage, ObjectPage);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ObjectEvent;
|
||||
|
||||
def_ld!("Event", ObjectEvent, base as Object);
|
||||
ld_document!(RefObjectEvent, ObjectEvent);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ObjectPlace {
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#accuracy")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub accuracy: Option<f64>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#altitude")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub altitude: Option<f64>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#latitude")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub latitude: Option<f64>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#longitude")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub longitude: Option<f64>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#radius")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub radius: Option<f64>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#units")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub units: Option<String>,
|
||||
}
|
||||
|
||||
def_ld!("Place", ObjectPlace, base as Object);
|
||||
ld_document!(RefObjectPlace, ObjectPlace);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ObjectProfile {
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#describes")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub describes: Option<RefObject>,
|
||||
}
|
||||
|
||||
def_ld!("Profile", ObjectProfile, base as Object);
|
||||
ld_document!(RefObjectProfile, ObjectProfile);
|
||||
|
||||
#[derive(Clone, Default, Debug, Serialize, Deserialize)]
|
||||
pub struct ObjectTombstone {
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#formerType")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub former_type: Option<OneOrMore<String>>,
|
||||
|
||||
#[serde(rename = "https://www.w3.org/ns/activitystreams#deleted")]
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub deleted: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
def_ld!("Tombstone", ObjectTombstone, base as Object);
|
||||
ld_document!(RefObjectTombstone, ObjectTombstone);
|
|
@ -0,0 +1,87 @@
|
|||
use crate::object::activity::ActivityBlock;
|
||||
|
||||
use crate::object::Object;
|
||||
use crate::recipe::RecipeError;
|
||||
use crate::{extract_field, Id, ObjectRaw};
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Block {
|
||||
pub id: Id,
|
||||
pub actor: Id,
|
||||
pub object: Id,
|
||||
pub to: Id,
|
||||
}
|
||||
|
||||
impl Block {
|
||||
fn parse(object: &ObjectRaw<impl AsRef<Object>>) -> Result<Block, RecipeError> {
|
||||
let json = object.as_json();
|
||||
let data: &Object = (*object.data).as_ref();
|
||||
|
||||
let ap_type = extract_field!(data, as_type, unwrap);
|
||||
if ap_type.iter().all(|t| t != "Block") {
|
||||
return Err(RecipeError::UnexpectedType(format!("{:?}", ap_type)));
|
||||
}
|
||||
|
||||
let block = ActivityBlock::deserialize(json)?;
|
||||
Ok(Block {
|
||||
id: Id(extract_field!(block, as_id, unwrap | owned)),
|
||||
actor: Id(extract_field!(
|
||||
block,
|
||||
actor,
|
||||
unwrap | single | as_id | owned
|
||||
)),
|
||||
object: Id(extract_field!(
|
||||
block,
|
||||
object,
|
||||
unwrap | single | as_id | owned
|
||||
)),
|
||||
to: Id(extract_field!(block, to, unwrap | single | as_id | owned)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::object::activity::{Activity, ActivityBlock, ActivityIgnore};
|
||||
use crate::object::Object;
|
||||
use crate::ObjectRaw;
|
||||
use serde::Deserialize;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
fn parse_json() {
|
||||
let json = json!({
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"id": "https://a.example.com/blocks/1",
|
||||
"type": "Block",
|
||||
"actor": "https://a.example.com/users/1",
|
||||
"object": "https://b.example.com/users/2",
|
||||
"to": "https://b.example.com/users/2",
|
||||
});
|
||||
|
||||
let object = ObjectRaw::<Activity>::deserialize(json).unwrap();
|
||||
|
||||
let block = super::Block::parse(&object).unwrap();
|
||||
|
||||
println!("{:#?}", block);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_json_with_multiple_types() {
|
||||
let json = json!({
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"id": "https://a.example.com/blocks/1",
|
||||
"type": ["Block", "https://example.com/SomeOtherType"],
|
||||
"actor": "https://a.example.com/users/1",
|
||||
"object": "https://b.example.com/users/2",
|
||||
"to": "https://b.example.com/users/2",
|
||||
});
|
||||
|
||||
let object = ObjectRaw::<Activity>::deserialize(json).unwrap();
|
||||
|
||||
let block = super::Block::parse(&object).unwrap();
|
||||
|
||||
println!("{:#?}", block);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,97 @@
|
|||
use crate::{OneOrMore, Resolvable};
|
||||
use thiserror::Error;
|
||||
|
||||
#[macro_use]
|
||||
pub mod account_move;
|
||||
#[macro_use]
|
||||
pub mod block;
|
||||
#[macro_use]
|
||||
pub mod flag;
|
||||
#[macro_use]
|
||||
pub mod poll;
|
||||
#[macro_use]
|
||||
pub mod tag;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum RecipeError {
|
||||
#[error("Serde error")]
|
||||
DeserializationError(#[from] serde_json::Error),
|
||||
#[error("Unexpected type: {0}")]
|
||||
UnexpectedType(String),
|
||||
#[error("Missing field: {0}")]
|
||||
MissingField(&'static str),
|
||||
#[error("Single item expected: {0}")]
|
||||
ExpectedSingleField(&'static str),
|
||||
#[error("Missing ID")]
|
||||
MissingId,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub struct FieldPipeline<T> {
|
||||
value: T,
|
||||
field_name: &'static str,
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! extract_field {
|
||||
($obj: expr, $field: ident, $($step:ident)|+ $(|)?) => {{
|
||||
let pipeline = $crate::recipe::FieldPipeline {
|
||||
value: $obj.$field.as_ref(),
|
||||
field_name: stringify!($field),
|
||||
};
|
||||
|
||||
$(
|
||||
let pipeline = pipeline.$step()?;
|
||||
)+
|
||||
|
||||
pipeline.into_inner()
|
||||
}};
|
||||
}
|
||||
|
||||
impl<T> FieldPipeline<Option<T>> {
|
||||
fn unwrap(self) -> Result<FieldPipeline<T>, RecipeError> {
|
||||
Ok(FieldPipeline {
|
||||
value: self
|
||||
.value
|
||||
.ok_or(RecipeError::MissingField(self.field_name))?,
|
||||
field_name: self.field_name,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Resolvable> FieldPipeline<&T> {
|
||||
fn as_id(&self) -> Result<FieldPipeline<&str>, RecipeError> {
|
||||
Ok(FieldPipeline {
|
||||
value: self.value.unresolve().ok_or(RecipeError::MissingId)?,
|
||||
field_name: self.field_name,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> FieldPipeline<&'a OneOrMore<T>> {
|
||||
fn single(self) -> Result<FieldPipeline<&'a T>, RecipeError> {
|
||||
Ok(FieldPipeline {
|
||||
value: match self.value {
|
||||
OneOrMore::One(x) => Ok(x),
|
||||
OneOrMore::Many(vec) if vec.len() == 1 => Ok(vec.first().unwrap()),
|
||||
OneOrMore::Many(_) => Err(RecipeError::ExpectedSingleField(self.field_name)),
|
||||
}?,
|
||||
field_name: self.field_name,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ToOwned + ?Sized> FieldPipeline<&T> {
|
||||
fn owned(&self) -> Result<FieldPipeline<T::Owned>, RecipeError> {
|
||||
Ok(FieldPipeline {
|
||||
value: self.value.to_owned(),
|
||||
field_name: self.field_name,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FieldPipeline<T> {
|
||||
fn into_inner(self) -> T {
|
||||
self.value
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
use futures_util::stream::StreamExt;
|
||||
use magnetar_activity_pub::Resolver;
|
||||
use magnetar_core::web_model::content_type::ContentActivityStreams;
|
||||
use reqwest::Client;
|
||||
use serde::Deserialize;
|
||||
use serde_json::Value;
|
||||
use thiserror::Error;
|
||||
use url::Url;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct DereferencingClient {
|
||||
pub client: Client,
|
||||
pub body_limit: usize,
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DereferencingClientBuilderError {
|
||||
#[error("Reqwest error: {0}")]
|
||||
ReqwestError(#[from] reqwest::Error),
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum DereferencingClientError {
|
||||
#[error("Reqwest error: {0}")]
|
||||
ReqwestError(#[from] reqwest::Error),
|
||||
#[error("JSON error: {0}")]
|
||||
JsonError(#[from] serde_json::Error),
|
||||
#[error("Body limit exceeded error")]
|
||||
BodyLimitExceededError,
|
||||
#[error("Invalid URL: {0}")]
|
||||
InvalidUrl(#[from] url::ParseError),
|
||||
#[error("Client error: {0}")]
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl DereferencingClient {
|
||||
pub fn new(
|
||||
force_https: bool,
|
||||
body_limit: usize,
|
||||
) -> Result<DereferencingClient, reqwest::Error> {
|
||||
let client = Client::builder().https_only(force_https).build()?;
|
||||
|
||||
Ok(DereferencingClient { client, body_limit })
|
||||
}
|
||||
|
||||
pub async fn dereference(&self, url: Url) -> Result<Value, DereferencingClientError> {
|
||||
let mut headers = reqwest::header::HeaderMap::new();
|
||||
|
||||
headers.insert(
|
||||
reqwest::header::ACCEPT,
|
||||
reqwest::header::HeaderValue::from_static(ContentActivityStreams.as_ref()),
|
||||
);
|
||||
|
||||
let response = self
|
||||
.client
|
||||
.get(url)
|
||||
.headers(headers)
|
||||
.send()
|
||||
.await
|
||||
.map_err(DereferencingClientError::ReqwestError)?;
|
||||
|
||||
let mut body = response.bytes_stream();
|
||||
|
||||
let mut data = Vec::with_capacity(4096);
|
||||
|
||||
while let Some(buf) = body.next().await {
|
||||
let chunk = buf.map_err(DereferencingClientError::ReqwestError)?;
|
||||
|
||||
if data.len() + chunk.len() > self.body_limit {
|
||||
return Err(DereferencingClientError::BodyLimitExceededError);
|
||||
}
|
||||
|
||||
data.extend_from_slice(&chunk);
|
||||
}
|
||||
|
||||
let json =
|
||||
serde_json::from_slice::<Value>(&data).map_err(DereferencingClientError::JsonError)?;
|
||||
|
||||
Ok(json)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl Resolver for DereferencingClient {
|
||||
type Error = DereferencingClientError;
|
||||
|
||||
async fn resolve<T: for<'a> Deserialize<'a>>(&self, id: &str) -> Result<T, Self::Error> {
|
||||
let url = id.parse().map_err(DereferencingClientError::InvalidUrl)?;
|
||||
|
||||
let json = self.dereference(url).await?;
|
||||
|
||||
serde_json::from_value(json).map_err(DereferencingClientError::JsonError)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,72 @@
|
|||
use axum::http::{HeaderMap, Method};
|
||||
use hyper::client::HttpConnector;
|
||||
use hyper::http::uri;
|
||||
use hyper::{header, Body, Client, Request, Response, Uri};
|
||||
use thiserror::Error;
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum ProxyClientError {
|
||||
#[error("Client error: {0}")]
|
||||
ClientError(String),
|
||||
#[error("URL error: {0}")]
|
||||
UriError(#[from] uri::InvalidUri),
|
||||
#[error("HTTP error: {0}")]
|
||||
HttpError(#[from] axum::http::Error),
|
||||
#[error("Hyper error: {0}")]
|
||||
HyperError(#[from] hyper::Error),
|
||||
}
|
||||
|
||||
pub struct ProxyClient {
|
||||
pub client: Client<HttpConnector, Body>,
|
||||
pub upstream: String,
|
||||
}
|
||||
|
||||
impl ProxyClient {
|
||||
pub fn new(upstream: String) -> ProxyClient {
|
||||
let client = Client::builder().set_host(false).build_http();
|
||||
|
||||
ProxyClient { client, upstream }
|
||||
}
|
||||
|
||||
pub async fn send(
|
||||
&self,
|
||||
host: &str,
|
||||
path: &str,
|
||||
method: Method,
|
||||
body: Body,
|
||||
headers_in: &HeaderMap,
|
||||
) -> Result<Response<Body>, ProxyClientError> {
|
||||
let mut builder = Request::builder();
|
||||
|
||||
let Some(headers) = builder.headers_mut() else {
|
||||
return Err(ProxyClientError::ClientError("No headers".to_owned()));
|
||||
};
|
||||
|
||||
*headers = headers_in.clone();
|
||||
|
||||
headers.insert(
|
||||
header::HOST,
|
||||
host.parse().map_err(|e| {
|
||||
ProxyClientError::ClientError(format!("Invalid header value: {e:?}"))
|
||||
})?,
|
||||
);
|
||||
|
||||
let uri = format!("{}/{}", self.upstream, path)
|
||||
.parse::<Uri>()
|
||||
.map_err(ProxyClientError::UriError)?;
|
||||
|
||||
let request = builder
|
||||
.method(method)
|
||||
.uri(uri)
|
||||
.body(body)
|
||||
.map_err(ProxyClientError::HttpError)?;
|
||||
|
||||
let response = self
|
||||
.client
|
||||
.request(request)
|
||||
.await
|
||||
.map_err(ProxyClientError::HyperError)?;
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
pub mod dereferencing_client;
|
||||
pub mod forwarding_client;
|
|
@ -1,4 +1,5 @@
|
|||
mod api_v1;
|
||||
pub mod client;
|
||||
pub mod model;
|
||||
pub mod nodeinfo;
|
||||
pub mod service;
|
||||
|
|
Loading…
Reference in New Issue