diff --git a/.gitignore b/.gitignore index adeaca8..3da6b60 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ target/ +kvdata/ node_modules/ *.db *.xml diff --git a/Cargo.lock b/Cargo.lock index bfe93ae..47e7508 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -186,7 +186,7 @@ checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", ] [[package]] @@ -197,7 +197,7 @@ checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", ] [[package]] @@ -209,6 +209,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "atomic" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" + [[package]] name = "autocfg" version = "1.1.0" @@ -452,7 +458,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", "syn_derive", ] @@ -502,6 +508,15 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +[[package]] +name = "cache-advisor" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f89ab55ca4e6a46a0740a1c5346db1ad66e4a76598bbfa060dc3259935a7450" +dependencies = [ + "crossbeam-queue", +] + [[package]] name = "camino" version = "1.1.6" @@ -538,6 +553,10 @@ name = "cc" version = "1.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8cd6604a82acf3039f1144f54b8eb34e91ffba622051189e71b781822d5ee1f5" +dependencies = [ + "jobserver", + "libc", +] [[package]] name = "cfg-if" @@ -553,14 +572,16 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chrono" -version = "0.4.35" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf5903dcbc0a39312feb77df2ff4c76387d591b9fc7b04a238dcf8bb62639a" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ "android-tzdata", "iana-time-zone", + "js-sys", "num-traits", "serde", + "wasm-bindgen", "windows-targets 0.52.4", ] @@ -595,7 +616,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", ] [[package]] @@ -610,6 +631,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "concurrent-map" +version = "5.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f5531a18ad61836deb8c2987422e44a38575564f423f448fe9e6cbbcb2171a" +dependencies = [ + "ebr", + "serde", + "stack-map", +] + [[package]] name = "const-oid" version = "0.9.6" @@ -732,6 +764,16 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "crossbeam-skiplist" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df29de440c58ca2cc6e587ec3d22347551a32435fbde9d2bff64e78a9ffa151b" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + [[package]] name = "crossbeam-utils" version = "0.8.19" @@ -777,7 +819,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.52", + "syn 2.0.61", ] [[package]] @@ -790,7 +832,7 @@ dependencies = [ "hashbrown 0.14.3", "lock_api", "once_cell", - "parking_lot_core 0.9.9", + "parking_lot_core", ] [[package]] @@ -858,6 +900,12 @@ version = "0.15.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1aaf95b3e5c8f23aa320147307562d361db0ae0d51242340f558153b4eb2439b" +[[package]] +name = "double-ended-peekable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0d05e1c0dbad51b52c38bda7adceef61b9efc2baf04acfe8726a8c4630a6f57" + [[package]] name = "dtoa" version = "1.0.9" @@ -873,6 +921,15 @@ dependencies = [ "dtoa", ] +[[package]] +name = "ebr" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a7f90b4164e55fcf36357b68aa2c13f6c922b16ba96f219a5220abd5a94fc4b" +dependencies = [ + "shared-local-state", +] + [[package]] name = "either" version = "1.10.0" @@ -953,6 +1010,12 @@ version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +[[package]] +name = "fault-injection" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3d175246dec3fddef3b1fcd57acdb023e4c562d032e9eccc5f246da3d7fed3" + [[package]] name = "filetime" version = "0.2.23" @@ -961,7 +1024,7 @@ checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "windows-sys 0.52.0", ] @@ -971,6 +1034,22 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fcfdc7a0362c9f4444381a9e697c79d435fe65b52a37466fc2c1184cee9edc6" +[[package]] +name = "fjall" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa8b3cbbdfa775c311965846c523ae291327a5cc3e433479583922ff9527594" +dependencies = [ + "byteorder", + "crc32fast", + "fs_extra", + "log", + "lsm-tree", + "path-absolutize", + "std-semaphore", + "tempfile", +] + [[package]] name = "flate2" version = "1.0.30" @@ -1033,6 +1112,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "fs_extra" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42703706b716c37f96a77aea830392ad231f44c9e9a67872fa5548707e11b11c" + [[package]] name = "fsevent-sys" version = "4.1.0" @@ -1042,6 +1127,12 @@ dependencies = [ "libc", ] +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + [[package]] name = "funty" version = "2.0.0" @@ -1097,7 +1188,7 @@ checksum = "1d930c203dd0b6ff06e0201a4a2fe9149b43c684fd4420555b26d21b1a02956f" dependencies = [ "futures-core", "lock_api", - "parking_lot 0.12.1", + "parking_lot", ] [[package]] @@ -1114,7 +1205,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", ] [[package]] @@ -1189,6 +1280,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +[[package]] +name = "guardian" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6817154789d2e9bb2af0486500e774af579d0e6539247044f06d803b141448b5" + [[package]] name = "h2" version = "0.4.3" @@ -1445,7 +1542,17 @@ checksum = "0122b7114117e64a63ac49f752a5ca4624d534c7b1c7de796ac196381cd2d947" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", +] + +[[package]] +name = "inline-array" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e86268f00167193a59f2145028ad707d5c1db9c2d89585ece0b8cc8a2b13fb5e" +dependencies = [ + "concurrent-map", + "serde", ] [[package]] @@ -1468,15 +1575,6 @@ dependencies = [ "libc", ] -[[package]] -name = "instant" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] - [[package]] name = "itertools" version = "0.10.5" @@ -1501,6 +1599,15 @@ version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] + [[package]] name = "js-sys" version = "0.3.69" @@ -1610,6 +1717,38 @@ version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +[[package]] +name = "lsm-tree" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "792f0f9d75b518035f7247774580ba60ee211d381237946e1a40609433f5573f" +dependencies = [ + "byteorder", + "chrono", + "crc32fast", + "crossbeam-skiplist", + "double-ended-peekable", + "fs_extra", + "guardian", + "log", + "lz4_flex", + "path-absolutize", + "quick_cache", + "rand 0.8.5", + "serde", + "serde_json", + "tempfile", +] + +[[package]] +name = "lz4_flex" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75761162ae2b0e580d7e7c390558127e5f01b4194debd6221fd8c207fc80e3f5" +dependencies = [ + "twox-hash", +] + [[package]] name = "matchers" version = "0.1.0" @@ -1759,6 +1898,14 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "model_derive" +version = "0.1.0" +dependencies = [ + "quote", + "syn 2.0.61", +] + [[package]] name = "moka" version = "0.12.5" @@ -1772,7 +1919,7 @@ dependencies = [ "crossbeam-utils", "futures-util", "once_cell", - "parking_lot 0.12.1", + "parking_lot", "quanta", "rustc_version", "skeptic", @@ -1843,7 +1990,7 @@ dependencies = [ "num-integer", "num-iter", "num-traits", - "rand", + "rand 0.8.5", "smallvec", "zeroize", ] @@ -1939,7 +2086,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", ] [[package]] @@ -1954,6 +2101,12 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39" +[[package]] +name = "pagetable" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92a516a35619e87f5c17e7a5dd0e0313aa01aecbd39b3c650b22a4500d74f6e0" + [[package]] name = "parcel_selectors" version = "0.26.4" @@ -1984,17 +2137,6 @@ dependencies = [ "vlq", ] -[[package]] -name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.6", -] - [[package]] name = "parking_lot" version = "0.12.1" @@ -2002,21 +2144,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" dependencies = [ "lock_api", - "parking_lot_core 0.9.9", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.16", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] @@ -2027,7 +2155,7 @@ checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.4.1", + "redox_syscall", "smallvec", "windows-targets 0.48.5", ] @@ -2052,7 +2180,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" dependencies = [ "base64ct", - "rand_core", + "rand_core 0.6.4", "subtle", ] @@ -2062,6 +2190,24 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +[[package]] +name = "path-absolutize" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4af381fe79fa195b4909485d99f73a80792331df0625188e707854f0b3383f5" +dependencies = [ + "path-dedot", +] + +[[package]] +name = "path-dedot" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ba0ad7e047712414213ff67533e6dd477af0a4e1d14fb52343e53d30ea9397" +dependencies = [ + "once_cell", +] + [[package]] name = "pathdiff" version = "0.2.1" @@ -2119,7 +2265,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d5285893bb5eb82e6aaf5d59ee909a06a16737a8970984dd7746ba9283498d6" dependencies = [ "phf_shared 0.10.0", - "rand", + "rand 0.8.5", ] [[package]] @@ -2129,7 +2275,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48e4cc64c2ad9ebe670cb8fd69dd50ae301650392e81c05f9bfcb2d5bdbc24b0" dependencies = [ "phf_shared 0.11.2", - "rand", + "rand 0.8.5", ] [[package]] @@ -2142,7 +2288,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", ] [[package]] @@ -2180,7 +2326,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", ] [[package]] @@ -2209,10 +2355,13 @@ dependencies = [ "clap", "dotenvy", "env_logger", + "fjall", "free-icons", "minijinja", "minijinja-autoreload", - "rand", + "model_derive", + "rand 0.8.5", + "redb", "sea-orm", "serde", "sled", @@ -2224,6 +2373,7 @@ dependencies = [ "tower-sessions-sqlx-store", "tracing", "tracing-subscriber", + "uuid", ] [[package]] @@ -2306,9 +2456,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.79" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] @@ -2360,10 +2510,20 @@ dependencies = [ ] [[package]] -name = "quote" -version = "1.0.35" +name = "quick_cache" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "347e1a588d1de074eeb3c00eadff93db4db65aeb62aee852b1efd0949fe65b6c" +dependencies = [ + "equivalent", + "hashbrown 0.14.3", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -2374,6 +2534,19 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi", +] + [[package]] name = "rand" version = "0.8.5" @@ -2382,7 +2555,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2392,9 +2565,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core", + "rand_core 0.6.4", ] +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + [[package]] name = "rand_core" version = "0.6.4" @@ -2434,12 +2622,21 @@ dependencies = [ ] [[package]] -name = "redox_syscall" -version = "0.2.16" +name = "rdrand" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" dependencies = [ - "bitflags 1.3.2", + "rand_core 0.3.1", +] + +[[package]] +name = "redb" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed7508e692a49b6b2290b56540384ccae9b1fb4d77065640b165835b56ffe3bb" +dependencies = [ + "libc", ] [[package]] @@ -2495,6 +2692,15 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[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 = "rend" version = "0.4.2" @@ -2583,7 +2789,7 @@ dependencies = [ "num-traits", "pkcs1", "pkcs8", - "rand_core", + "rand_core 0.6.4", "signature", "spki", "subtle", @@ -2600,7 +2806,7 @@ dependencies = [ "borsh", "bytes", "num-traits", - "rand", + "rand 0.8.5", "rkyv", "serde", "serde_json", @@ -2717,7 +2923,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", ] [[package]] @@ -2758,7 +2964,7 @@ dependencies = [ "proc-macro2", "quote", "sea-bae", - "syn 2.0.52", + "syn 2.0.61", "unicode-ident", ] @@ -2818,29 +3024,29 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.197" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", ] [[package]] name = "serde_json" -version = "1.0.114" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", @@ -2900,6 +3106,15 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "shared-local-state" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a50ccb2f45251772ed15abfd1e5f10a305288187b1582ab2e4295b29bbb4929" +dependencies = [ + "parking_lot", +] + [[package]] name = "signal-hook-registry" version = "1.4.1" @@ -2916,7 +3131,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" dependencies = [ "digest", - "rand_core", + "rand_core 0.6.4", ] [[package]] @@ -2966,18 +3181,29 @@ dependencies = [ [[package]] name = "sled" -version = "0.34.7" +version = "1.0.0-alpha.121" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f96b4737c2ce5987354855aed3797279def4ebf734436c6aa4552cf8e169935" +checksum = "4c13e52b2355f6d81e32a0271584fe9996120ec9785cf72adc7e9ef8bf96d0fe" dependencies = [ + "bincode 1.3.3", + "cache-advisor", + "concurrent-map", "crc32fast", - "crossbeam-epoch", - "crossbeam-utils", + "crossbeam-channel", + "crossbeam-queue", + "ebr", + "fault-injection", + "fnv", "fs2", - "fxhash", - "libc", + "inline-array", "log", - "parking_lot 0.11.2", + "pagetable", + "parking_lot", + "rayon", + "serde", + "stack-map", + "tempdir", + "zstd", ] [[package]] @@ -3162,7 +3388,7 @@ dependencies = [ "memchr", "once_cell", "percent-encoding", - "rand", + "rand 0.8.5", "rsa", "rust_decimal", "serde", @@ -3207,7 +3433,7 @@ dependencies = [ "memchr", "num-bigint", "once_cell", - "rand", + "rand 0.8.5", "rust_decimal", "serde", "serde_json", @@ -3248,12 +3474,27 @@ dependencies = [ "uuid", ] +[[package]] +name = "stack-map" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b49d6d36fee60faad91e23603db2356677b58ec2429237b39d5c60c26868f37c" +dependencies = [ + "serde", +] + [[package]] name = "static_assertions" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "std-semaphore" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ae9eec00137a8eed469fb4148acd9fc6ac8c3f9b110f52cd34698c8b5bfa0e" + [[package]] name = "stringprep" version = "0.1.4" @@ -3296,9 +3537,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.52" +version = "2.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07" +checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" dependencies = [ "proc-macro2", "quote", @@ -3314,7 +3555,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", ] [[package]] @@ -3335,6 +3576,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" +[[package]] +name = "tempdir" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" +dependencies = [ + "rand 0.4.6", + "remove_dir_all", +] + [[package]] name = "tempfile" version = "3.10.1" @@ -3364,7 +3615,7 @@ checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", ] [[package]] @@ -3434,7 +3685,7 @@ dependencies = [ "libc", "mio", "num_cpus", - "parking_lot 0.12.1", + "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", @@ -3450,7 +3701,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", ] [[package]] @@ -3522,7 +3773,7 @@ dependencies = [ "cookie", "futures-util", "http", - "parking_lot 0.12.1", + "parking_lot", "pin-project-lite", "tower-layer", "tower-service", @@ -3594,8 +3845,8 @@ dependencies = [ "base64 0.22.0", "futures", "http", - "parking_lot 0.12.1", - "rand", + "parking_lot", + "rand 0.8.5", "serde", "serde_json", "thiserror", @@ -3662,7 +3913,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", ] [[package]] @@ -3710,6 +3961,16 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "859eb650cfee7434994602c3a68b25d77ad9e68c8a6cd491616ef86661382eb3" +[[package]] +name = "twox-hash" +version = "1.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" +dependencies = [ + "cfg-if", + "static_assertions", +] + [[package]] name = "typenum" version = "1.17.0" @@ -3789,11 +4050,13 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.7.0" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f00cc9702ca12d3c81455259621e676d0f7251cec66a21e98fe2e9a37db93b2a" +checksum = "a183cf7feeba97b4dd1c0d46788634f6221d87fa961b305bed08c851829efcc0" dependencies = [ + "atomic", "getrandom", + "rand 0.8.5", "serde", ] @@ -3876,7 +4139,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", "wasm-bindgen-shared", ] @@ -3898,7 +4161,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3931,7 +4194,7 @@ version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a44ab49fad634e88f55bf8f9bb3abd2f27d7204172a112c7c9987e01c1c94ea9" dependencies = [ - "redox_syscall 0.4.1", + "redox_syscall", "wasite", ] @@ -4208,7 +4471,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.52", + "syn 2.0.61", ] [[package]] @@ -4216,3 +4479,32 @@ name = "zeroize" version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" + +[[package]] +name = "zstd" +version = "0.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a27595e173641171fc74a1232b7b1c7a7cb6e18222c11e9dfb9888fa424c53c" +dependencies = [ + "zstd-safe", +] + +[[package]] +name = "zstd-safe" +version = "6.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee98ffd0b48ee95e6c5168188e44a54550b1564d9d530ee21d5f0eaed1069581" +dependencies = [ + "libc", + "zstd-sys", +] + +[[package]] +name = "zstd-sys" +version = "2.0.10+zstd.1.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" +dependencies = [ + "cc", + "pkg-config", +] diff --git a/Cargo.toml b/Cargo.toml index 4fe7451..92cefe2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,13 +17,16 @@ bincode = "1.3.3" clap = { version = "4.5.3", features = ["derive", "env"] } dotenvy = "0.15.7" env_logger = "0.11.3" +fjall = "0.6.5" free-icons = "0.7.0" minijinja = { version = "1.0.14", features = ["loader"] } minijinja-autoreload = "1.0.14" +model_derive = { path = "./model_derive" } rand = "0.8.5" +redb = "2.1.0" sea-orm = { version = "0.12.15", features = ["sqlx-sqlite", "macros", "runtime-tokio-rustls"] } serde = { version = "1.0.197", features = ["derive"] } -sled = "0.34.7" +sled = "=1.0.0-alpha.121" thiserror = "1.0.58" tokio = { version = "1.36.0", features = ["rt", "full"] } tower-http = { version = "0.5.2", features = ["fs", "trace"] } @@ -32,3 +35,4 @@ tower-sessions-moka-store = "0.11.0" tower-sessions-sqlx-store = { version = "0.11.0", features = ["sqlite"] } tracing = "0.1.40" tracing-subscriber = { version = "0.3.18", features = ["env-filter"] } +uuid = { version = "1.8.0", features = ["v4", "fast-rng", "v7", "serde"] } diff --git a/Makefile b/Makefile index 8bdda4c..b9e412d 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,9 @@ run: SECURE_SESSIONS=false RUST_LOG=debug cargo run -- --reload-templates +run-watch: + SECURE_SESSIONS=false RUST_LOG=debug cargo watch --why -x 'run -- --reload-templates' + run-release: SECURE_SESSIONS=false RUST_LOG=info cargo run --release diff --git a/model_derive/Cargo.lock b/model_derive/Cargo.lock new file mode 100644 index 0000000..93b7aef --- /dev/null +++ b/model_derive/Cargo.lock @@ -0,0 +1,46 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "model_derive" +version = "0.1.0" +dependencies = [ + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.82" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "2.0.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c993ed8ccba56ae856363b1845da7266a7cb78e1d146c8a32d54b45a8b831fc9" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" diff --git a/model_derive/Cargo.toml b/model_derive/Cargo.toml new file mode 100644 index 0000000..3489eb2 --- /dev/null +++ b/model_derive/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "model_derive" +version = "0.1.0" +edition = "2021" + +[lib] +proc-macro = true + +[dependencies] +quote = "1.0.36" +syn = { version = "2.0.61", features = ["full", "derive"] } diff --git a/model_derive/src/lib.rs b/model_derive/src/lib.rs new file mode 100644 index 0000000..996a23d --- /dev/null +++ b/model_derive/src/lib.rs @@ -0,0 +1,48 @@ +use proc_macro::TokenStream; +use quote::{format_ident, quote}; +use syn::{parse_macro_input, DeriveInput, LitInt}; + +#[proc_macro_derive(Model, attributes(model_version))] +pub fn model(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + + let name = input.ident; + let attrs = input.attrs; + + let model_version = attrs.iter().find_map(|attr| { + if attr.path().is_ident("model_version") { + attr.parse_args::().ok().and_then(|lit| { + Some(lit.base10_parse::().unwrap()) + }) + } else { + None + } + }).unwrap_or(0); + + let lower_name = name.to_string().to_lowercase(); + let lower_name_ident = format_ident!("{}", lower_name); + + + let expanded = quote! { + impl Model for #name { + type Id = uuid::Uuid; + + fn id(&self) -> Self::Id { + self.id + } + + fn key(id: Self::Id) -> Vec { + let mut key = vec![]; + key.extend_from_slice(format!("{}:{}:", #lower_name, #model_version).as_bytes()); + key.extend_from_slice(&id.into_bytes()); + key + } + + fn partition(kv_handle: &KvHandle) -> &PartitionHandle { + &kv_handle.#lower_name_ident + } + } + }; + + TokenStream::from(expanded) +} diff --git a/src/context.rs b/src/context.rs index 0cbd9d0..0df1143 100644 --- a/src/context.rs +++ b/src/context.rs @@ -2,18 +2,21 @@ use std::sync::Arc; use minijinja_autoreload::AutoReloader; -use crate::{handler::internal_server_error, prelude::*}; +use crate::{handler::internal_server_error, kv::KvHandle, prelude::*}; #[derive(Clone)] pub struct Context { pub db: DatabaseConnection, + // TODO: add a design doc explaining why this not relational + pub kv_handles: KvHandle, template_loader: Arc, } impl Context { - pub fn new(db: DatabaseConnection, template_loader: AutoReloader) -> Context { + pub fn new(db: DatabaseConnection, kv_handles: KvHandle, template_loader: AutoReloader) -> Context { Context { db, + kv_handles, template_loader: Arc::new(template_loader), } } diff --git a/src/handler/home.rs b/src/handler/home.rs index 6f121f9..8077eb5 100644 --- a/src/handler/home.rs +++ b/src/handler/home.rs @@ -1,26 +1,11 @@ use axum::response::Redirect; use axum_login::AuthSession; -use crate::{models::Project, prelude::*}; +use crate::{models::{ModelPermission, Project}, prelude::*}; pub async fn home_page(State(ctx): State, auth_session: AuthSession) -> Response { if let Some(user) = auth_session.user { - let projects: Vec = vec![ - Project { - id: 1, - owner_id: 1, - name: "Blog posts".to_owned(), - description: "Planning and publication schedule for my blog".to_owned(), - key: "BLOG".to_owned(), - }, - Project { - id: 2, - owner_id: 1, - name: "Bugs (Pique)".to_owned(), - description: "The bugs we've found so far in Pique".to_owned(), - key: "BUG".to_owned(), - }, - ]; + let projects: Vec = ModelPermission::user_projects(&ctx.kv_handles, user.id).unwrap_or_default(); let values = context! { user => user, diff --git a/src/handler/projects.rs b/src/handler/projects.rs index 6796f9a..60d953e 100644 --- a/src/handler/projects.rs +++ b/src/handler/projects.rs @@ -1,50 +1,92 @@ -use axum::response::Redirect; +use axum::{response::Redirect, Form}; use axum_login::AuthSession; -use crate::{models::Project, prelude::*}; +use crate::{ + handler::internal_server_error, + models::{ModelPermission, ModelType, Permission, Project}, + prelude::*, +}; pub async fn projects_page( State(ctx): State, auth_session: AuthSession, ) -> Response { if let Some(user) = auth_session.user { - let projects: Vec = vec![ - Project { - id: 1, - owner_id: 1, - name: "Blog posts".to_owned(), - description: "Planning and publication schedule for my blog".to_owned(), - key: "BLOG".to_owned(), - }, - Project { - id: 2, - owner_id: 1, - name: "Bugs (Pique)".to_owned(), - description: "The bugs we've found so far in Pique".to_owned(), - key: "BUG".to_owned(), - }, - ]; - - let values = context! { - user => user, - projects => projects, - }; - - ctx.render_resp("projects/list_projects.html", values) + render_projects_page(ctx, user).await } else { Redirect::to("/login").into_response() } } -pub async fn create_project( +async fn render_projects_page(ctx: Context, user: crate::entity::user::Model) -> Response { + let projects = ModelPermission::user_projects(&ctx.kv_handles, user.id).unwrap_or_default(); + + let values = context! { + user => user, + projects => projects, + }; + + ctx.render_resp("projects/list_projects.html", values) +} + +pub async fn create_project_page( State(ctx): State, auth_session: AuthSession, ) -> Response { - if let Some(_user) = auth_session.user { - let values = context! {}; + let user = match auth_session.user { + Some(user) => user, + None => return Redirect::to("/login").into_response(), + }; - ctx.render_resp("projects/create_project.html", values) - } else { - Redirect::to("/login").into_response() - } + let values = context! { + user => user, + }; + ctx.render_resp("projects/create_project.html", values) +} + +#[derive(Debug, Deserialize)] +pub struct CreateProjectSubmission { + pub name: String, + pub key: String, + pub description: String, +} + +pub async fn create_project_submit( + State(ctx): State, + auth_session: AuthSession, + form: Form, +) -> Response { + let user = match auth_session.user { + Some(user) => user, + None => return Redirect::to("/login").into_response(), + }; + + let project = Project { + id: Uuid::new_v4(), + owner_id: user.id, + + name: form.name.clone(), + key: form.key.clone(), + description: form.description.clone(), + }; + // TODO: validation + + if let Err(err) = project.save(&ctx.kv_handles) { + error!(?err, "failed to save new project"); + return internal_server_error(); + } + + let permission = ModelPermission { + user_id: user.id, + model_type: ModelType::Project, + role: Permission::Admin, + model_id: project.id, + }; + + if let Err(err) = permission.add(&ctx.kv_handles) { + error!(?err, "failed to save new project permission"); + return internal_server_error(); + } + + Redirect::to("/projects").into_response() } diff --git a/src/kv.rs b/src/kv.rs new file mode 100644 index 0000000..0d68fa0 --- /dev/null +++ b/src/kv.rs @@ -0,0 +1,42 @@ +use std::path::Path; + +use anyhow::Result; +use fjall::{Config, Keyspace, PartitionCreateOptions, PartitionHandle}; + +/// Contains the handles needed to reference key-value data. +/// +/// This contains both the Keyspace and multiple PartitionHandle. +/// The Keyspace allows operational control and reporting at the top level, +/// while each PartitionHandle controls reading, writing, and removing from a +/// particular partition of the data. +/// +/// All fields are public, because this is meant to be used internally as a +/// wrapper to pass everything around, instead of passing each handle around by +/// itself. +#[derive(Clone)] +pub struct KvHandle { + pub keyspace: Keyspace, + + pub project: PartitionHandle, + pub document: PartitionHandle, + pub permissions: PartitionHandle, +} + +impl KvHandle { + pub fn open>(p: P) -> Result { + // TODO: those should probably be configurable, or like, not just hard coded. + let config = Config::new(p).flush_workers(4).compaction_workers(4); + let keyspace = Keyspace::open(config)?; + + let project = keyspace.open_partition("project", PartitionCreateOptions::default())?; + let document = keyspace.open_partition("document", PartitionCreateOptions::default())?; + let permissions = keyspace.open_partition("permissions", PartitionCreateOptions::default())?; + + Ok(KvHandle { + keyspace, + project, + document, + permissions, + }) + } +} diff --git a/src/lib.rs b/src/lib.rs index a8fe969..4f3e2ba 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,3 +11,4 @@ pub mod serialize; pub mod server; pub mod session; pub mod templates; +pub mod kv; diff --git a/src/logging.rs b/src/logging.rs index ed0eca7..5e03789 100644 --- a/src/logging.rs +++ b/src/logging.rs @@ -1,5 +1,7 @@ +use tracing_subscriber::EnvFilter; + pub fn setup_logging() { tracing_subscriber::fmt() - .with_max_level(tracing::Level::DEBUG) + .with_env_filter(EnvFilter::from_default_env()) .init(); } diff --git a/src/models.rs b/src/models.rs index 1a8bd5d..8e57f32 100644 --- a/src/models.rs +++ b/src/models.rs @@ -1,8 +1,50 @@ -use serde::{Deserialize, Serialize}; +use core::fmt::{self, Display}; +use crate::prelude::*; -#[derive(Debug, Serialize, Deserialize, PartialEq)] +use anyhow::Result; +use fjall::PartitionHandle; +use model_derive::Model; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; + +use crate::kv::KvHandle; + +pub trait Model: Sized + Serialize + for<'a> Deserialize<'a> { + type Id; + + fn id(&self) -> Self::Id; + fn key(id: Self::Id) -> Vec; + fn partition(kv_handle: &KvHandle) -> &PartitionHandle; + + fn save(&self, kv_handle: &KvHandle) -> Result<()> { + let key = Self::key(self.id()); + let value = bincode::serialize(self)?; + let partition = Self::partition(kv_handle); + + partition.insert(key, value)?; + + Ok(()) + } + + fn load(kv_handle: &KvHandle, id: Self::Id) -> Result> { + let key = Self::key(id); + let partition = Self::partition(kv_handle); + + match partition.get(key.as_slice())? { + Some(bytes) => { + let bytes = bytes.to_vec(); + let value: Self = bincode::deserialize(&bytes)?; + Ok(Some(value)) + } + None => Ok(None), + } + } +} + +#[derive(Debug, Model, Serialize, Deserialize, PartialEq)] +#[model_version(0)] pub struct Project { - pub id: u64, + pub id: Uuid, pub owner_id: i32, pub name: String, @@ -14,11 +56,106 @@ pub struct Project { pub key: String, } -#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[derive(Debug, Model, Serialize, Deserialize, PartialEq)] +#[model_version(0)] pub struct Document { - pub id: u64, - pub project_id: u64, + pub id: Uuid, + pub project_id: Uuid, pub title: String, pub content: String, } + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[repr(u8)] +pub enum ModelType { + Project = 0, + Document = 1, +} + +impl Display for ModelType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + ModelType::Project => write!(f, "project"), + ModelType::Document => write!(f, "document"), + } + } +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +#[repr(u8)] +pub enum Permission { + Admin = 0, + Read = 1, +} + +impl Display for Permission { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Permission::Admin => write!(f, "admin"), + Permission::Read => write!(f, "read"), + } + } +} + +#[derive(Debug, Serialize, Deserialize, PartialEq)] +pub struct ModelPermission { + pub user_id: i32, + pub model_type: ModelType, + pub role: Permission, + pub model_id: Uuid, +} + +impl ModelPermission { + pub fn add(&self, kv_handle: &KvHandle) -> Result<()> { + let key = format!( + "{}:{}:{}:{}", + self.user_id, self.model_type, self.role, self.model_id + ); + let value = bincode::serialize(self)?; + + kv_handle.permissions.insert(key, value)?; + + Ok(()) + } + + pub fn user_projects(kv_handle: &KvHandle, user_id: i32) -> Result> { + let prefix = format!("{}:{}:", user_id, ModelType::Project); + + let mut ids = vec![]; + for row in kv_handle.permissions.prefix(prefix).into_iter() { + let (_key, value) = row?; + let permission: ModelPermission = bincode::deserialize(&value)?; + ids.push(permission.model_id); + } + + let projects: Vec = ids + .into_iter() + .filter_map(|id| { + let res = Project::load(kv_handle, id); + res.ok().flatten() + }) + .collect(); + + Ok(projects) + } + + pub fn user_documents(kv_handle: &KvHandle, user_id: i32) -> Result> { + let prefix = format!("{}:{}:", user_id, ModelType::Document); + + let mut ids = vec![]; + for row in kv_handle.permissions.prefix(prefix).into_iter() { + let (_key, value) = row?; + let permission: ModelPermission = bincode::deserialize(&value)?; + ids.push(permission.model_id); + } + + let documents: Vec = ids + .into_iter() + .filter_map(|id| Document::load(kv_handle, id).ok().flatten()) + .collect(); + + Ok(documents) + } + +} diff --git a/src/prelude.rs b/src/prelude.rs index 0099512..e24c43a 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -1,5 +1,6 @@ pub use crate::context::Context; pub use crate::entity::prelude::*; +pub use crate::models::Model; pub use axum::extract::State; pub use axum::response::{Html, IntoResponse, Response}; pub use minijinja::context; diff --git a/src/server.rs b/src/server.rs index 7225332..e427cb6 100644 --- a/src/server.rs +++ b/src/server.rs @@ -10,7 +10,7 @@ use tower_sessions::SessionManagerLayer; use tower_sessions_sqlx_store::{sqlx::SqlitePool, SqliteStore}; use tracing::Level; -use crate::{config::CommandLineOptions, context::Context, handler::{home::home_page, login::logout, login_page, login_submit, projects::{create_project, projects_page}}, logging::setup_logging, templates::make_template_loader}; +use crate::{config::CommandLineOptions, context::Context, handler::{home::home_page, login::logout, login_page, login_submit, projects::{create_project_page, create_project_submit, projects_page}}, kv::KvHandle, logging::setup_logging, templates::make_template_loader}; pub async fn run() -> Result<()> { dotenvy::dotenv()?; @@ -25,7 +25,10 @@ pub async fn run() -> Result<()> { let session_layer = create_session_manager_layer().await?; - let context = Context::new(db, template_loader); + // TODO: better name, also make it an option + let kv_handles = KvHandle::open("./kvdata/")?; + + let context = Context::new(db, kv_handles, template_loader); let auth_backend = context.clone(); let auth_layer = AuthManagerLayerBuilder::new(auth_backend, session_layer.clone()).build(); @@ -41,7 +44,8 @@ pub async fn run() -> Result<()> { .route("/login", post(login_submit)) .route("/logout", get(logout)) .route("/projects", get(projects_page)) - .route("/projects/new", get(create_project)) + .route("/projects/new", get(create_project_page)) + .route("/projects/new", post(create_project_submit)) .layer(trace_layer) .layer(session_layer) .layer(auth_layer) diff --git a/templates/projects/create_project.html b/templates/projects/create_project.html index 1dbed99..e3838a2 100644 --- a/templates/projects/create_project.html +++ b/templates/projects/create_project.html @@ -16,13 +16,27 @@ -
- +
+
+ + + + + + + +
+
-