Added basic expansion logic and ability to deserialize single objects into vectors of that type
This commit is contained in:
parent
5d21e028db
commit
7b538c0a0c
|
@ -36,9 +36,9 @@ dependencies = [
|
|||
|
||||
[[package]]
|
||||
name = "async-trait"
|
||||
version = "0.1.57"
|
||||
version = "0.1.58"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f"
|
||||
checksum = "1e805d94e6b5001b651426cf4cd446b1ab5f319d27bab5c644f61de0a804360c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
|
@ -211,6 +211,22 @@ dependencies = [
|
|||
"version_check",
|
||||
]
|
||||
|
||||
[[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.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||
|
||||
[[package]]
|
||||
name = "cpufeatures"
|
||||
version = "0.2.5"
|
||||
|
@ -250,6 +266,15 @@ dependencies = [
|
|||
"subtle",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encoding_rs"
|
||||
version = "0.8.31"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9852635589dc9f9ea1b6fe9f05b50ef208c85c834a562f0c6abb1c475736ec2b"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "failure"
|
||||
version = "0.1.8"
|
||||
|
@ -278,12 +303,22 @@ version = "0.2.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.8.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a7a407cfaa3385c4ae6b23e84623d48c2798d06e3e6a1878f7f59f17b3f86499"
|
||||
dependencies = [
|
||||
"instant",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flabk"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"argon2",
|
||||
"async-trait",
|
||||
"axum",
|
||||
"base-62",
|
||||
"handlebars",
|
||||
|
@ -291,6 +326,7 @@ dependencies = [
|
|||
"mime_guess",
|
||||
"rand",
|
||||
"rand_core",
|
||||
"reqwest",
|
||||
"rust-embed",
|
||||
"serde",
|
||||
"serde_json",
|
||||
|
@ -305,6 +341,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.1.0"
|
||||
|
@ -395,6 +446,25 @@ version = "0.26.2"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
|
||||
|
||||
[[package]]
|
||||
name = "h2"
|
||||
version = "0.3.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f9f29bc9dda355256b2916cf526ab02ce0aeaaaf2bad60d65ef3f12f11dd0f4"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"fnv",
|
||||
"futures-core",
|
||||
"futures-sink",
|
||||
"futures-util",
|
||||
"http",
|
||||
"indexmap",
|
||||
"slab",
|
||||
"tokio",
|
||||
"tokio-util",
|
||||
"tracing",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "handlebars"
|
||||
version = "4.3.3"
|
||||
|
@ -409,6 +479,12 @@ dependencies = [
|
|||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashbrown"
|
||||
version = "0.12.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.1.19"
|
||||
|
@ -477,6 +553,7 @@ dependencies = [
|
|||
"futures-channel",
|
||||
"futures-core",
|
||||
"futures-util",
|
||||
"h2",
|
||||
"http",
|
||||
"http-body",
|
||||
"httparse",
|
||||
|
@ -490,6 +567,54 @@ 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 = "idna"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6"
|
||||
dependencies = [
|
||||
"unicode-bidi",
|
||||
"unicode-normalization",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "1.9.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "10a35a97730320ffe8e2d410b5d3b69279b98d2c14bdb8b70ea89ecf7888d41e"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"hashbrown",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "instant"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ipnet"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "879d54834c8c76457ef4293a689b2a8c59b076067ad77b15efafbb05f92a592b"
|
||||
|
||||
[[package]]
|
||||
name = "itoa"
|
||||
version = "1.0.3"
|
||||
|
@ -519,6 +644,12 @@ dependencies = [
|
|||
"simple_asn1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.132"
|
||||
|
@ -602,6 +733,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 = "num-bigint"
|
||||
version = "0.2.6"
|
||||
|
@ -683,6 +832,51 @@ version = "0.3.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"
|
||||
|
||||
[[package]]
|
||||
name = "openssl"
|
||||
version = "0.10.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "12fc0523e3bd51a692c8850d075d74dc062ccf251c0110668cbd921917118a13"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"cfg-if",
|
||||
"foreign-types",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"openssl-macros",
|
||||
"openssl-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "openssl-macros"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b501e44f11665960c7e7fcf062c7d96a14ade4aa98116c004b2e37b5be7d736c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[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.77"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b03b84c3b2d099b81f0953422b4d4ad58761589d0229b5506356afca05a3670a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"cc",
|
||||
"libc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "parking_lot"
|
||||
version = "0.12.1"
|
||||
|
@ -826,6 +1020,12 @@ version = "0.1.0"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
|
||||
|
||||
[[package]]
|
||||
name = "pkg-config"
|
||||
version = "0.3.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160"
|
||||
|
||||
[[package]]
|
||||
name = "postgres-protocol"
|
||||
version = "0.6.4"
|
||||
|
@ -920,6 +1120,52 @@ dependencies = [
|
|||
"bitflags",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "remove_dir_all"
|
||||
version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reqwest"
|
||||
version = "0.11.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "431949c384f4e2ae07605ccaa56d1d9d2ecdb5cadd4f9577ccfab29f2e5149fc"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"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"
|
||||
|
@ -990,12 +1236,45 @@ dependencies = [
|
|||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "schannel"
|
||||
version = "0.1.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "88d6731146462ea25d9244b2ed5fd1d716d25c52e4d54aa4fb0f3c4e9854dbe2"
|
||||
dependencies = [
|
||||
"lazy_static",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "scopeguard"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
|
||||
|
||||
[[package]]
|
||||
name = "security-framework"
|
||||
version = "2.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2bc1bb97804af6631813c55739f771071e0f2ed33ee20b68c86ec505d906356c"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"core-foundation",
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
"security-framework-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "security-framework-sys"
|
||||
version = "2.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0160a13a177a45bfb43ce71c01580998474f556ad854dcbca936dd2841a5c556"
|
||||
dependencies = [
|
||||
"core-foundation-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.144"
|
||||
|
@ -1177,6 +1456,20 @@ dependencies = [
|
|||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand",
|
||||
"libc",
|
||||
"redox_syscall",
|
||||
"remove_dir_all",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.34"
|
||||
|
@ -1262,6 +1555,16 @@ dependencies = [
|
|||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-native-tls"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7d995660bd2b7f8c1568414c1126076c13fbb725c40112dc0120b78eb9b717b"
|
||||
dependencies = [
|
||||
"native-tls",
|
||||
"tokio",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio-postgres"
|
||||
version = "0.7.7"
|
||||
|
@ -1445,6 +1748,23 @@ version = "0.7.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a"
|
||||
|
||||
[[package]]
|
||||
name = "url"
|
||||
version = "2.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643"
|
||||
dependencies = [
|
||||
"form_urlencoded",
|
||||
"idna",
|
||||
"percent-encoding",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
|
@ -1503,6 +1823,18 @@ dependencies = [
|
|||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fa76fb221a1f8acddf5b54ace85912606980ad661ac7a503b4570ffd3a624dad"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"web-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.82"
|
||||
|
@ -1615,3 +1947,12 @@ name = "windows_x86_64_msvc"
|
|||
version = "0.36.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c811ca4a8c853ef420abd8592ba53ddbbac90410fab6903b3e79972a631f7680"
|
||||
|
||||
[[package]]
|
||||
name = "winreg"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
|
12
Cargo.toml
12
Cargo.toml
|
@ -8,6 +8,7 @@ edition = "2021"
|
|||
[dependencies]
|
||||
anyhow = "1.0.64"
|
||||
argon2 = "0.4.1"
|
||||
async-trait = "0.1.58"
|
||||
axum = "0.5.16"
|
||||
base-62 = "0.1.1"
|
||||
handlebars = "4.3.3"
|
||||
|
@ -15,8 +16,17 @@ jsonwebtoken = "8.1.1"
|
|||
mime_guess = "2.0.4"
|
||||
rand = "0.8.5"
|
||||
rand_core = { version = "0.6.3", features = ["std"] }
|
||||
reqwest = { version = "0.11.12", features = [
|
||||
"__tls",
|
||||
"default-tls",
|
||||
"hyper-tls",
|
||||
"native-tls-crate",
|
||||
"tokio-native-tls",
|
||||
"serde_json",
|
||||
"json",
|
||||
] }
|
||||
rust-embed = "6.4.0"
|
||||
serde = { version = "1.0.144", features = ["derive", "std", "serde_derive"]}
|
||||
serde = { version = "1.0.144", features = ["derive", "std", "serde_derive"] }
|
||||
serde_json = "1.0.85"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
tokio-postgres = { version = "0.7.7", features = ["with-serde_json-1"] }
|
||||
|
|
|
@ -0,0 +1,264 @@
|
|||
use serde::Deserialize;
|
||||
|
||||
pub const CONTEXT_ID: &str = "https://www.w3.org/ns/activitystreams";
|
||||
|
||||
#[derive(Default, Debug, Clone, Deserialize)]
|
||||
pub struct Context {
|
||||
#[serde(rename = "@context")]
|
||||
pub ctx: ContextMap,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Deserialize)]
|
||||
#[serde(rename_all = "PascalCase")]
|
||||
pub struct ContextMap {
|
||||
#[serde(rename = "@vocab")]
|
||||
pub vocab: String,
|
||||
#[serde(rename = "xsd")]
|
||||
pub xsd: String,
|
||||
#[serde(rename = "as")]
|
||||
pub as_field: String,
|
||||
#[serde(rename = "ldp")]
|
||||
pub ldp: String,
|
||||
#[serde(rename = "vcard")]
|
||||
pub vcard: String,
|
||||
#[serde(rename = "id")]
|
||||
pub id: String,
|
||||
#[serde(rename = "type")]
|
||||
pub type_field: String,
|
||||
pub accept: String,
|
||||
pub activity: String,
|
||||
pub intransitive_activity: String,
|
||||
pub add: String,
|
||||
pub announce: String,
|
||||
pub application: String,
|
||||
pub arrive: String,
|
||||
pub article: String,
|
||||
pub audio: String,
|
||||
pub block: String,
|
||||
pub collection: String,
|
||||
pub collection_page: String,
|
||||
pub relationship: String,
|
||||
pub create: String,
|
||||
pub delete: String,
|
||||
pub dislike: String,
|
||||
pub document: String,
|
||||
pub event: String,
|
||||
pub follow: String,
|
||||
pub flag: String,
|
||||
pub group: String,
|
||||
pub ignore: String,
|
||||
pub image: String,
|
||||
pub invite: String,
|
||||
pub join: String,
|
||||
pub leave: String,
|
||||
pub like: String,
|
||||
pub link: String,
|
||||
pub mention: String,
|
||||
pub note: String,
|
||||
pub object: String,
|
||||
pub offer: String,
|
||||
pub ordered_collection: String,
|
||||
pub ordered_collection_page: String,
|
||||
pub organization: String,
|
||||
pub page: String,
|
||||
pub person: String,
|
||||
pub place: String,
|
||||
pub profile: String,
|
||||
pub question: String,
|
||||
pub reject: String,
|
||||
pub remove: String,
|
||||
pub service: String,
|
||||
pub tentative_accept: String,
|
||||
pub tentative_reject: String,
|
||||
pub tombstone: String,
|
||||
pub undo: String,
|
||||
pub update: String,
|
||||
pub video: String,
|
||||
pub view: String,
|
||||
pub listen: String,
|
||||
pub read: String,
|
||||
#[serde(rename = "Move")]
|
||||
pub move_field: String,
|
||||
pub travel: String,
|
||||
pub is_following: String,
|
||||
pub is_followed_by: String,
|
||||
pub is_contact: String,
|
||||
pub is_member: String,
|
||||
#[serde(rename = "subject")]
|
||||
pub subject: Option<TypedField>,
|
||||
#[serde(rename = "relationship")]
|
||||
pub relationship2: Option<TypedField>,
|
||||
#[serde(rename = "actor")]
|
||||
pub actor: Option<TypedField>,
|
||||
#[serde(rename = "attributedTo")]
|
||||
pub attributed_to: Option<TypedField>,
|
||||
#[serde(rename = "attachment")]
|
||||
pub attachment: Option<TypedField>,
|
||||
#[serde(rename = "bcc")]
|
||||
pub bcc: Option<TypedField>,
|
||||
#[serde(rename = "bto")]
|
||||
pub bto: Option<TypedField>,
|
||||
#[serde(rename = "cc")]
|
||||
pub cc: Option<TypedField>,
|
||||
#[serde(rename = "context")]
|
||||
pub context: Option<TypedField>,
|
||||
#[serde(rename = "current")]
|
||||
pub current: Option<TypedField>,
|
||||
#[serde(rename = "first")]
|
||||
pub first: Option<TypedField>,
|
||||
#[serde(rename = "generator")]
|
||||
pub generator: Option<TypedField>,
|
||||
#[serde(rename = "icon")]
|
||||
pub icon: Option<TypedField>,
|
||||
#[serde(rename = "image")]
|
||||
pub image2: Option<TypedField>,
|
||||
#[serde(rename = "inReplyTo")]
|
||||
pub in_reply_to: Option<TypedField>,
|
||||
#[serde(rename = "items")]
|
||||
pub items: Option<TypedField>,
|
||||
#[serde(rename = "instrument")]
|
||||
pub instrument: Option<TypedField>,
|
||||
#[serde(rename = "orderedItems")]
|
||||
pub ordered_items: Option<TypedField>,
|
||||
#[serde(rename = "last")]
|
||||
pub last: Option<TypedField>,
|
||||
#[serde(rename = "location")]
|
||||
pub location: Option<TypedField>,
|
||||
#[serde(rename = "next")]
|
||||
pub next: Option<TypedField>,
|
||||
#[serde(rename = "object")]
|
||||
pub object2: Option<TypedField>,
|
||||
#[serde(rename = "oneOf")]
|
||||
pub one_of: Option<TypedField>,
|
||||
#[serde(rename = "anyOf")]
|
||||
pub any_of: Option<TypedField>,
|
||||
#[serde(rename = "closed")]
|
||||
pub closed: Option<TypedField>,
|
||||
#[serde(rename = "origin")]
|
||||
pub origin: Option<TypedField>,
|
||||
#[serde(rename = "accuracy")]
|
||||
pub accuracy: Option<TypedField>,
|
||||
#[serde(rename = "prev")]
|
||||
pub prev: Option<TypedField>,
|
||||
#[serde(rename = "preview")]
|
||||
pub preview: Option<TypedField>,
|
||||
#[serde(rename = "replies")]
|
||||
pub replies: Option<TypedField>,
|
||||
#[serde(rename = "result")]
|
||||
pub result: Option<TypedField>,
|
||||
#[serde(rename = "audience")]
|
||||
pub audience: Option<TypedField>,
|
||||
#[serde(rename = "partOf")]
|
||||
pub part_of: Option<TypedField>,
|
||||
#[serde(rename = "tag")]
|
||||
pub tag: Option<TypedField>,
|
||||
#[serde(rename = "target")]
|
||||
pub target: Option<TypedField>,
|
||||
#[serde(rename = "to")]
|
||||
pub to: Option<TypedField>,
|
||||
#[serde(rename = "url")]
|
||||
pub url: Option<TypedField>,
|
||||
#[serde(rename = "altitude")]
|
||||
pub altitude: Option<TypedField>,
|
||||
#[serde(rename = "content")]
|
||||
pub content: String,
|
||||
#[serde(rename = "contentMap")]
|
||||
pub content_map: Option<TypedField>,
|
||||
#[serde(rename = "name")]
|
||||
pub name: String,
|
||||
#[serde(rename = "nameMap")]
|
||||
pub name_map: Option<TypedField>,
|
||||
#[serde(rename = "duration")]
|
||||
pub duration: Option<TypedField>,
|
||||
#[serde(rename = "endTime")]
|
||||
pub end_time: Option<TypedField>,
|
||||
#[serde(rename = "height")]
|
||||
pub height: Option<TypedField>,
|
||||
#[serde(rename = "href")]
|
||||
pub href: Option<TypedField>,
|
||||
#[serde(rename = "hreflang")]
|
||||
pub hreflang: String,
|
||||
#[serde(rename = "latitude")]
|
||||
pub latitude: Option<TypedField>,
|
||||
#[serde(rename = "longitude")]
|
||||
pub longitude: Option<TypedField>,
|
||||
#[serde(rename = "mediaType")]
|
||||
pub media_type: String,
|
||||
#[serde(rename = "published")]
|
||||
pub published: Option<TypedField>,
|
||||
#[serde(rename = "radius")]
|
||||
pub radius: Option<TypedField>,
|
||||
#[serde(rename = "rel")]
|
||||
pub rel: String,
|
||||
#[serde(rename = "startIndex")]
|
||||
pub start_index: Option<TypedField>,
|
||||
#[serde(rename = "startTime")]
|
||||
pub start_time: Option<TypedField>,
|
||||
#[serde(rename = "summary")]
|
||||
pub summary: String,
|
||||
#[serde(rename = "summaryMap")]
|
||||
pub summary_map: Option<TypedField>,
|
||||
#[serde(rename = "totalItems")]
|
||||
pub total_items: Option<TypedField>,
|
||||
#[serde(rename = "units")]
|
||||
pub units: String,
|
||||
#[serde(rename = "updated")]
|
||||
pub updated: Option<TypedField>,
|
||||
#[serde(rename = "width")]
|
||||
pub width: Option<TypedField>,
|
||||
#[serde(rename = "describes")]
|
||||
pub describes: Option<TypedField>,
|
||||
#[serde(rename = "formerType")]
|
||||
pub former_type: Option<TypedField>,
|
||||
#[serde(rename = "deleted")]
|
||||
pub deleted: Option<TypedField>,
|
||||
#[serde(rename = "inbox")]
|
||||
pub inbox: Option<TypedField>,
|
||||
#[serde(rename = "outbox")]
|
||||
pub outbox: Option<TypedField>,
|
||||
#[serde(rename = "following")]
|
||||
pub following: Option<TypedField>,
|
||||
#[serde(rename = "followers")]
|
||||
pub followers: Option<TypedField>,
|
||||
#[serde(rename = "streams")]
|
||||
pub streams: Option<TypedField>,
|
||||
#[serde(rename = "preferredUsername")]
|
||||
pub preferred_username: String,
|
||||
#[serde(rename = "endpoints")]
|
||||
pub endpoints: Option<TypedField>,
|
||||
#[serde(rename = "uploadMedia")]
|
||||
pub upload_media: Option<TypedField>,
|
||||
#[serde(rename = "proxyUrl")]
|
||||
pub proxy_url: Option<TypedField>,
|
||||
#[serde(rename = "liked")]
|
||||
pub liked: Option<TypedField>,
|
||||
#[serde(rename = "oauthAuthorizationEndpoint")]
|
||||
pub oauth_authorization_endpoint: Option<TypedField>,
|
||||
#[serde(rename = "oauthTokenEndpoint")]
|
||||
pub oauth_token_endpoint: Option<TypedField>,
|
||||
#[serde(rename = "provideClientKey")]
|
||||
pub provide_client_key: Option<TypedField>,
|
||||
#[serde(rename = "signClientKey")]
|
||||
pub sign_client_key: Option<TypedField>,
|
||||
#[serde(rename = "sharedInbox")]
|
||||
pub shared_inbox: Option<TypedField>,
|
||||
pub public: Option<TypedField>,
|
||||
#[serde(rename = "source")]
|
||||
pub source: String,
|
||||
#[serde(rename = "likes")]
|
||||
pub likes: Option<TypedField>,
|
||||
#[serde(rename = "shares")]
|
||||
pub shares: Option<TypedField>,
|
||||
#[serde(rename = "alsoKnownAs")]
|
||||
pub also_known_as: Option<TypedField>,
|
||||
}
|
||||
|
||||
#[derive(Default, Debug, Clone, Deserialize)]
|
||||
pub struct TypedField {
|
||||
#[serde(rename = "@id")]
|
||||
pub id: String,
|
||||
#[serde(rename = "@type")]
|
||||
pub kind: Option<String>,
|
||||
#[serde(rename = "@container")]
|
||||
pub container: Option<String>,
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
use async_trait::async_trait;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use self::{context::Context, note::Note, resolve::ResolveError, serde_ext::pull_single_into_vec};
|
||||
|
||||
pub mod context;
|
||||
pub mod note;
|
||||
pub mod resolve;
|
||||
mod serde_ext;
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize, Debug)]
|
||||
pub enum ActivityKind {
|
||||
Create,
|
||||
Like,
|
||||
Note,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum ExpandError {
|
||||
InvalidKind(Option<ActivityKind>),
|
||||
NoAttribution,
|
||||
ResolveIRI(String),
|
||||
Other(String),
|
||||
}
|
||||
|
||||
impl From<ResolveError> for ExpandError {
|
||||
fn from(err: ResolveError) -> Self {
|
||||
Self::ResolveIRI(err.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
pub trait ExpandLD<T> {
|
||||
async fn expand(obj: &ObjectLD) -> Result<T, ExpandError>;
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct ActivityLD {
|
||||
#[serde(rename = "@context")]
|
||||
pub context_uri: String,
|
||||
pub kind: ActivityKind,
|
||||
#[serde(rename = "actor")]
|
||||
pub actor_uri: String,
|
||||
#[serde(rename = "to")]
|
||||
pub to_uris: Vec<String>,
|
||||
pub object: Option<ObjectLD>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct ObjectLD {
|
||||
#[serde(rename = "@context")]
|
||||
pub context_uri: Option<String>,
|
||||
pub id: String,
|
||||
#[serde(rename = "type")]
|
||||
pub kind: Option<ActivityKind>,
|
||||
#[serde(rename = "attributedTo")]
|
||||
pub attributed_to: Option<String>,
|
||||
pub published: Option<String>,
|
||||
pub content: Option<String>,
|
||||
pub context: Option<String>,
|
||||
pub conversation: Option<String>,
|
||||
pub url: Option<String>,
|
||||
#[serde(rename = "to")]
|
||||
#[serde(deserialize_with = "pull_single_into_vec")]
|
||||
pub to_uris: Vec<String>,
|
||||
}
|
||||
|
||||
pub enum ActorType {}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Actor {
|
||||
id: String,
|
||||
}
|
||||
|
||||
pub async fn test() {
|
||||
let obj = r#"{
|
||||
"@context": "https://www.w3.org/ns/activitystreams",
|
||||
"attributedTo": "https://localhost/u/test",
|
||||
"content": "honk donk",
|
||||
"context": "data:,electrichonkytonk-2jqQ42HyJXctnBKTy1",
|
||||
"conversation": "data:,electrichonkytonk-2jqQ42HyJXctnBKTy1",
|
||||
"id": "https://localhost/u/test/h/6Q8BFF8W6PZT2ddngZ",
|
||||
"published": "2022-09-30T19:04:45Z",
|
||||
"summary": "",
|
||||
"to": "https://www.w3.org/ns/activitystreams#Public",
|
||||
"type": "Note",
|
||||
"url": "https://localhost/u/test/h/6Q8BFF8W6PZT2ddngZ"
|
||||
}"#;
|
||||
|
||||
let obj = serde_json::from_str::<ObjectLD>(obj).unwrap();
|
||||
let unwrapped = Note::expand(&obj).await.unwrap();
|
||||
println!("{:#?}", &unwrapped);
|
||||
println!("to: {:#?}", obj.to_uris);
|
||||
println!("{}", serde_json::to_string_pretty(&obj).unwrap());
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
use async_trait::async_trait;
|
||||
|
||||
use super::{
|
||||
context::{self, Context},
|
||||
resolve, ActivityKind, Actor, ExpandError, ExpandLD, ObjectLD,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Note {
|
||||
pub id: String,
|
||||
pub content: Option<String>,
|
||||
pub context: Option<String>,
|
||||
pub published_at: Option<String>,
|
||||
pub author: Actor,
|
||||
pub to: Vec<Actor>,
|
||||
pub url: Option<String>,
|
||||
pub conversation: Option<String>,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl ExpandLD<Note> for Note {
|
||||
async fn expand(obj: &ObjectLD) -> Result<Note, ExpandError> {
|
||||
let obj = obj.clone();
|
||||
let resolver = resolve::Resolver::new();
|
||||
if let Some(kind) = obj.kind {
|
||||
if let ActivityKind::Note = kind {
|
||||
Ok(Note {
|
||||
id: obj.id,
|
||||
content: obj.content,
|
||||
published_at: obj.published,
|
||||
author: obj
|
||||
.attributed_to
|
||||
.map(|id| Actor { id })
|
||||
.ok_or(ExpandError::NoAttribution)?,
|
||||
to: obj.to_uris.into_iter().map(|id| Actor { id }).collect(),
|
||||
url: obj.url,
|
||||
context: obj.context,
|
||||
conversation: obj.conversation,
|
||||
})
|
||||
} else {
|
||||
Err(ExpandError::InvalidKind(Some(kind)))
|
||||
}
|
||||
} else {
|
||||
Err(ExpandError::InvalidKind(None))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<ObjectLD> for Note {
|
||||
fn into(self) -> ObjectLD {
|
||||
ObjectLD {
|
||||
context_uri: Some(context::CONTEXT_ID.to_string()),
|
||||
id: self.id.clone(),
|
||||
kind: Some(ActivityKind::Note),
|
||||
attributed_to: Some(self.author.id),
|
||||
published: self.published_at,
|
||||
content: self.content,
|
||||
context: self.context,
|
||||
conversation: self.conversation,
|
||||
url: Some(self.id),
|
||||
to_uris: self.to.into_iter().map(|a| a.id).collect(),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
use std::{future::Future, string::FromUtf8Error};
|
||||
|
||||
use reqwest::{Method, StatusCode};
|
||||
|
||||
const LD_CONTENT_TYPE: &str = "application/ld+json";
|
||||
|
||||
pub(crate) struct ResolveError(pub String);
|
||||
|
||||
impl From<reqwest::Error> for ResolveError {
|
||||
fn from(err: reqwest::Error) -> Self {
|
||||
Self(err.to_string())
|
||||
}
|
||||
}
|
||||
impl From<FromUtf8Error> for ResolveError {
|
||||
fn from(e: FromUtf8Error) -> Self {
|
||||
Self(format!(
|
||||
"invalid schema format (tried utf8): {}",
|
||||
e.to_string()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct Resolver {
|
||||
client: reqwest::Client,
|
||||
}
|
||||
|
||||
impl Resolver {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
client: reqwest::ClientBuilder::new().build().unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
async fn get<Out, F, Fut>(&self, iri: String, ok: F) -> Result<Out, ResolveError>
|
||||
where
|
||||
F: FnOnce(reqwest::Response) -> Fut,
|
||||
Fut: Future<Output = Result<Out, ResolveError>>,
|
||||
{
|
||||
let resp = self
|
||||
.client
|
||||
.request(Method::GET, iri)
|
||||
.header("Accept", LD_CONTENT_TYPE)
|
||||
.send()
|
||||
.await?;
|
||||
|
||||
match resp.status() {
|
||||
StatusCode::OK => Ok(ok(resp).await?),
|
||||
status => Err(ResolveError(format!("non-ok status: {}", status))),
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn resolve_into<'a, T: for<'de> serde::Deserialize<'de>>(
|
||||
&self,
|
||||
iri: String,
|
||||
) -> Result<T, ResolveError> {
|
||||
Ok(self
|
||||
.get(iri, |resp| async { Ok(resp.json().await?) })
|
||||
.await?)
|
||||
}
|
||||
|
||||
pub async fn resolve(&self, iri: String) -> Result<Vec<u8>, ResolveError> {
|
||||
Ok(self
|
||||
.get(iri, |resp| async { Ok(resp.bytes().await?.to_vec()) })
|
||||
.await?)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
use std::{fmt, marker::PhantomData};
|
||||
|
||||
use serde::{de, Deserialize, Deserializer};
|
||||
|
||||
// Allows deserialization of a single item into a vector of that item
|
||||
// As long as they implement the From<String> trait
|
||||
pub(super) fn pull_single_into_vec<'de, D, T>(deserializer: D) -> Result<Vec<T>, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
T: From<String> + serde::Deserialize<'de>,
|
||||
{
|
||||
struct VecComposer<T>(PhantomData<Vec<T>>);
|
||||
|
||||
impl<'de, T> de::Visitor<'de> for VecComposer<T>
|
||||
where
|
||||
T: From<String> + serde::Deserialize<'de>,
|
||||
{
|
||||
type Value = Vec<T>;
|
||||
|
||||
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
|
||||
let name = std::any::type_name::<T>();
|
||||
formatter.write_str(format!("expected {} or Vec<{}>", name, name).as_str())
|
||||
}
|
||||
|
||||
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
|
||||
where
|
||||
E: de::Error,
|
||||
{
|
||||
Ok(vec![value.to_string().into()])
|
||||
}
|
||||
|
||||
fn visit_seq<S>(self, visitor: S) -> Result<Self::Value, S::Error>
|
||||
where
|
||||
S: de::SeqAccess<'de>,
|
||||
{
|
||||
Deserialize::deserialize(de::value::SeqAccessDeserializer::new(visitor))
|
||||
}
|
||||
}
|
||||
|
||||
deserializer.deserialize_any(VecComposer(PhantomData))
|
||||
}
|
30
src/main.rs
30
src/main.rs
|
@ -1,41 +1,17 @@
|
|||
#![feature(let_chains)]
|
||||
mod astreams;
|
||||
mod database;
|
||||
mod sec;
|
||||
mod servek;
|
||||
mod svc;
|
||||
|
||||
use database::db::DB;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use servek::servek::Server;
|
||||
use svc::{auth::Auth, profiles::Profiler};
|
||||
|
||||
#[derive(Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum ActivityKind {
|
||||
Create,
|
||||
Like,
|
||||
Note,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct ActivityLD {
|
||||
pub context_uri: String,
|
||||
pub kind: ActivityKind,
|
||||
pub actor_uri: String,
|
||||
pub to_uris: Vec<String>,
|
||||
pub object: Option<ObjectLD>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct ObjectLD {
|
||||
pub context_uri: String,
|
||||
pub id: Option<String>,
|
||||
pub kind: Option<ActivityKind>,
|
||||
pub attributed_to: Option<String>,
|
||||
pub published: Option<String>,
|
||||
pub content: Option<String>,
|
||||
}
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), anyhow::Error> {
|
||||
astreams::test().await;
|
||||
let db = DB::new(
|
||||
"localhost".to_owned(),
|
||||
"flabk".to_owned(),
|
||||
|
|
Loading…
Reference in New Issue