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