clean up and mainenence, bump dependencies

This commit is contained in:
tezlm 2023-08-16 11:38:29 -07:00
parent 7d1fb9d991
commit 1236c427c1
Signed by: tezlm
GPG key ID: 649733FCD94AFBBA
31 changed files with 446 additions and 372 deletions

280
Cargo.lock generated
View file

@ -52,9 +52,9 @@ dependencies = [
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "1.0.2" version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" checksum = "6748e8def348ed4d14996fa801f4122cd763fff530258cdc03f64b25f89d3a5a"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -121,9 +121,9 @@ dependencies = [
[[package]] [[package]]
name = "anstyle-wincon" name = "anstyle-wincon"
version = "1.0.1" version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "180abfa45703aebe0093f79badacc01b8fd4ea2e35118747e5811127f926e188" checksum = "c677ab05e09154296dd37acecd46420c17b9713e8366facafa8fc0885167cf4c"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"windows-sys", "windows-sys",
@ -135,12 +135,6 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
[[package]]
name = "ascii_table"
version = "4.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75054ce561491263d7b80dc2f6f6c6f8cdfd0c7a7c17c5cf3b8117829fa72ae1"
[[package]] [[package]]
name = "async-recursion" name = "async-recursion"
version = "1.0.4" version = "1.0.4"
@ -149,18 +143,18 @@ checksum = "0e97ce7de6cf12de5d7226c73f5ba9811622f4db3a5b91b55c53e987e5f91cba"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
name = "async-trait" name = "async-trait"
version = "0.1.72" version = "0.1.73"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cc6dde6e4ed435a4c1ee4e73592f5ba9da2151af10076cc04858746af9352d09" checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -186,9 +180,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
[[package]] [[package]]
name = "axum" name = "axum"
version = "0.6.19" version = "0.6.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a6a1de45611fdb535bfde7b7de4fd54f4fd2b17b1737c0a59b69bf9b92074b8c" checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"axum-core", "axum-core",
@ -247,7 +241,7 @@ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -297,9 +291,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.3.3" version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42" checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]] [[package]]
name = "bitpacking" name = "bitpacking"
@ -375,11 +369,12 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.79" version = "1.0.82"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" checksum = "305fe645edc1442a0fa8b6726ba61d422798d37a52e12eaecf4b022ebbb88f01"
dependencies = [ dependencies = [
"jobserver", "jobserver",
"libc",
] ]
[[package]] [[package]]
@ -429,9 +424,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.3.19" version = "4.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5fd304a20bff958a57f04c4e96a2e7594cc4490a0e809cbd48bb6437edaa452d" checksum = "c27cdf28c0f604ba3f512b0c9a409f8de8513e4816705deb0498b627e7c3a3fd"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@ -440,9 +435,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.3.19" version = "4.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01c6a3f08f1fe5662a35cfe393aec09c4df95f60ee93b7556505260f75eee9e1" checksum = "08a9f1ab5e9f01a9b81f202e8562eb9a10de70abf9eaeac1be465c28b75aa4aa"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@ -459,7 +454,7 @@ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -472,14 +467,11 @@ checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
name = "cli" name = "cli"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"ascii_table",
"base64 0.21.2",
"bytes", "bytes",
"clap", "clap",
"colored", "colored",
"ctrlc", "ctrlc",
"dirs", "dirs",
"ed25519-dalek",
"fuser", "fuser",
"humantime", "humantime",
"json-canon", "json-canon",
@ -668,6 +660,15 @@ version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308"
[[package]]
name = "deranged"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7684a49fb1af197853ef7b2ee694bc1f5b4179556f1e5710e1760c5db6f5e929"
dependencies = [
"serde",
]
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.9.0" version = "0.9.0"
@ -783,9 +784,9 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
[[package]] [[package]]
name = "errno" name = "errno"
version = "0.3.1" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" checksum = "6b30f669a7961ef1631673d2766cc92f52d64f7ef354d4fe0ddfd30ed52f0f4f"
dependencies = [ dependencies = [
"errno-dragonfly", "errno-dragonfly",
"libc", "libc",
@ -872,9 +873,9 @@ dependencies = [
[[package]] [[package]]
name = "flate2" name = "flate2"
version = "1.0.26" version = "1.0.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010"
dependencies = [ dependencies = [
"crc32fast", "crc32fast",
"miniz_oxide", "miniz_oxide",
@ -990,7 +991,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -1269,9 +1270,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904"
[[package]] [[package]]
name = "httpdate" name = "httpdate"
version = "1.0.2" version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9"
[[package]] [[package]]
name = "humantime" name = "humantime"
@ -1296,7 +1297,7 @@ dependencies = [
"httpdate", "httpdate",
"itoa", "itoa",
"pin-project-lite", "pin-project-lite",
"socket2", "socket2 0.4.9",
"tokio", "tokio",
"tower-service", "tower-service",
"tracing", "tracing",
@ -1312,7 +1313,7 @@ dependencies = [
"futures-util", "futures-util",
"http", "http",
"hyper", "hyper",
"rustls 0.21.5", "rustls 0.21.6",
"tokio", "tokio",
"tokio-rustls 0.24.1", "tokio-rustls 0.24.1",
] ]
@ -1352,9 +1353,9 @@ dependencies = [
[[package]] [[package]]
name = "image" name = "image"
version = "0.24.6" version = "0.24.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "527909aa81e20ac3a44803521443a765550f09b5130c2c2fa1ea59c2f8f50a3a" checksum = "6f3dfdbdd72063086ff443e297b61695500514b1e41095b6fb9a5ab48a70a711"
dependencies = [ dependencies = [
"bytemuck", "bytemuck",
"byteorder", "byteorder",
@ -1538,9 +1539,9 @@ checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.4.3" version = "0.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09fc20d2ca12cb9f044c93e3bd6d32d523e6e2ec3db4f7b2939cd99026ecd3f0" checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
@ -1554,9 +1555,9 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.19" version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b06a4cde4c0f271a446782e3eff8de789548ce57dbc8eca9292c27f4a42004b4" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]] [[package]]
name = "loom" name = "loom"
@ -1646,9 +1647,9 @@ dependencies = [
[[package]] [[package]]
name = "matchit" name = "matchit"
version = "0.7.0" version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b87248edafb776e59e6ee64a79086f65890d3510f2c656c000bf2a7e8a0aea40" checksum = "ed1202b2a6f884ae56f04cff409ab315c5ce26b5e58d7412e484f01fd52f52ef"
[[package]] [[package]]
name = "md5" name = "md5"
@ -1993,7 +1994,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"proc-macro2-diagnostics", "proc-macro2-diagnostics",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -2042,29 +2043,29 @@ dependencies = [
[[package]] [[package]]
name = "pin-project" name = "pin-project"
version = "1.1.2" version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "030ad2bc4db10a8944cb0d837f158bdfec4d4a4873ab701a95046770d11f8842" checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422"
dependencies = [ dependencies = [
"pin-project-internal", "pin-project-internal",
] ]
[[package]] [[package]]
name = "pin-project-internal" name = "pin-project-internal"
version = "1.1.2" version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec2e072ecce94ec471b13398d5402c188e76ac03cf74dd1a975161b23a3f6d9c" checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.10" version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4c40d25201921e5ff0c862a505c6557ea88568a4e3ace775ab55e93f2f4f9d57" checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05"
[[package]] [[package]]
name = "pin-utils" name = "pin-utils"
@ -2120,7 +2121,7 @@ checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
"version_check", "version_check",
"yansi", "yansi",
] ]
@ -2267,13 +2268,13 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.9.1" version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" checksum = "81bc1d4caf89fac26a70747fe603c130093b53c773888797a6329091246d651a"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
"regex-automata 0.3.3", "regex-automata 0.3.6",
"regex-syntax 0.7.4", "regex-syntax 0.7.4",
] ]
@ -2288,9 +2289,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.3.3" version = "0.3.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39354c10dd07468c2e73926b23bb9c2caca74c5501e38a35da70406f1d923310" checksum = "fed1ceff11a1dddaee50c9dc8e4938bd106e9d89ae372f192311e7da498e3b69"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -2332,7 +2333,7 @@ dependencies = [
"once_cell", "once_cell",
"percent-encoding", "percent-encoding",
"pin-project-lite", "pin-project-lite",
"rustls 0.21.5", "rustls 0.21.6",
"rustls-pemfile", "rustls-pemfile",
"serde", "serde",
"serde_json", "serde_json",
@ -2387,11 +2388,11 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.38.4" version = "0.38.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0a962918ea88d644592894bc6dc55acc6c0956488adcebbfb6e273506b7fd6e5" checksum = "19ed4fa021d81c8392ce04db050a3da9a60299050b7ae1cf482d862b54a7218f"
dependencies = [ dependencies = [
"bitflags 2.3.3", "bitflags 2.4.0",
"errno", "errno",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
@ -2412,9 +2413,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls" name = "rustls"
version = "0.21.5" version = "0.21.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79ea77c539259495ce8ca47f53e66ae0330a8819f67e23ac96ca02f50e7b7d36" checksum = "1d1feddffcfcc0b33f5c6ce9a29e341e4cd59c3f78e7ee45f4a40c038b1d6cbb"
dependencies = [ dependencies = [
"log", "log",
"ring", "ring",
@ -2433,9 +2434,9 @@ dependencies = [
[[package]] [[package]]
name = "rustls-webpki" name = "rustls-webpki"
version = "0.101.2" version = "0.101.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "513722fd73ad80a71f72b61009ea1b584bcfa1483ca93949c8f290298837fa59" checksum = "261e9e0888cba427c3316e6322805653c9425240b6fd96cee7cb671ab70ab8d0"
dependencies = [ dependencies = [
"ring", "ring",
"untrusted", "untrusted",
@ -2483,9 +2484,9 @@ dependencies = [
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.177" version = "1.0.183"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "63ba2516aa6bf82e0b19ca8b50019d52df58455d3cf9bdaf6315225fdd0c560a" checksum = "32ac8da02677876d532745a130fc9d8e6edfa81a269b107c5b00829b91d8eb3c"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -2503,20 +2504,20 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.177" version = "1.0.183"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "401797fe7833d72109fedec6bfcbe67c0eed9b99772f26eb8afd261f0abc6fd3" checksum = "aafe972d60b0b9bee71a91b92fee2d4fb3c9d7e8f6b179aa99f27203d99a4816"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.104" version = "1.0.105"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "076066c5f1078eac5b722a31827a8832fe108bed65dfa75e233c89f8206e976c" checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
dependencies = [ dependencies = [
"itoa", "itoa",
"ryu", "ryu",
@ -2560,8 +2561,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"async-recursion", "async-recursion",
"axum", "axum",
"base64 0.21.2", "bitflags 2.4.0",
"bitflags 2.3.3",
"bytes", "bytes",
"clap", "clap",
"epub", "epub",
@ -2632,9 +2632,9 @@ dependencies = [
[[package]] [[package]]
name = "sha2-asm" name = "sha2-asm"
version = "0.6.2" version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf27176fb5d15398e3a479c652c20459d9dac830dedd1fa55b42a77dbcdbfcea" checksum = "f27ba7066011e3fb30d808b51affff34f0a66d3a03a58edd787c6e420e40e44e"
dependencies = [ dependencies = [
"cc", "cc",
] ]
@ -2709,6 +2709,16 @@ dependencies = [
"winapi", "winapi",
] ]
[[package]]
name = "socket2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
dependencies = [
"libc",
"windows-sys",
]
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.5.2" version = "0.5.2"
@ -2841,9 +2851,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
name = "store-fs" name = "store-fs"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"async-trait",
"axum", "axum",
"flume",
"futures-util", "futures-util",
"serde", "serde",
"serde_json", "serde_json",
@ -2915,9 +2923,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.27" version = "2.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b60f673f44a8255b9c8c657daf66a596d435f2da81a555b06dc644d080ba45e0" checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -3075,9 +3083,9 @@ dependencies = [
[[package]] [[package]]
name = "tempfile" name = "tempfile"
version = "3.7.0" version = "3.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5486094ee78b2e5038a6382ed7645bc084dc2ec433426ca4c3cb61e2007b8998" checksum = "dc02fddf48964c42031a0b3fe0428320ecf3a73c401040fc0096f97794310651"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"fastrand", "fastrand",
@ -3099,22 +3107,22 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.44" version = "1.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" checksum = "d9207952ae1a003f42d3d5e892dac3c6ba42aa6ac0c79a6a91a2b5cb4253e75c"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.44" version = "1.0.46"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" checksum = "f1728216d3244de4f14f14f8c15c79be1a7c67867d28d69b719690e2a19fb445"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -3129,9 +3137,9 @@ dependencies = [
[[package]] [[package]]
name = "tiff" name = "tiff"
version = "0.8.1" version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7449334f9ff2baf290d55d73983a7d6fa15e01198faef72af07e2a8db851e471" checksum = "6d172b0f4d3fba17ba89811858b9d3d97f928aece846475bbda076ca46736211"
dependencies = [ dependencies = [
"flate2", "flate2",
"jpeg-decoder", "jpeg-decoder",
@ -3140,10 +3148,11 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.23" version = "0.3.25"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "59e399c068f43a5d116fedaf73b203fa4f9c519f17e2b34f63221d3792f81446" checksum = "b0fdd63d58b18d663fbdf70e049f00a22c8e42be082203be7f26589213cd75ea"
dependencies = [ dependencies = [
"deranged",
"itoa", "itoa",
"serde", "serde",
"time-core", "time-core",
@ -3158,9 +3167,9 @@ checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
[[package]] [[package]]
name = "time-macros" name = "time-macros"
version = "0.2.10" version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96ba15a897f3c86766b757e5ac7221554c6750054d74d5b28844fce5fb36a6c4" checksum = "eb71511c991639bb078fd5bf97757e03914361c48100d52878b8e52b46fb92cd"
dependencies = [ dependencies = [
"time-core", "time-core",
] ]
@ -3182,11 +3191,10 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.29.1" version = "1.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" checksum = "40de3a2ba249dcb097e01be5e67a5ff53cf250397715a071a81543e8a832a920"
dependencies = [ dependencies = [
"autocfg",
"backtrace", "backtrace",
"bytes", "bytes",
"libc", "libc",
@ -3194,7 +3202,7 @@ dependencies = [
"num_cpus", "num_cpus",
"pin-project-lite", "pin-project-lite",
"signal-hook-registry", "signal-hook-registry",
"socket2", "socket2 0.5.3",
"tokio-macros", "tokio-macros",
"windows-sys", "windows-sys",
] ]
@ -3207,7 +3215,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -3227,7 +3235,7 @@ version = "0.24.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081"
dependencies = [ dependencies = [
"rustls 0.21.5", "rustls 0.21.6",
"tokio", "tokio",
] ]
@ -3244,9 +3252,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio-tungstenite" name = "tokio-tungstenite"
version = "0.19.0" version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec509ac96e9a0c43427c74f003127d953a265737636129424288d27cb5c4b12c" checksum = "2b2dbec703c26b00d74844519606ef15d09a7d6857860f84ad223dec002ddea2"
dependencies = [ dependencies = [
"futures-util", "futures-util",
"log", "log",
@ -3324,7 +3332,7 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55ae70283aba8d2a8b411c695c437fe25b8b5e44e23e780662002fc72fb47a82" checksum = "55ae70283aba8d2a8b411c695c437fe25b8b5e44e23e780662002fc72fb47a82"
dependencies = [ dependencies = [
"bitflags 2.3.3", "bitflags 2.4.0",
"bytes", "bytes",
"futures-core", "futures-core",
"futures-util", "futures-util",
@ -3370,7 +3378,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -3420,9 +3428,9 @@ checksum = "3528ecfd12c466c6f163363caf2d02a71161dd5e1cc6ae7b34207ea2d42d81ed"
[[package]] [[package]]
name = "tungstenite" name = "tungstenite"
version = "0.19.0" version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15fba1a6d6bb030745759a9a2a588bfe8490fc8b4751a277db3a0be1c9ebbf67" checksum = "e862a1c4128df0112ab625f55cd5c934bcb4312ba80b39ae4b4835a3fd58e649"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"bytes", "bytes",
@ -3629,7 +3637,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -3663,7 +3671,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -3751,9 +3759,9 @@ dependencies = [
[[package]] [[package]]
name = "windows-targets" name = "windows-targets"
version = "0.48.1" version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05d4b17490f70499f20b9e791dcf6a299785ce8af4d709018206dc5b4953e95f" checksum = "d1eeca1c172a285ee6c2c84c341ccea837e7c01b12fbb2d0fe3c9e550ce49ec8"
dependencies = [ dependencies = [
"windows_aarch64_gnullvm", "windows_aarch64_gnullvm",
"windows_aarch64_msvc", "windows_aarch64_msvc",
@ -3766,51 +3774,51 @@ dependencies = [
[[package]] [[package]]
name = "windows_aarch64_gnullvm" name = "windows_aarch64_gnullvm"
version = "0.48.0" version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" checksum = "b10d0c968ba7f6166195e13d593af609ec2e3d24f916f081690695cf5eaffb2f"
[[package]] [[package]]
name = "windows_aarch64_msvc" name = "windows_aarch64_msvc"
version = "0.48.0" version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" checksum = "571d8d4e62f26d4932099a9efe89660e8bd5087775a2ab5cdd8b747b811f1058"
[[package]] [[package]]
name = "windows_i686_gnu" name = "windows_i686_gnu"
version = "0.48.0" version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" checksum = "2229ad223e178db5fbbc8bd8d3835e51e566b8474bfca58d2e6150c48bb723cd"
[[package]] [[package]]
name = "windows_i686_msvc" name = "windows_i686_msvc"
version = "0.48.0" version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" checksum = "600956e2d840c194eedfc5d18f8242bc2e17c7775b6684488af3a9fff6fe3287"
[[package]] [[package]]
name = "windows_x86_64_gnu" name = "windows_x86_64_gnu"
version = "0.48.0" version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" checksum = "ea99ff3f8b49fb7a8e0d305e5aec485bd068c2ba691b6e277d29eaeac945868a"
[[package]] [[package]]
name = "windows_x86_64_gnullvm" name = "windows_x86_64_gnullvm"
version = "0.48.0" version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" checksum = "8f1a05a1ece9a7a0d5a7ccf30ba2c33e3a61a30e042ffd247567d1de1d94120d"
[[package]] [[package]]
name = "windows_x86_64_msvc" name = "windows_x86_64_msvc"
version = "0.48.0" version = "0.48.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" checksum = "d419259aba16b663966e29e6d7c6ecfa0bb8425818bb96f6f1f3c3eb71a6e7b9"
[[package]] [[package]]
name = "winnow" name = "winnow"
version = "0.5.3" version = "0.5.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f46aab759304e4d7b2075a9aecba26228bb073ee8c50db796b2c72c676b5d807" checksum = "1e461589e194280efaa97236b73623445efa195aa633fd7004f39805707a9d53"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
@ -3843,15 +3851,15 @@ dependencies = [
[[package]] [[package]]
name = "yansi" name = "yansi"
version = "1.0.0-rc" version = "1.0.0-rc.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ee746ad3851dd3bc40e4a028ab3b00b99278d929e48957bcb2d111874a7e43e" checksum = "1367295b8f788d371ce2dbc842c7b709c73ee1364d30351dd300ec2203b12377"
[[package]] [[package]]
name = "zerocopy" name = "zerocopy"
version = "0.6.1" version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "332f188cc1bcf1fe1064b8c58d150f497e697f49774aa846f2dc949d9a25f236" checksum = "f3b9c234616391070b0b173963ebc65a9195068e7ed3731c6edac2ec45ebe106"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"zerocopy-derive", "zerocopy-derive",
@ -3859,13 +3867,13 @@ dependencies = [
[[package]] [[package]]
name = "zerocopy-derive" name = "zerocopy-derive"
version = "0.3.2" version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6505e6815af7de1746a08f69c69606bb45695a17149517680f3b2149713b19a3" checksum = "8f7f3a471f98d0a61c34322fbbfd10c384b07687f680d4119813713f72308d91"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 1.0.109", "syn 2.0.28",
] ]
[[package]] [[package]]
@ -3885,7 +3893,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.27", "syn 2.0.28",
] ]
[[package]] [[package]]

View file

@ -6,14 +6,11 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
ascii_table = "4.0.2"
base64 = "0.21.2"
bytes = "1.4.0" bytes = "1.4.0"
clap = { version = "4.3.11", features = ["derive"] } clap = { version = "4.3.11", features = ["derive"] }
colored = "2.0.4" colored = "2.0.4"
ctrlc = "3.4.0" ctrlc = "3.4.0"
dirs = "5.0.1" dirs = "5.0.1"
ed25519-dalek = "1.0.1"
fuser = "0.12.0" fuser = "0.12.0"
humantime = "2.1.0" humantime = "2.1.0"
json-canon = "0.1.3" json-canon = "0.1.3"

View file

@ -112,6 +112,8 @@ pub struct ActorEvent {
pub name: String, pub name: String,
#[serde(rename = "type")] #[serde(rename = "type")]
pub actor_type: ActorType, pub actor_type: ActorType,
#[serde(flatten)]
pub _other: HashMap<String, Value>,
} }
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)] #[derive(Debug, Serialize, Deserialize, Clone, PartialEq, Eq)]

View file

@ -8,7 +8,6 @@ edition = "2021"
[dependencies] [dependencies]
async-recursion = "1.0.4" async-recursion = "1.0.4"
axum = { version = "0.6.18", features = ["macros", "headers", "ws"] } axum = { version = "0.6.18", features = ["macros", "headers", "ws"] }
base64 = "0.21.2"
bitflags = "2.3.3" bitflags = "2.3.3"
bytes = "1.4.0" bytes = "1.4.0"
clap = { version = "4.3.14", features = ["derive"] } clap = { version = "4.3.14", features = ["derive"] }
@ -31,7 +30,7 @@ serde = { version = "1.0.164", features = ["derive"] }
serde-aux = "4.2.0" serde-aux = "4.2.0"
serde_json = "1.0.97" serde_json = "1.0.97"
sha2 = { version = "0.10.7", features = ["asm"] } sha2 = { version = "0.10.7", features = ["asm"] }
sqlx = { version = "0.6.3", features = ["sqlite", "runtime-tokio-rustls", "offline"] } sqlx = { version = "0.6.3", features = ["sqlite", "runtime-tokio-rustls"] }
tantivy = "0.20.2" tantivy = "0.20.2"
thiserror = "1.0.40" thiserror = "1.0.40"
tokio = { version = "1.28.2", features = ["rt-multi-thread", "macros", "process"] } tokio = { version = "1.28.2", features = ["rt-multi-thread", "macros", "process"] }

View file

@ -80,26 +80,31 @@ impl Client {
Ok(res.item_ref) Ok(res.item_ref)
} }
pub async fn get(&self, item_ref: &ItemRef) -> Result<Item, Error> { pub async fn get(&self, item_ref: &ItemRef) -> Result<Option<Item>, Error> {
debug!("get blob"); debug!("get blob");
let req = self let req = self
.http .http
.get(format!("{}/blobs/{}", self.base_url, item_ref)) .get(format!("{}/blobs/{}", self.base_url, item_ref))
.send() .send()
.await? .await?;
if req.status() == StatusCode::NOT_FOUND {
return Ok(None);
}
let bytes = req
.error_for_status()? .error_for_status()?
.bytes() .bytes()
.await?; .await?;
Item::from_bytes(req) Ok(Some(Item::from_bytes(bytes)?))
} }
pub async fn get_via(&self, item_ref: &ItemRef, via: &str) -> Result<Item, Error> { pub async fn get_via(&self, item_ref: &ItemRef, via: &str) -> Result<Option<Item>, Error> {
debug!("get blob through server {}", via); debug!("get blob through server {}", via);
let url = format!("http://{}/things/{}", via, item_ref); let url = format!("http://{}/things/{}", via, item_ref);
trace!("target url: {}", url); trace!("target url: {}", url);
let req = match self.http.get(url).send().await? { let req = match self.http.get(url).send().await? {
req if req.status() == StatusCode::GONE => req, req if req.status() == StatusCode::GONE => req,
req if req.status() == StatusCode::NOT_MODIFIED => return Ok(None),
req => req.error_for_status()?, req => req.error_for_status()?,
}; };
let header = req let header = req
@ -127,6 +132,6 @@ impl Client {
return Err(Error::Validation("server gave an invalid hash")); return Err(Error::Validation("server gave an invalid hash"));
} }
Ok(item) Ok(Some(item))
} }
} }

View file

@ -3,6 +3,7 @@ use axum::http::StatusCode;
use axum::response::IntoResponse; use axum::response::IntoResponse;
use serde_json::json; use serde_json::json;
use tracing::error; use tracing::error;
use ufh::item::ItemRef;
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum Error { pub enum Error {
@ -12,8 +13,8 @@ pub enum Error {
Json(serde_json::Error), Json(serde_json::Error),
#[error("{0}")] #[error("{0}")]
Database(sqlx::Error), Database(sqlx::Error),
#[error("not found")] #[error("{0} not found")]
NotFound, NotFound(String),
#[error("{0}")] #[error("{0}")]
Image(image::ImageError), Image(image::ImageError),
#[error("{1}")] #[error("{1}")]
@ -35,8 +36,11 @@ pub enum Error {
impl From<reqwest::Error> for Error { impl From<reqwest::Error> for Error {
fn from(err: reqwest::Error) -> Self { fn from(err: reqwest::Error) -> Self {
if err.status().is_some_and(|code| code == StatusCode::NOT_FOUND) { if err
Error::NotFound .status()
.is_some_and(|code| code == StatusCode::NOT_FOUND)
{
Error::NotFound(err.url().expect("404 error should have a url").to_string())
} else { } else {
Error::Reqwest(err) Error::Reqwest(err)
} }
@ -52,7 +56,7 @@ impl From<serde_json::Error> for Error {
impl From<sqlx::Error> for Error { impl From<sqlx::Error> for Error {
fn from(err: sqlx::Error) -> Self { fn from(err: sqlx::Error) -> Self {
match err { match err {
sqlx::Error::RowNotFound => Error::NotFound, sqlx::Error::RowNotFound => Error::NotFound("row".into()),
err => Error::Database(err), err => Error::Database(err),
} }
} }
@ -116,7 +120,7 @@ impl Error {
sqlx::Error::RowNotFound => unreachable!(), sqlx::Error::RowNotFound => unreachable!(),
_ => StatusCode::INTERNAL_SERVER_ERROR, _ => StatusCode::INTERNAL_SERVER_ERROR,
}, },
Error::NotFound => StatusCode::NOT_FOUND, Error::NotFound(_) => StatusCode::NOT_FOUND,
Error::Image(_) => StatusCode::UNSUPPORTED_MEDIA_TYPE, Error::Image(_) => StatusCode::UNSUPPORTED_MEDIA_TYPE,
Error::Validation(_) => StatusCode::BAD_REQUEST, Error::Validation(_) => StatusCode::BAD_REQUEST,
Error::ItemRefParse(_) => StatusCode::BAD_REQUEST, Error::ItemRefParse(_) => StatusCode::BAD_REQUEST,
@ -127,4 +131,9 @@ impl Error {
Error::Http(status, _) => *status, Error::Http(status, _) => *status,
} }
} }
#[inline]
pub fn no_ref(item_ref: &ItemRef) -> Error {
Error::NotFound(format!("ref {}", item_ref))
}
} }

View file

@ -23,12 +23,15 @@ type Relations = HashMap<ItemRef, (Event, RelInfo)>;
pub async fn get_relations(db: &Sqlite, event: &Event) -> Result<Relations, Error> { pub async fn get_relations(db: &Sqlite, event: &Event) -> Result<Relations, Error> {
// get/validate relations // get/validate relations
let rel_ids: Vec<_> = event.relations.keys().cloned().collect(); let rel_ids: Vec<_> = event.relations.keys().cloned().collect();
let rel_events = db.bulk_fetch(&rel_ids, false).await?; let rel_events = db.bulk_fetch(&rel_ids).await?;
if rel_events.iter().any(|i| i.1.is_none()) {
return Err(Error::Validation("one or more chunk items doesn't exist"));
}
rel_events rel_events
.into_iter() .into_iter()
.map(|(item_ref, item)| { .map(|(item_ref, item)| {
let rel_info = &event.relations[&item_ref]; let rel_info = &event.relations[&item_ref];
match item { match item.unwrap() {
DbItem::Event(event) => Ok((item_ref, (*event, rel_info.clone()))), DbItem::Event(event) => Ok((item_ref, (*event, rel_info.clone()))),
DbItem::Blob(_) => Err(Error::Validation( DbItem::Blob(_) => Err(Error::Validation(
"some relations are to blobs instead of events", "some relations are to blobs instead of events",
@ -53,7 +56,7 @@ pub async fn prepare_special(
match &event.content { match &event.content {
EventContent::Actor(_) => { EventContent::Actor(_) => {
let query = ufh::query::Query::builder() let query = ufh::query::Query::builder()
.with_type("x.user") .with_type("x.actor")
.with_sender(&event.sender) .with_sender(&event.sender)
.build(); .build();
let result = me.db.query_events(&query, Location::Beginning, 1).await?; let result = me.db.query_events(&query, Location::Beginning, 1).await?;
@ -62,14 +65,13 @@ pub async fn prepare_special(
} }
}, },
EventContent::File(f) => { EventContent::File(f) => {
match me.db.bulk_fetch(&f.chunks, false).await { let items = me.db.bulk_fetch(&f.chunks).await?;
Ok(items) if items.iter().all(|i| matches!(i, (_, DbItem::Blob(_)))) => Ok(()), if items.iter().any(|i| i.1.is_none()) {
Ok(_) => Err(Error::Validation("one or more chunk items isn't a blob")), return Err(Error::Validation("one or more chunk items doesn't exist"));
Err(Error::NotFound) => { }
Err(Error::Validation("one or more chunk items doesn't exist")) if items.iter().any(|i| !matches!(i, (_, Some(DbItem::Blob(_))))) {
} return Err(Error::Validation("one or more chunk items isn't a blob"));
Err(err) => Err(err), }
}?;
} }
EventContent::Redact(_) => { EventContent::Redact(_) => {
if event.relations.is_empty() { if event.relations.is_empty() {

View file

@ -1,22 +1,23 @@
use crate::{ use crate::{
blobs, blobs,
items::events::update_search_index, items::events::update_search_index,
peer::{Contact, NodeId, RPCRequest, RPCResponse},
perms::can_send_event, perms::can_send_event,
routes::things::{thumbnail::ThumbnailSize, Error}, routes::things::{thumbnail::ThumbnailSize, Error},
state::{ state::{
db::{sqlite::Sqlite, Database}, db::{sqlite::Sqlite, Database},
search::tantivy::Tantivy, search::tantivy::Tantivy,
}, },
Relations, peer::{NodeId, Contact, RPCResponse, RPCRequest}, P2PState, P2PState, Relations,
}; };
use axum::http::StatusCode; use axum::http::StatusCode;
use bytes::Bytes; use bytes::Bytes;
use events::DelayedAction; use events::DelayedAction;
use lru::LruCache; use lru::LruCache;
use once_cell::sync::OnceCell; use once_cell::sync::OnceCell;
use std::{num::NonZeroUsize, sync::Arc, collections::HashSet}; use std::{collections::HashSet, num::NonZeroUsize, sync::Arc};
use tokio::sync::RwLock; use tokio::sync::RwLock;
use tracing::{trace, debug, info, error}; use tracing::{debug, error, info, trace};
use ufh::{ use ufh::{
derived::Derived, derived::Derived,
event::{Event, EventContent, WipEvent}, event::{Event, EventContent, WipEvent},
@ -25,6 +26,9 @@ use ufh::{
pub mod events; pub mod events;
// TODO: make this tuneable via config file
const CACHE_SIZE: usize = 100;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
#[allow(clippy::large_enum_variant)] #[allow(clippy::large_enum_variant)]
pub enum Item { pub enum Item {
@ -124,7 +128,7 @@ impl Items {
#[async_recursion::async_recursion] #[async_recursion::async_recursion]
pub async fn commit_event_create(&self, wip: WipCreate) -> Result<DerivelessCreate, Error> { pub async fn commit_event_create(&self, wip: WipCreate) -> Result<DerivelessCreate, Error> {
let event = wip.event; let event = wip.event;
let rowid = self.db.event_create(&event).await?; let rowid = self.db.event_create(&event).await?;
debug!("created event (rowid={})", rowid); debug!("created event (rowid={})", rowid);
@ -133,7 +137,11 @@ impl Items {
debug!("commit special cases"); debug!("commit special cases");
} }
Ok(DerivelessCreate { item_ref: wip.item_ref, rowid, event }) Ok(DerivelessCreate {
item_ref: wip.item_ref,
rowid,
event,
})
} }
/// finish extra processing, eg. deriving metadata or indexing for fts /// finish extra processing, eg. deriving metadata or indexing for fts
@ -164,14 +172,21 @@ impl Items {
Derived::default() Derived::default()
}; };
let event = Event { derived: derived.clone(), ..event }; let event = Event {
derived: derived.clone(),
..event
};
// TODO (performance): this exists to get the updated event derives, but could easily be done without a query // TODO (performance): this exists to get the updated event derives, but could easily be done without a query
let relations = events::get_relations(&self.db, &event).await?; let relations = events::get_relations(&self.db, &event).await?;
update_search_index(self, &event, &relations).await?; update_search_index(self, &event, &relations).await?;
Ok(Create { event, relations, rowid: wip.rowid }) Ok(Create {
event,
relations,
rowid: wip.rowid,
})
} }
pub async fn create_event(&self, wip: WipEvent) -> Result<Create, Error> { pub async fn create_event(&self, wip: WipEvent) -> Result<Create, Error> {
@ -189,82 +204,81 @@ impl Items {
} }
#[tracing::instrument(skip_all, fields(item_ref))] #[tracing::instrument(skip_all, fields(item_ref))]
pub async fn get(&self, item_ref: &ItemRef) -> Result<Item, Error> { pub async fn get(&self, item_ref: &ItemRef) -> Result<Option<Item>, Error> {
static CACHE: OnceCell<RwLock<LruCache<ItemRef, Item>>> = OnceCell::new(); static CACHE: OnceCell<RwLock<LruCache<ItemRef, Item>>> = OnceCell::new();
// let mut cache = CACHE.get_or_init(|| Mutex::new(LruCache::new(NonZeroUsize::new(100).unwrap()))).lock().await;
let cache = CACHE let cache = CACHE
.get_or_init(|| RwLock::new(LruCache::new(NonZeroUsize::new(1).unwrap()))) .get_or_init(|| RwLock::new(LruCache::new(NonZeroUsize::new(CACHE_SIZE).unwrap())));
.read() let cached = cache.read().await.peek(item_ref).cloned();
.await;
let cached = cache.peek(item_ref).cloned();
drop(cache);
match cached { match cached {
Some(item) => { Some(item) => {
CACHE.get().expect("already init").write().await.promote(item_ref); cache.write().await.promote(item_ref);
Ok(item) Ok(Some(item))
} }
None => { None => {
let item = self.get_uncached(item_ref).await?; let Some(item) = self.get_uncached(item_ref).await? else {
CACHE.get().expect("already init").write().await.put(item_ref.clone(), item.clone()); return Ok(None);
Ok(item) };
cache.write().await.put(item_ref.clone(), item.clone());
Ok(Some(item))
} }
} }
} }
async fn get_uncached(&self, item_ref: &ItemRef) -> Result<Item, Error> { // TODO (future, maybe): batch lookup requests per bucket
// this only makes sense when you have a lot of requests concerning one bucket at once
async fn get_uncached(&self, item_ref: &ItemRef) -> Result<Option<Item>, Error> {
tracing::Span::current().record("item_ref", item_ref.to_string()); tracing::Span::current().record("item_ref", item_ref.to_string());
if let Some(item) = self.db.event_fetch(item_ref).await? { if let Some(item) = self.db.event_fetch(item_ref).await? {
return Ok(Item::Event(item)); return Ok(Some(Item::Event(item)));
} }
match self.blobs.get(item_ref).await { match self.blobs.get(item_ref).await {
Ok(blobs::Item::WipEvent(wip)) => { Ok(Some(blobs::Item::WipEvent(wip))) => {
debug!("event didn't exist in db, re-adding"); debug!("event didn't exist in db, re-adding");
return self.import_event(wip).await; return Ok(Some(self.import_event(wip).await?));
} }
Ok(blobs::Item::Raw(bytes)) => { Ok(Some(blobs::Item::Raw(bytes))) => {
// make sure the blob is in db // make sure the blob is in db
// TODO (performance): remove this // TODO (performance): remove this
debug!("re-inserting into db"); debug!("re-inserting into db");
self.db.create_blob(item_ref, bytes.len() as u32).await?; self.db.create_blob(item_ref, bytes.len() as u32).await?;
return Ok(Item::Blob(bytes)); return Ok(Some(Item::Blob(bytes)));
}, }
Err(Error::NotFound) => { Ok(None) => trace!("not found"),
trace!("not found");
},
Err(err) => { Err(err) => {
error!("blobs::get failed: {}", err); error!("blobs::get failed: {}", err);
return Err(err) return Err(err);
} }
}; };
for hoster in find_hosters(&self.p2p, &NodeId::new_from_ref(item_ref)).await { for hoster in find_hosters(&self.p2p, &NodeId::new_from_ref(item_ref)).await {
trace!("importing item from (host={})", hoster.host); trace!("importing item from (host={})", hoster.host);
match self.blobs.get_via(item_ref, &hoster.host).await { match self.blobs.get_via(item_ref, &hoster.host).await {
Ok(blobs::Item::WipEvent(wip)) => { Ok(Some(blobs::Item::WipEvent(wip))) => {
debug!("importing event from other server"); debug!("importing event from other server");
return self.import_event(wip).await; return Ok(Some(self.import_event(wip).await?));
}, }
Ok(blobs::Item::Raw(bytes)) => { Ok(Some(blobs::Item::Raw(bytes))) => {
debug!("pulled new blob (size={})", bytes.len()); debug!("pulled new blob (size={})", bytes.len());
self.blobs.put(blobs::Item::Raw(bytes.clone())).await?; self.blobs.put(blobs::Item::Raw(bytes.clone())).await?;
self.db.create_blob(item_ref, bytes.len() as u32).await?; self.db.create_blob(item_ref, bytes.len() as u32).await?;
return Ok(Item::Blob(bytes)); return Ok(Some(Item::Blob(bytes)));
}, }
Err(Error::NotFound) => { Ok(None) => {
trace!("target item not found"); trace!("target item not found");
}, }
Err(Error::Reqwest(err)) if err.status().is_some_and(|s| s.is_client_error()) => { Err(Error::Reqwest(err)) if err.status().is_some_and(|s| s.is_client_error()) => {
debug!("couldn't fetch from other server: {}", err); debug!("couldn't fetch from other server: {}", err);
return Err(err.into()); return Err(err.into());
}, }
Err(_) => (), Err(_) => (),
}; };
} }
trace!("item not found"); trace!("item not found");
return Err(Error::NotFound); // TODO: cache `None`s
Ok(None)
} }
#[async_recursion::async_recursion] #[async_recursion::async_recursion]
@ -295,10 +309,10 @@ impl Items {
#[tracing::instrument(skip_all, fields(key))] #[tracing::instrument(skip_all, fields(key))]
async fn find_hosters(p2p: &P2PState, key: &NodeId) -> Vec<Contact> { async fn find_hosters(p2p: &P2PState, key: &NodeId) -> Vec<Contact> {
tracing::Span::current().record("key", key.to_string()); tracing::Span::current().record("key", key.to_string());
let map = p2p.map.lock().await; let map = p2p.map.lock().await;
trace!("map: {:?}", map); trace!("map: {:?}", map);
if let Some(value) = map.get(key) { if let Some(value) = map.get(key) {
trace!("found item locally"); trace!("found item locally");
value.clone() value.clone()
@ -314,7 +328,10 @@ async fn find_hosters(p2p: &P2PState, key: &NodeId) -> Vec<Contact> {
if contact == p2p.contact { if contact == p2p.contact {
continue; continue;
} }
let Ok(response) = contact.send(&p2p.contact, RPCRequest::FindValue(*key)).await else { let Ok(response) = contact
.send(&p2p.contact, RPCRequest::FindValue(*key))
.await
else {
trace!("failed to send, removing node (host={})", p2p.contact.host); trace!("failed to send, removing node (host={})", p2p.contact.host);
let mut router = p2p.router.lock().await; let mut router = p2p.router.lock().await;
router.remove(&contact.id); router.remove(&contact.id);
@ -339,7 +356,7 @@ async fn find_hosters(p2p: &P2PState, key: &NodeId) -> Vec<Contact> {
} }
RPCResponse::Ok => { RPCResponse::Ok => {
trace!("node sent Ok message (host={})", p2p.contact.host); trace!("node sent Ok message (host={})", p2p.contact.host);
}, }
} }
} }
trace!("no nodes"); trace!("no nodes");

View file

@ -54,6 +54,9 @@ use crate::state::db::{Database, Location};
const MAX_SIZE: u64 = 1024 * 1024; const MAX_SIZE: u64 = 1024 * 1024;
// TODO: split out indexers a bit more quickly than anticipated: build
// times are getting long!
// TODO (future): maybe use a websocket instead of long polling? // TODO (future): maybe use a websocket instead of long polling?
// for receiving new events, would potentially be a lot more complicated though // for receiving new events, would potentially be a lot more complicated though

View file

@ -30,8 +30,8 @@ pub async fn can_view_event(db: &Sqlite, event: &Event, user: &ActorId) -> bool
} }
// FIXME (security): don't allow user enumeration! and find a better way to do this // FIXME (security): don't allow user enumeration! and find a better way to do this
if event.get_type() == "x.user" { if event.get_type() == "x.actor" {
trace!("TEMP: matches because this is an x.user event"); trace!("TEMP: matches because this is an x.actor event");
return true; return true;
} }
@ -97,18 +97,18 @@ pub async fn can_send_event(db: &Sqlite, wip: &WipEvent) -> Result<bool, Error>
}; };
let rel_ids: Vec<_> = relations.keys().cloned().collect(); let rel_ids: Vec<_> = relations.keys().cloned().collect();
let rel_events = match db.bulk_fetch(&rel_ids, false).await { let rel_events = db.bulk_fetch(&rel_ids).await?;
Ok(rel_events) => rel_events,
// Err(Error::NotFound) => { if rel_events.iter().any(|i| i.1.is_none()) {
// todo!(); // TODO: fetch missing relations
// }, todo!();
Err(err) => return Err(err),
}; };
let relations = rel_events let relations = rel_events
.into_iter() .into_iter()
.map(|(item_ref, item)| { .map(|(item_ref, item)| {
let rel_info = &relations[&item_ref]; let rel_info = &relations[&item_ref];
match item { match item.unwrap() {
DbItem::Event(event) => Ok((item_ref, (*event, rel_info.clone()))), DbItem::Event(event) => Ok((item_ref, (*event, rel_info.clone()))),
DbItem::Blob(_) => Err(Error::Validation( DbItem::Blob(_) => Err(Error::Validation(
"some relations are to blobs instead of events", "some relations are to blobs instead of events",

View file

@ -58,18 +58,19 @@ async fn search(
.search(&params.q, limit, offset, sniplen) .search(&params.q, limit, offset, sniplen)
.await?; .await?;
let item_refs: Vec<ItemRef> = results.iter().map(|i| i.item_ref.clone()).collect(); let item_refs: Vec<ItemRef> = results.iter().map(|i| i.item_ref.clone()).collect();
let results = state.db.bulk_fetch(&item_refs, true) let results = state.db.bulk_fetch(&item_refs)
.await? .await?
.into_iter() .into_iter()
.zip(results) .zip(results)
.map(|((_, item), doc)| { .map(|((_, item), doc)| {
match item { match item {
DbItem::Blob(_) => panic!("search result returned a blob"), Some(DbItem::Blob(_)) => unreachable!("search result returned a blob"),
DbItem::Event(event) => SearchDoc { Some(DbItem::Event(event)) => SearchDoc {
score: doc.score, score: doc.score,
snippet: doc.snippet, snippet: doc.snippet,
event, event,
}, },
None => unreachable!("search result returned a nonexistant event"),
} }
}) })
.collect(); .collect();

View file

@ -26,11 +26,12 @@ pub async fn route(
debug!("fetch blob"); debug!("fetch blob");
let (event, file) = match state.items.get(&item_ref).await? { let (event, file) = match state.items.get(&item_ref).await? {
Item::Event(event) => match event.content.clone() { Some(Item::Event(event)) => match event.content.clone() {
EventContent::File(file) => (event, file), EventContent::File(file) => (event, file),
_ => return Err(Error::Validation("this is not a x.file event")), _ => return Err(Error::Validation("this is not a x.file event")),
}, },
Item::Blob(_) => return Err(Error::Validation("this is not an event at all")), Some(Item::Blob(_)) => return Err(Error::Validation("this is not an event at all")),
None => return Err(Error::no_ref(&item_ref)),
}; };
let mime = event let mime = event
@ -70,14 +71,16 @@ pub async fn route(
} }
let blobs: Vec<(ItemRef, usize)> = state let blobs: Vec<(ItemRef, usize)> = state
.db .db
.bulk_fetch(&file.chunks, false) .bulk_fetch(&file.chunks)
.await? .await?
.into_iter() .into_iter()
.map(|(item_ref, item)| match item { .map(|(item_ref, item)| match item {
DbItem::Event(_) => { Some(DbItem::Event(_)) => {
unreachable!("all file chunks should've been validated to be blobs on create") unreachable!("all file chunks should've been validated to be blobs on create")
} }
DbItem::Blob(size) => (item_ref, size as usize), Some(DbItem::Blob(size)) => (item_ref, size as usize),
// FIXME (future): this won't be true soon, if servers garbage collect unused foreign blobs
None => unreachable!("all file chunks should've been validated to exist on create")
}) })
.collect(); .collect();
let total_len: usize = blobs.iter().map(|i| i.1).sum(); let total_len: usize = blobs.iter().map(|i| i.1).sum();
@ -89,7 +92,8 @@ pub async fn route(
let mut chunks = Vec::with_capacity(file.chunks.len()); let mut chunks = Vec::with_capacity(file.chunks.len());
for item_ref in &intersection { for item_ref in &intersection {
let Item::Blob(blob) = state.items.get(item_ref).await? else { let Some(Item::Blob(blob)) = state.items.get(item_ref).await? else {
// should i remove this constraint - allow x.file events to exist without having all blobs?
unreachable!("file didn't reference a blob"); unreachable!("file didn't reference a blob");
}; };
chunks.push(blob); chunks.push(blob);
@ -106,7 +110,7 @@ pub async fn route(
let mut chunks = Vec::with_capacity(file.chunks.len()); let mut chunks = Vec::with_capacity(file.chunks.len());
for item_ref in &intersection { for item_ref in &intersection {
let Item::Blob(blob) = state.items.get(item_ref).await? else { let Some(Item::Blob(blob)) = state.items.get(item_ref).await? else {
unreachable!("file didn't reference a blob"); unreachable!("file didn't reference a blob");
}; };
chunks.push(blob); chunks.push(blob);

View file

@ -29,10 +29,10 @@ pub async fn route(
debug!("bulk check"); debug!("bulk check");
let have = state let have = state
.db .db
.bulk_fetch(&options.refs, true) .bulk_fetch(&options.refs)
.await? .await?
.into_iter() .into_iter()
.map(|(item_ref, _)| item_ref) .filter_map(|(item_ref, item)| item.is_some().then_some(item_ref))
.collect(); .collect();
Ok(Json(BulkCheckResponse { have })) Ok(Json(BulkCheckResponse { have }))
} }

View file

@ -127,7 +127,7 @@ pub async fn route(
} }
pub async fn notify_have(p2p: &P2PState, item_ref: &ItemRef) { pub async fn notify_have(p2p: &P2PState, item_ref: &ItemRef) {
let key = NodeId::new_from_ref(&item_ref); let key = NodeId::new_from_ref(item_ref);
let mut map = p2p.map.lock().await; let mut map = p2p.map.lock().await;
map.insert(key, vec![p2p.contact.clone()]); map.insert(key, vec![p2p.contact.clone()]);
drop(map); drop(map);

View file

@ -29,7 +29,7 @@ pub async fn route(
let item = state.items.get(&item_ref).await?; let item = state.items.get(&item_ref).await?;
match item { match item {
Item::Blob(blob) => { Some(Item::Blob(blob)) => {
debug!("got blob"); debug!("got blob");
Ok(( Ok((
StatusCode::OK, StatusCode::OK,
@ -37,12 +37,12 @@ pub async fn route(
blob, blob,
)) ))
} }
Item::Event(event) => { Some(Item::Event(event)) => {
let is_visible = if let Some(user) = &auth.user { let is_visible = if let Some(user) = &auth.user {
can_view_event(&state.db, &event, user).await can_view_event(&state.db, &event, user).await
} else { } else {
// note that this doesn't define whether any event is *enumeratable* // note that this doesn't define whether any event is *enumeratable*
(event.get_type() == "x.file" || event.get_type() == "x.user") && !event.is_redacted() (event.get_type() == "x.file" || event.get_type() == "x.actor") && !event.is_redacted()
}; };
if !is_visible { if !is_visible {
// TODO (security): should this be "not found" instead of forbidden? // TODO (security): should this be "not found" instead of forbidden?
@ -67,5 +67,6 @@ pub async fn route(
Bytes::from(event_str.into_bytes()), Bytes::from(event_str.into_bytes()),
)) ))
} }
None => Err(Error::no_ref(&item_ref)),
} }
} }

View file

@ -41,7 +41,7 @@ pub async fn route(
.db .db
.event_fetch(&item_ref) .event_fetch(&item_ref)
.await? .await?
.ok_or(Error::NotFound)?; .ok_or_else(|| Error::no_ref(&item_ref))?;
let blob = get_blob(&state.items, &event).await?; let blob = get_blob(&state.items, &event).await?;
debug!("generate thumbnail"); debug!("generate thumbnail");
let thumb = generate_thumb(&blob, &size)?; let thumb = generate_thumb(&blob, &size)?;

View file

@ -176,9 +176,10 @@ pub async fn get_blob(
}; };
let mut chunks = Vec::with_capacity(file.chunks.len()); let mut chunks = Vec::with_capacity(file.chunks.len());
for item_ref in &file.chunks { for item_ref in &file.chunks {
let Item::Blob(blob) = items.get(item_ref).await? else { let blob = match items.get(item_ref).await? {
// possibly unreachable!(), assuming everything validated properly on insert Some(Item::Blob(blob)) => blob,
return Err(Error::Validation("file didn't reference a blob")); Some(Item::Event(_)) => return Err(Error::Validation("file didn't reference a blob")),
None => return Err(Error::no_ref(item_ref)),
}; };
chunks.push(blob); chunks.push(blob);
} }

View file

@ -78,7 +78,7 @@ pub trait Database {
// misc // misc
async fn tags_set(&self, item_refs: &[ItemRef], tags: &[String]) -> Result<(), Self::Error>; async fn tags_set(&self, item_refs: &[ItemRef], tags: &[String]) -> Result<(), Self::Error>;
async fn bulk_fetch(&self, item_refs: &[ItemRef], partial: bool) -> Result<Vec<(ItemRef, DbItem)>, Self::Error>; async fn bulk_fetch(&self, item_refs: &[ItemRef]) -> Result<Vec<(ItemRef, Option<DbItem>)>, Self::Error>;
// thumbnails // thumbnails
async fn thumbnail_put(&self, item_ref: &ItemRef, size: &ThumbnailSize, bytes: &[u8]) -> Result<(), Self::Error>; async fn thumbnail_put(&self, item_ref: &ItemRef, size: &ThumbnailSize, bytes: &[u8]) -> Result<(), Self::Error>;

View file

@ -396,8 +396,7 @@ impl Database for Sqlite {
async fn bulk_fetch( async fn bulk_fetch(
&self, &self,
item_refs: &[ItemRef], item_refs: &[ItemRef],
partial: bool, ) -> Result<Vec<(ItemRef, Option<DbItem>)>, Self::Error> {
) -> Result<Vec<(ItemRef, DbItem)>, Self::Error> {
let _lock = self.lock.read().await; let _lock = self.lock.read().await;
let mut builder = sqlx::QueryBuilder::new( let mut builder = sqlx::QueryBuilder::new(
" "
@ -431,10 +430,7 @@ impl Database for Sqlite {
.unwrap_or_default(); .unwrap_or_default();
DbItem::Event(Box::new(Event { derived, ..event })) DbItem::Event(Box::new(Event { derived, ..event }))
}; };
items.push((item_ref, item)); items.push((item_ref, Some(item)));
}
if !partial && item_refs.len() != items.len() {
return Err(Error::NotFound);
} }
// TODO (performance): ... // TODO (performance): ...
items.sort_by(|(a_ref, _), (b_ref, _)| { items.sort_by(|(a_ref, _), (b_ref, _)| {

View file

@ -1,3 +1,6 @@
// NOTE: THIS MAY NOT BE ACCURATE!!!
// see the real `perms.rs` in server for now, this will be stabalized in the future!
/// pseudocode for validing events /// pseudocode for validing events
/// the 2 main functions `is_event_visible` and `is_event_sendable` /// the 2 main functions `is_event_visible` and `is_event_sendable`
@ -49,16 +52,16 @@ fn validate_relations(event: &Event, ctx: &Context) -> bool {
} }
fn is_relation_valid(relation: &Event, ctx: &Context) -> bool { fn is_relation_valid(relation: &Event, ctx: &Context) -> bool {
// a relation is allowed if the user has sent that event
if relation.sender == ctx.user {
return true;
}
if let Some(acl) = get_acl(&relation) { if let Some(acl) = get_acl(&relation) {
// or if an acl set on it allows it // a relation is allowed if an acl set on it allows it
acl.can_send(ctx.user, ctx.event, ctx.relations) acl.can_send(ctx.user, ctx.event, ctx.relations)
} else { } else {
// or if all of it's relations are also valid // or if no acl is set, the user has sent that event
if relation.sender == ctx.user {
return true;
}
// or if no acl is set, if all of it's relations are also valid
validate_relations(relation, ctx) validate_relations(relation, ctx)
} }
} }

View file

@ -33,7 +33,7 @@ For implementation
4. servers can synchronize with each other 4. servers can synchronize with each other
5. i can specify access control on events 5. i can specify access control on events
This project is working on impl stage 4, currently. This project is working on impl stage 4/5, currently.
TODO: work out a proper api spec for blob servers and index servers TODO: work out a proper api spec for blob servers and index servers

70
spec/render.ts Normal file
View file

@ -0,0 +1,70 @@
import * as marked from "npm:marked";
if (!Deno.args[0]) throw new Error("needs a file as cli arg");
const filename = Deno.args[0];
const input = Deno.readTextFileSync(filename);
const rendered = marked.lexer(input).map(renderBlock).filter(i => i);
console.log(JSON.stringify({ doc: rendered, name: filename }));
// console.log(rendered);
interface Token {
type: string,
text: string,
tokens?: Array<Token>,
[key: string]: any,
}
function renderBlock(token: Token): any {
switch (token.type) {
case "paragraph": {
return renderInline(token);
}
case "heading": {
return { type: "header", level: token.depth, content: renderInline(token) };
}
case "list": {
return {
type: token.ordered ? "ol" : "ul",
items: token.items.map(i => {
if (i.tokens.length === 1) renderBlock(i.tokens[0]);
return i.tokens.map(renderBlock);
}),
};
}
case "code": {
return {
type: "code",
lang: token.lang,
content: renderInline(token),
};
}
case "space": {
return null;
}
case "text": {
return renderInline(token);
}
case "table": {
return {
type: "table",
headers: token.header.map(renderInline),
rows: token.rows.map(row => row.map(renderInline)),
}
}
default: {
return token;
}
}
}
function renderInline(token: Token): string {
const text = token.tokens ? token.tokens.map(renderInline).join("") : token.text;
switch (token.type) {
case "em": return `~italic{${text}}`;
case "strong": return `~bold{${text}}`;
case "link": return `~link{${text}}{${token.href}}`;
case "codespan": return `~code{${text}}`;
default: return `${text}`;
}
}

View file

@ -1,114 +0,0 @@
import type { Document } from "./scenes/Document/static";
import { api } from "./lib/api"
const event = api.makeEvent("x.example", {
hello: "world",
}, {
"sha224-123example789": { type: "frobnicates" },
});
const doc: Document = [
{
type: "header",
level: 1,
content: "Welcome!"
},
{
type: "text",
content: [
"ufh is a protocol for syncing and querying a distributed graph database."
]
},
{
type: "text",
content: [
"A decent chunk of inspiration is taken from ",
{
text: "matrix",
href: "https://matrix.org"
},
", ",
{
text: "ipfs",
href: "https://ipfs.tech/"
},
", and ",
{
text: "perkeep",
href: "https://perkeep.org/"
},
"."
]
},
{
type: "header",
level: 2,
content: "Spec"
},
{
type: "text",
content: [
"Everything in ufh is an ",
{
text: "object",
bold: true
},
", which can be referenced with an immutable ",
{
text: "ref",
bold: true
},
". The two main types of object are ",
{
text: "blob",
bold: true
},
"s and ",
{
text: "event",
bold: true
},
"s."
]
},
{
type: "callout",
is: "notice",
content: [
"a ref looks like ",
{
text: "sha224",
color: "#9085f3",
note: {
doc: "hash",
type: "inline"
},
code: "mono"
},
{
text: "-",
code: "mono"
},
{
text: "784093e5719d1935d14...784eb1e332cf750d1a9",
color: "#e66e82",
note: {
doc: "digest",
type: "inline"
},
code: "mono"
}
]
},
{
type: "text",
content: "Here's what an event looks like"
},
{
type: "code",
lang: "json",
content: JSON.stringify(await event, null, 4),
},
];
export default { name: "ufh spec", doc }

1
spec/test.json Normal file

File diff suppressed because one or more lines are too long

View file

@ -7,9 +7,7 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
async-trait = "0.1.68"
axum = { version = "0.6.18", features = ["macros", "headers"] } axum = { version = "0.6.18", features = ["macros", "headers"] }
flume = "0.10.14"
futures-util = "0.3.28" futures-util = "0.3.28"
serde = { version = "1.0.163", features = ["derive"] } serde = { version = "1.0.163", features = ["derive"] }
serde_json = "1.0.96" serde_json = "1.0.96"

View file

@ -21,6 +21,7 @@
import log from "./lib/log"; import log from "./lib/log";
import Clock from "./Clock.svelte"; import Clock from "./Clock.svelte";
import Pins from "./Pins.svelte"; import Pins from "./Pins.svelte";
import Prompt from "./popups/Prompt.svelte";
$: log.web("set state", $state); $: log.web("set state", $state);
@ -187,6 +188,10 @@
> >
</div> </div>
</Popup> </Popup>
{:else if popup.type === "prompt"}
<Popup on:close={() => popup.resolve(null)}>
<Prompt {popup} />
</Popup>
{:else} {:else}
<Popup>unknown popup</Popup> <Popup>unknown popup</Popup>
{/if} {/if}

View file

@ -45,7 +45,7 @@ export interface QueryOptions {
type Relations = Record<ref, { type: string, key?: string }>; type Relations = Record<ref, { type: string, key?: string }>;
type TypedEvents = { type TypedEvents = {
"x.user": { name: string }, "x.user": { name: string, type: "node" | "user" | "bot" },
"x.file": { chunks: Array<string>, name?: string }, "x.file": { chunks: Array<string>, name?: string },
"x.redact": { reason?: string }, "x.redact": { reason?: string },
"x.acl": { "x.acl": {

20
web/popups/Prompt.svelte Normal file
View file

@ -0,0 +1,20 @@
<script lang="ts">
import { state } from "../state";
export let popup: any;
let input: string;
function exit(cancelled: boolean) {
state.do("popup/close");
popup.resolve(cancelled ? null : input);
}
</script>
<div>{popup.question}</div>
<form on:submit|preventDefault={() => exit(false)}>
<input bind:value={input}>
</form>
<div style="margin-top: 1em; text-align: right">
<button on:click={() => exit(true)}>cancel</button>
<button on:click={() => exit(false)}>confirm</button>
</div>

View file

@ -1,6 +1,41 @@
<script lang="ts"> <script lang="ts">
import { api, base64 } from "../lib/api"; import { api, base64 } from "../lib/api";
import { query } from "../lib/util";
import { state } from "../state";
const me = query({
senders: [api.getUserId()],
types: ["x.actor"],
});
function prompt(question: string): Promise<string | null> {
return new Promise(res => {
state.do("popup/open", {
type: "prompt",
question,
resolve: res,
});
});
}
async function createUser() {
const name = await prompt("username?");
if (!name) return;
api.createEvent("x.actor", { name, type: "user" });
}
</script> </script>
<div class="user">
{#if $me[0]}
{@const cont = $me[0].getContent()}
user event: name={cont.name}, type={cont.type}
<details>
<summary>full event</summary>
<pre><code>{JSON.stringify($me[0].toRaw(), null, 4)}</code></pre>
</details>
{:else}
no user event <button on:click={createUser}>create</button>
{/if}
</div>
<table> <table>
<tr> <tr>
<td>Server:</td> <td>Server:</td>
@ -43,6 +78,12 @@
</tr> </tr>
</table> </table>
<style lang="scss"> <style lang="scss">
.user {
margin: 1em;
padding: 1em;
border: solid var(--borders) 1px;
}
table { table {
margin: 1em; margin: 1em;

View file

@ -66,11 +66,15 @@ pre, code {
&:not(.lang-mono) { &:not(.lang-mono) {
background: var(--bg-secondary); background: var(--bg-secondary);
padding: 0 2px; padding: 0 4px;
border-radius: 2px; border-radius: 2px;
} }
} }
pre:not(.lang-mono) {
padding: 4px;
}
pre { pre {
overflow-x: auto; overflow-x: auto;
padding: 4px; padding: 4px;
@ -78,7 +82,7 @@ pre {
table { table {
border: solid var(--borders) 1px; border: solid var(--borders) 1px;
border-radius: 4px; // border-radius: 4px;
border-spacing: 0; border-spacing: 0;
& > thead { & > thead {

View file

@ -10,5 +10,6 @@ export type Popup =
{ type: "edit", event: Event, panel: EditPanels } | { type: "edit", event: Event, panel: EditPanels } |
{ type: "create" } | { type: "create" } |
{ type: "confirm", question: string, resolve: (accepted: boolean) => void } | { type: "confirm", question: string, resolve: (accepted: boolean) => void } |
{ type: "prompt", question: string, resolve: (text: string | null) => void } |
{ type: "text", text: string }; { type: "text", text: string };