From 674929bec5534c7d258c03d0b65de84abec1c1b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tom=C3=A1=C5=A1=20Ml=C3=A1dek?= Date: Fri, 29 Dec 2023 20:59:40 +0100 Subject: [PATCH] wip --- Cargo.lock | 734 ++++++++++++---------------------------------- cli/Cargo.toml | 23 +- cli/src/main.rs | 3 +- cli/src/routes.rs | 427 ++++++++++++++------------- cli/src/serve.rs | 2 + 5 files changed, 418 insertions(+), 771 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index fe358bd..19d0e6e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,298 +2,6 @@ # It is not intended for manual editing. version = 3 -[[package]] -name = "actix" -version = "0.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f728064aca1c318585bf4bb04ffcfac9e75e508ab4e8b1bd9ba5dfe04e2cbed5" -dependencies = [ - "actix-rt", - "actix_derive", - "bitflags 1.3.2", - "bytes", - "crossbeam-channel", - "futures-core", - "futures-sink", - "futures-task", - "futures-util", - "log", - "once_cell", - "parking_lot", - "pin-project-lite", - "smallvec", - "tokio", - "tokio-util", -] - -[[package]] -name = "actix-codec" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "617a8268e3537fe1d8c9ead925fca49ef6400927ee7bc26750e90ecee14ce4b8" -dependencies = [ - "bitflags 1.3.2", - "bytes", - "futures-core", - "futures-sink", - "memchr", - "pin-project-lite", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "actix-cors" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b340e9cfa5b08690aae90fb61beb44e9b06f44fe3d0f93781aaa58cfba86245e" -dependencies = [ - "actix-utils", - "actix-web", - "derive_more", - "futures-util", - "log", - "once_cell", - "smallvec", -] - -[[package]] -name = "actix-files" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d832782fac6ca7369a70c9ee9a20554623c5e51c76e190ad151780ebea1cf689" -dependencies = [ - "actix-http", - "actix-service", - "actix-utils", - "actix-web", - "askama_escape", - "bitflags 1.3.2", - "bytes", - "derive_more", - "futures-core", - "http-range", - "log", - "mime", - "mime_guess", - "percent-encoding", - "pin-project-lite", -] - -[[package]] -name = "actix-http" -version = "3.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2079246596c18b4a33e274ae10c0e50613f4d32a4198e09c7b93771013fed74" -dependencies = [ - "actix-codec", - "actix-rt", - "actix-service", - "actix-utils", - "ahash 0.8.3", - "base64 0.21.3", - "bitflags 1.3.2", - "brotli", - "bytes", - "bytestring", - "derive_more", - "encoding_rs", - "flate2", - "futures-core", - "h2", - "http", - "httparse", - "httpdate", - "itoa", - "language-tags", - "local-channel", - "mime", - "percent-encoding", - "pin-project-lite", - "rand", - "sha1", - "smallvec", - "tokio", - "tokio-util", - "tracing", - "zstd", -] - -[[package]] -name = "actix-macros" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e01ed3140b2f8d422c68afa1ed2e85d996ea619c988ac834d255db32138655cb" -dependencies = [ - "quote", - "syn 2.0.29", -] - -[[package]] -name = "actix-multipart" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee489e3c01eae4d1c35b03c4493f71cb40d93f66b14558feb1b1a807671cc4e" -dependencies = [ - "actix-multipart-derive", - "actix-utils", - "actix-web", - "bytes", - "derive_more", - "futures-core", - "futures-util", - "httparse", - "local-waker", - "log", - "memchr", - "mime", - "serde", - "serde_json", - "serde_plain", - "tempfile", - "tokio", -] - -[[package]] -name = "actix-multipart-derive" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ec592f234db8a253cf80531246a4407c8a70530423eea80688a6c5a44a110e7" -dependencies = [ - "darling", - "parse-size", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "actix-router" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66ff4d247d2b160861fa2866457e85706833527840e4133f8f49aa423a38799" -dependencies = [ - "bytestring", - "http", - "regex", - "serde", - "tracing", -] - -[[package]] -name = "actix-rt" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28f32d40287d3f402ae0028a9d54bef51af15c8769492826a69d28f81893151d" -dependencies = [ - "actix-macros", - "futures-core", - "tokio", -] - -[[package]] -name = "actix-server" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb13e7eef0423ea6eab0e59f6c72e7cb46d33691ad56a726b3cd07ddec2c2d4" -dependencies = [ - "actix-rt", - "actix-service", - "actix-utils", - "futures-core", - "futures-util", - "mio", - "socket2 0.5.3", - "tokio", - "tracing", -] - -[[package]] -name = "actix-service" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a" -dependencies = [ - "futures-core", - "paste", - "pin-project-lite", -] - -[[package]] -name = "actix-utils" -version = "3.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a1dcdff1466e3c2488e1cb5c36a71822750ad43839937f85d2f4d9f8b705d8" -dependencies = [ - "local-waker", - "pin-project-lite", -] - -[[package]] -name = "actix-web" -version = "4.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd3cb42f9566ab176e1ef0b8b3a896529062b4efc6be0123046095914c4c1c96" -dependencies = [ - "actix-codec", - "actix-http", - "actix-macros", - "actix-router", - "actix-rt", - "actix-server", - "actix-service", - "actix-utils", - "actix-web-codegen", - "ahash 0.7.6", - "bytes", - "bytestring", - "cfg-if 1.0.0", - "cookie", - "derive_more", - "encoding_rs", - "futures-core", - "futures-util", - "http", - "itoa", - "language-tags", - "log", - "mime", - "once_cell", - "pin-project-lite", - "regex", - "serde", - "serde_json", - "serde_urlencoded", - "smallvec", - "socket2 0.4.9", - "time 0.3.28", - "url", -] - -[[package]] -name = "actix-web-codegen" -version = "4.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2262160a7ae29e3415554a3f1fc04c764b1540c116aa524683208078b7a75bc9" -dependencies = [ - "actix-router", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "actix_derive" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d44b8fee1ced9671ba043476deddef739dd0959bf77030b26b738cc591737a7" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "addr2line" version = "0.21.0" @@ -326,18 +34,6 @@ dependencies = [ "version_check", ] -[[package]] -name = "ahash" -version = "0.8.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" -dependencies = [ - "cfg-if 1.0.0", - "getrandom", - "once_cell", - "version_check", -] - [[package]] name = "aho-corasick" version = "1.0.4" @@ -347,21 +43,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "alloc-no-stdlib" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" - -[[package]] -name = "alloc-stdlib" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" -dependencies = [ - "alloc-no-stdlib", -] - [[package]] name = "android-tzdata" version = "0.1.1" @@ -444,10 +125,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] -name = "askama_escape" -version = "0.10.3" +name = "async-trait" +version = "0.1.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "619743e34b5ba4e9703bba34deac3427c72507c7159f5fd030aea8cac0cfe341" +checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] [[package]] name = "autocfg" @@ -455,6 +141,59 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "axum" +version = "0.6.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" +dependencies = [ + "async-trait", + "axum-core", + "bitflags 1.3.2", + "bytes", + "futures-util", + "headers", + "http", + "http-body", + "hyper", + "itoa", + "matchit", + "memchr", + "mime", + "multer", + "percent-encoding", + "pin-project-lite", + "rustversion", + "serde", + "serde_json", + "serde_path_to_error", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "axum-core" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", + "rustversion", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "backtrace" version = "0.3.69" @@ -544,27 +283,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "brotli" -version = "3.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", - "brotli-decompressor", -] - -[[package]] -name = "brotli-decompressor" -version = "2.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" -dependencies = [ - "alloc-no-stdlib", - "alloc-stdlib", -] - [[package]] name = "bstr" version = "1.6.0" @@ -606,15 +324,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" -[[package]] -name = "bytestring" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238e4886760d98c4f899360c834fa93e62cf7f721ac3c2da375cbdf4b8679aae" -dependencies = [ - "bytes", -] - [[package]] name = "cc" version = "1.0.83" @@ -752,23 +461,6 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" -[[package]] -name = "convert_case" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" - -[[package]] -name = "cookie" -version = "0.16.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e859cd57d0710d9e06c381b550c06e76992472a8c6d527aecd2fc673dcc231fb" -dependencies = [ - "percent-encoding", - "time 0.3.28", - "version_check", -] - [[package]] name = "core-foundation" version = "0.9.3" @@ -865,41 +557,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "darling" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b750cb3417fd1b327431a470f388520309479ab0bf5e323505daf0290cd3850" -dependencies = [ - "darling_core", - "darling_macro", -] - -[[package]] -name = "darling_core" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109c1ca6e6b7f82cc233a97004ea8ed7ca123a9af07a8230878fcfda9b158bf0" -dependencies = [ - "fnv", - "ident_case", - "proc-macro2", - "quote", - "strsim", - "syn 1.0.109", -] - -[[package]] -name = "darling_macro" -version = "0.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4aab4dbc9f7611d8b55048a3a16d2d010c2c8334e46304b40ac1cc14bf3b48e" -dependencies = [ - "darling_core", - "quote", - "syn 1.0.109", -] - [[package]] name = "data-encoding" version = "2.4.0" @@ -942,19 +599,6 @@ version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" -[[package]] -name = "derive_more" -version = "0.99.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" -dependencies = [ - "convert_case", - "proc-macro2", - "quote", - "rustc_version", - "syn 1.0.109", -] - [[package]] name = "diesel" version = "1.4.8" @@ -1273,7 +917,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.6", + "ahash", ] [[package]] @@ -1282,6 +926,31 @@ version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +[[package]] +name = "headers" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3e372db8e5c0d213e0cd0b9be18be2aca3d44cf2fe30a9d46a65581cd454584" +dependencies = [ + "base64 0.13.1", + "bitflags 1.3.2", + "bytes", + "headers-core", + "http", + "httpdate", + "mime", + "sha1", +] + +[[package]] +name = "headers-core" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" +dependencies = [ + "http", +] + [[package]] name = "heck" version = "0.4.1" @@ -1330,12 +999,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "http-range" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" - [[package]] name = "httparse" version = "1.8.0" @@ -1419,12 +1082,6 @@ dependencies = [ "flate2", ] -[[package]] -name = "ident_case" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" - [[package]] name = "idna" version = "0.4.0" @@ -1573,12 +1230,6 @@ dependencies = [ "cpufeatures", ] -[[package]] -name = "language-tags" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4345964bb142484797b161f473a503a434de77149dd8c7427788c6e13379388" - [[package]] name = "lazy_static" version = "1.4.0" @@ -1639,24 +1290,6 @@ version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503" -[[package]] -name = "local-channel" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f303ec0e94c6c54447f84f3b0ef7af769858a9c4ef56ef2a986d3dcd4c3fc9c" -dependencies = [ - "futures-core", - "futures-sink", - "futures-util", - "local-waker", -] - -[[package]] -name = "local-waker" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e34f76eb3611940e0e7d53a9aaa4e6a3151f69541a282fd0dad5571420c53ff1" - [[package]] name = "lock_api" version = "0.4.10" @@ -1723,6 +1356,12 @@ dependencies = [ "regex-automata 0.1.10", ] +[[package]] +name = "matchit" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed1202b2a6f884ae56f04cff409ab315c5ce26b5e58d7412e484f01fd52f52ef" + [[package]] name = "memchr" version = "2.6.0" @@ -1771,16 +1410,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime_guess" -version = "2.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4192263c238a5f0d0c6bfd21f336a313a4ce1c450542449ca191bb657b4642ef" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -1822,11 +1451,28 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2" dependencies = [ "libc", - "log", "wasi 0.11.0+wasi-snapshot-preview1", "windows-sys", ] +[[package]] +name = "multer" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http", + "httparse", + "log", + "memchr", + "mime", + "spin 0.9.8", + "version_check", +] + [[package]] name = "multibase" version = "0.9.1" @@ -2105,18 +1751,6 @@ dependencies = [ "windows-targets", ] -[[package]] -name = "parse-size" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "944553dd59c802559559161f9816429058b869003836120e262e8caec061b7ae" - -[[package]] -name = "paste" -version = "1.0.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" - [[package]] name = "pem" version = "1.1.1" @@ -2180,6 +1814,26 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] + [[package]] name = "pin-project-lite" version = "0.2.13" @@ -2436,7 +2090,7 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", + "spin 0.5.2", "untrusted", "web-sys", "winapi", @@ -2448,15 +2102,6 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustc_version" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" -dependencies = [ - "semver", -] - [[package]] name = "rustix" version = "0.38.9" @@ -2470,6 +2115,12 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + [[package]] name = "ryu" version = "1.0.15" @@ -2538,12 +2189,6 @@ dependencies = [ "libc", ] -[[package]] -name = "semver" -version = "1.0.18" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" - [[package]] name = "serde" version = "1.0.188" @@ -2576,11 +2221,12 @@ dependencies = [ ] [[package]] -name = "serde_plain" -version = "1.0.2" +name = "serde_path_to_error" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1fc6db65a611022b23a0dec6975d63fb80a302cb3388835ff02c097258d50" +checksum = "4beec8bce849d58d06238cb50db2e1c417cfeafa4c63f692b15c82b7c80f8335" dependencies = [ + "itoa", "serde", ] @@ -2726,6 +2372,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "string_cache" version = "0.8.7" @@ -2780,6 +2432,12 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "synstructure" version = "0.12.6" @@ -2924,13 +2582,23 @@ dependencies = [ "libc", "mio", "num_cpus", - "parking_lot", "pin-project-lite", - "signal-hook-registry", "socket2 0.5.3", + "tokio-macros", "windows-sys", ] +[[package]] +name = "tokio-macros" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.29", +] + [[package]] name = "tokio-native-tls" version = "0.3.1" @@ -2964,6 +2632,28 @@ dependencies = [ "serde", ] +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "pin-project-lite", + "tokio", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-layer" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c20c8dbed6283a09604c3e69b4b7eeb54e298b8a600d4d5ecb5ad39de609f1d0" + [[package]] name = "tower-service" version = "0.3.2" @@ -3066,15 +2756,6 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" -[[package]] -name = "unicase" -version = "2.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d2d4dafb69621809a81864c9c1b864479e1235c0dd4e199924b9742439ed89" -dependencies = [ - "version_check", -] - [[package]] name = "unicode-bidi" version = "0.3.13" @@ -3138,14 +2819,8 @@ dependencies = [ name = "upend-cli" version = "0.1.0" dependencies = [ - "actix", - "actix-cors", - "actix-files", - "actix-multipart", - "actix-rt", - "actix-web", - "actix_derive", "anyhow", + "axum", "bytes", "chrono", "clap", @@ -3181,6 +2856,7 @@ dependencies = [ "signal-hook", "tempfile", "thiserror", + "tokio", "tracing", "tracing-subscriber", "tree_magic_mini", @@ -3579,33 +3255,3 @@ dependencies = [ "mac", "markup5ever", ] - -[[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.8+zstd.1.5.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" -dependencies = [ - "cc", - "libc", - "pkg-config", -] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index deac289..241a68c 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -11,7 +11,8 @@ path = "src/main.rs" [dependencies] upend-base = { path = "../base" } upend-db = { path = "../db" } -clap = { version = "4.2.4", features = ["derive", "env", "color", "string", "cargo"] } + +tokio = {version = "1.32.0", features = ["macros", "rt-multi-thread"]} log = "0.4" tracing = "0.1" @@ -37,13 +38,7 @@ diesel = { version = "1.4", features = [ diesel_migrations = "1.4" libsqlite3-sys = { version = "^0", features = ["bundled"] } -actix = "0.13" -actix-files = "0.6" -actix-rt = "2" -actix-web = "4" -actix_derive = "0.6" -actix-cors = "0.6" -actix-multipart = "0.6.0" +axum = {version = "0.6.20", features = ["headers", "multipart", "tracing"]} jsonwebtoken = "8" chrono = { version = "0.4", features = ["serde"] } @@ -87,6 +82,8 @@ shadow-rs = { version = "0.23", default-features = false } reqwest = { version = "0.11.16", features = ["blocking", "json"] } url = "2" +clap = { version = "4.2.4", features = ["derive", "env", "color", "string", "cargo"] } + bytes = "1.4.0" signal-hook = "0.3.15" @@ -94,15 +91,7 @@ signal-hook = "0.3.15" shadow-rs = { version = "0.23", default-features = false } [features] -default = [ - "desktop", - "previews", - "previews-image", - "extractors-web", - "extractors-audio", - "extractors-exif", - "extractors-media", -] +default = ["desktop", "previews", "previews-image", "extractors-web", "extractors-audio", "extractors-exif", "extractors-media"] desktop = ["webbrowser", "opener", "is_executable"] previews = [] previews-image = ["image", "webp", "kamadak-exif"] diff --git a/cli/src/main.rs b/cli/src/main.rs index 7fb6cc2..1d06b7b 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -3,7 +3,6 @@ extern crate upend_db; use crate::common::{get_resource_path, REQWEST_ASYNC_CLIENT}; use crate::config::UpEndConfig; -use actix_web::HttpServer; use anyhow::Result; use clap::{Args, CommandFactory, FromArgMatches, Parser, Subcommand, ValueEnum}; use filebuffer::FileBuffer; @@ -177,7 +176,7 @@ struct ServeArgs { allow_host: Vec, } -#[actix_web::main] +#[tokio::main] async fn main() -> Result<()> { let command = Cli::command().version(option_env!("UPEND_VERSION").unwrap_or("unknown")); let args = Cli::from_arg_matches(&command.get_matches())?; diff --git a/cli/src/routes.rs b/cli/src/routes.rs index fc705f4..671fddd 100644 --- a/cli/src/routes.rs +++ b/cli/src/routes.rs @@ -1,52 +1,45 @@ +use std::collections::HashMap; +use std::convert::{TryFrom, TryInto}; +use std::io::Write; +use std::sync::Arc; +use std::time::{SystemTime, UNIX_EPOCH}; + +use axum::extract::Path; +use axum::extract::{Query, State}; +use axum::http::StatusCode; +use axum::response::{IntoResponse, Response}; +use axum::Json; +use axum::{routing::get, routing::post, routing::put, Router}; +use futures::channel::oneshot; +use futures_util::{StreamExt, TryStreamExt}; +#[cfg(feature = "desktop")] +use is_executable::IsExecutable; +use serde::{Deserialize, Serialize}; +use serde_json::json; +use serde_json::Value; +use tempfile::NamedTempFile; +use tracing::{debug, info, trace}; +use url::Url; + +use upend_base::addressing::AddressComponents; +use upend_base::addressing::{Address, Addressable}; +use upend_base::constants::{ATTR_ADDED, ATTR_LABEL}; +use upend_base::entry::{Entry, EntryValue, InvariantEntry}; +use upend_base::hash::{b58_decode, b58_encode, sha256hash}; +use upend_db::hierarchies::list_roots; +use upend_db::jobs; +use upend_db::stores::{Blob, UpStore}; +use upend_db::UpEndDatabase; + use crate::common::build; use crate::common::REQWEST_CLIENT; use crate::config::UpEndConfig; use crate::extractors; use crate::previews::PreviewStore; use crate::util::exec::block_background; -use actix_files::NamedFile; -use actix_multipart::Multipart; -use actix_web::error::{ - ErrorBadRequest, ErrorInternalServerError, ErrorNotFound, ErrorUnauthorized, -}; -use actix_web::http::header::ContentDisposition; -use actix_web::{ - delete, error, get, post, put, routes, web, Either, Error, HttpResponse, ResponseError, -}; -use actix_web::{http, Responder}; -use actix_web::{ - http::header::{CacheControl, CacheDirective, DispositionType}, - HttpRequest, -}; -use anyhow::Result; -use futures::channel::oneshot; -use futures_util::{StreamExt, TryStreamExt}; -use serde::{Deserialize, Serialize}; -use serde_json::json; -use std::collections::HashMap; -use std::convert::{TryFrom, TryInto}; -use std::io::Write; -use std::sync::Arc; -use std::time::{SystemTime, UNIX_EPOCH}; -use tempfile::NamedTempFile; -use tracing::{debug, info, trace}; -use upend_base::addressing::AddressComponents; -use upend_base::addressing::{Address, Addressable}; -use upend_base::constants::{ATTR_ADDED, ATTR_LABEL}; -use upend_base::entry::{Entry, EntryValue, InvariantEntry}; -use upend_base::hash::{b58_decode, b58_encode, sha256hash}; -use upend_base::lang::Query; -use upend_db::hierarchies::{list_roots, resolve_path, UHierPath}; -use upend_db::jobs; -use upend_db::stores::{Blob, UpStore}; -use upend_db::UpEndDatabase; -use url::Url; - -#[cfg(feature = "desktop")] -use is_executable::IsExecutable; #[derive(Clone)] -pub struct State { +pub struct ApiState { pub upend: Arc, pub store: Arc>, pub config: UpEndConfig, @@ -60,61 +53,106 @@ struct JwtClaims { exp: usize, } +pub fn get_router() { + let app = Router::new() + .route("/auth/login", post(login)) + .route("/raw/:hash", get(get_raw)) + .route("/thumb/:hash", get(get_thumbnail)) + .route("/query", get(get_query)) + .route( + "/obj/:address", + get(get_object).put(put_object).delete(delete_object), + ) + .route("/blob", put(put_blob)) + .route("/obj/:address/:attribute", put(put_object_attribute)) + .route("/address", get(get_address)) + .route("/all/attributes", get(get_all_attributes)) + .route("/hier/:path", get(list_hier).put(list_hier)) + .route("/hier_roots", get(list_hier_roots)) + .route("/jobs", get(get_jobs)); +} + +pub type Result = std::result::Result; + +pub enum ApiError { + Other(anyhow::Error), + Unauthorized(String), + NotFound(String), + BadRequest(String), + NotImplemented(String), +} + +impl From for ApiError { + fn from(err: anyhow::Error) -> Self { + ApiError::Other(err) + } +} + +impl IntoResponse for ApiError { + fn into_response(self) -> Response { + match self { + ApiError::Other(err) => { + (StatusCode::INTERNAL_SERVER_ERROR, err.to_string()).into_response() + } + ApiError::Unauthorized(err) => (StatusCode::UNAUTHORIZED, err).into_response(), + ApiError::NotFound(err) => (StatusCode::NOT_FOUND, err).into_response(), + ApiError::BadRequest(err) => (StatusCode::BAD_REQUEST, err).into_response(), + ApiError::NotImplemented(err) => (StatusCode::NOT_IMPLEMENTED, err).into_response(), + } + } +} + #[derive(Deserialize)] pub struct LoginRequest { key: String, } -#[post("/api/auth/login")] +// #[post("/api/auth/login")] pub async fn login( - state: web::Data, - payload: web::Json, -) -> Result { + State(state): State>, + Json(payload): Json, +) -> Result> { if state.config.key.is_none() || Some(&payload.key) == state.config.key.as_ref() { let claims = JwtClaims { - exp: (SystemTime::now() - .duration_since(UNIX_EPOCH) - .map_err(ErrorInternalServerError)? - .as_secs() - + 7 * 24 * 60 * 60) as usize, + exp: (SystemTime::now().duration_since(UNIX_EPOCH)?.as_secs() + 7 * 24 * 60 * 60) + as usize, }; let token = jsonwebtoken::encode( &jsonwebtoken::Header::default(), &claims, &jsonwebtoken::EncodingKey::from_secret(state.config.secret.as_ref()), - ) - .map_err(ErrorInternalServerError)?; + )?; - Ok(HttpResponse::Ok().json(json!({ "token": token }))) + Ok(Json::from(json!({ "token": token }))) } else { - Err(ErrorUnauthorized("Incorrect token.")) + Err(ApiError::Unauthorized("Incorrect token.".to_owned())) } } -fn check_auth(req: &HttpRequest, state: &State) -> Result<(), actix_web::Error> { - if let Some(key) = &state.config.key { - if let Some(auth_header) = req.headers().get("Authorization") { - let auth_header = auth_header.to_str().map_err(|err| { - ErrorBadRequest(format!("Invalid value in Authorization header: {err:?}")) - })?; - - let token = jsonwebtoken::decode::( - auth_header, - &jsonwebtoken::DecodingKey::from_secret(key.as_ref()), - &jsonwebtoken::Validation::default(), - ); - - token - .map(|_| ()) - .map_err(|err| ErrorUnauthorized(format!("Invalid token: {err:?}"))) - } else { - Err(ErrorUnauthorized("Authorization required.")) - } - } else { - Ok(()) - } -} +// fn check_auth(req: &HttpRequest, state: &ApiState) -> Result<(), actix_web::Error> { +// if let Some(key) = &state.config.key { +// if let Some(auth_header) = req.headers().get("Authorization") { +// let auth_header = auth_header.to_str().map_err(|err| { +// ErrorBadRequest(format!("Invalid value in Authorization header: {err:?}")) +// })?; +// +// let token = jsonwebtoken::decode::( +// auth_header, +// &jsonwebtoken::DecodingKey::from_secret(key.as_ref()), +// &jsonwebtoken::Validation::default(), +// ); +// +// token +// .map(|_| ()) +// .map_err(|err| ErrorUnauthorized(format!("Invalid token: {err:?}"))) +// } else { +// Err(ErrorUnauthorized("Authorization required.")) +// } +// } else { +// Ok(()) +// } +// } #[derive(Deserialize)] pub struct RawRequest { @@ -122,23 +160,19 @@ pub struct RawRequest { inline: Option, } -#[get("/api/raw/{hash}")] +// #[get("/api/raw/{hash}")] pub async fn get_raw( - state: web::Data, - web::Query(query): web::Query, - hash: web::Path, -) -> Result { - let address = - Address::decode(&b58_decode(hash.into_inner()).map_err(ErrorInternalServerError)?) - .map_err(ErrorInternalServerError)?; + State(state): State>, + Query(query): Query, + Path(hash): Path, +) -> Result<()> { + let address = Address::decode(&b58_decode(hash.into_inner())?)?; if let Address::Hash(hash) = address { let hash = Arc::new(hash); let _hash = hash.clone(); let _store = state.store.clone(); - let blobs = web::block(move || _store.retrieve(_hash.as_ref())) - .await? - .map_err(ErrorInternalServerError)?; + let blobs = tokio::task::spawn_blocking(move || _store.retrieve(_hash.as_ref())).await??; if let Some(blob) = blobs.get(0) { let file_path = blob.get_file_path(); @@ -180,9 +214,9 @@ pub async fn get_raw( http::header::WARNING.to_string(), )); - file_path.parent().ok_or_else(|| { - ErrorInternalServerError("No parent to open as fallback.") - })? + file_path + .parent() + .ok_or_else(|| anyhow!("No parent to open as fallback."))? }; opener::open(path).map_err(error::ErrorServiceUnavailable)?; return Ok(Either::Right(response.finish())); @@ -191,38 +225,36 @@ pub async fn get_raw( #[cfg(not(feature = "desktop"))] unreachable!() } else { - return Err(error::ErrorNotImplemented("Desktop features not enabled.")); + return Err(ApiError::NotImplemented("Desktop features not enabled.")); } } - let connection = state.upend.connection().map_err(ErrorInternalServerError)?; + let connection = state.upend.connection()?; let _hash = hash.clone(); - let entry = web::block(move || connection.retrieve_entry(_hash.as_ref())) - .await? - .map_err(ErrorInternalServerError)?; + let entry = tokio::task::spawn_blocking(move || connection.retrieve_entry(_hash.as_ref())) + .await??; if let Some(entry) = entry { return Ok(Either::Right(HttpResponse::Ok().json(entry))); } - Err(error::ErrorNotFound("NOT FOUND")) + Err(ApiError::NotFound("NOT FOUND")) } else { - Err(ErrorBadRequest( + Err(ApiError::BadRequest( "Address does not refer to a rawable object.", )) } } -#[get("/api/thumb/{hash}")] +// #[get("/api/thumb/{hash}")] pub async fn get_thumbnail( - state: web::Data, - hash: web::Path, - web::Query(query): web::Query>, + State(state): State>, + Path(hash): Path, + Query(query): Query>, ) -> Result, Error> { #[cfg(feature = "previews")] if let Some(preview_store) = &state.preview_store { let hash = hash.into_inner(); - let address = Address::decode(&b58_decode(&hash).map_err(ErrorInternalServerError)?) - .map_err(ErrorInternalServerError)?; + let address = Address::decode(&b58_decode(&hash)?)?; if let Address::Hash(address_hash) = address { let preview_store = preview_store.clone(); let (tx, rx) = oneshot::channel(); @@ -232,7 +264,7 @@ pub async fn get_thumbnail( tx.send(result).unwrap(); }); - let preview_result = rx.await.unwrap().map_err(ErrorInternalServerError)?; + let preview_result = rx.await.unwrap()?; if let Some(preview_path) = preview_result { let mut file = NamedFile::open(&preview_path)?.disable_content_disposition(); @@ -258,27 +290,18 @@ pub async fn get_thumbnail( Err(error::ErrorNotImplemented("Previews not enabled.")) } -#[post("/api/query")] -pub async fn get_query(state: web::Data, query: String) -> Result { - let connection = state.upend.connection().map_err(ErrorInternalServerError)?; +// #[post("/api/query")] +pub async fn get_query( + State(state): State>, + query: String, +) -> Result { + let connection = state.upend.connection()?; let in_query: Query = query.parse().map_err(ErrorBadRequest)?; - let entries = web::block(move || connection.query(in_query)) - .await - .map_err(ErrorInternalServerError)? - .map_err(ErrorInternalServerError)?; + let entries = tokio::task::spawn_blocking(move || connection.query(in_query)).await??; let mut result: HashMap = HashMap::new(); for entry in entries { - result.insert( - b58_encode( - entry - .address() - .map_err(ErrorInternalServerError)? - .encode() - .map_err(ErrorInternalServerError)?, - ), - entry, - ); + result.insert(b58_encode(entry.address()?.encode()?), entry); } Ok(HttpResponse::Ok().json(&result)) @@ -299,24 +322,23 @@ impl EntriesAsHash for Vec { } } -#[get("/api/obj/{address_str}")] +// #[get("/api/obj/{address_str}")] pub async fn get_object( - state: web::Data, + State(state): State>, address: web::Path
, ) -> Result { - let connection = state.upend.connection().map_err(ErrorInternalServerError)?; + let connection = state.upend.connection()?; let address = address.into_inner(); let _address = address.clone(); - let result: Vec = web::block(move || connection.retrieve_object(&_address)) - .await? - .map_err(ErrorInternalServerError)?; + let result: Vec = + tokio::task::spawn_blocking(move || connection.retrieve_object(&_address)).await??; trace!("{:?}", result); Ok(HttpResponse::Ok().json(json!({ "entity": address.as_components(), - "entries": result.as_hash().map_err(ErrorInternalServerError)? + "entries": result.as_hash()? }))) } @@ -358,17 +380,17 @@ pub struct UpdateQuery { provenance: Option, } -#[put("/api/obj")] +// #[put("/api/obj")] pub async fn put_object( req: HttpRequest, - state: web::Data, + State(state): State>, payload: web::Json, web::Query(query): web::Query, ) -> Result { check_auth(&req, &state)?; let (entry_address, entity_address) = { - let connection = state.upend.connection().map_err(ErrorInternalServerError)?; + let connection = state.upend.connection()?; let in_entry = payload.into_inner(); debug!("PUTting {in_entry:?}"); @@ -399,17 +421,16 @@ pub async fn put_object( match in_entry { PutInput::Entry(in_entry) => { let entry = process_inentry(in_entry).map_err(ErrorBadRequest)?; - web::block::<_, Result<_>>(move || { + tokio::task::spawn_blocking::<_, Result<_>>(move || { Ok(( Some(connection.insert_entry(entry.clone())?), Some(entry.entity), )) }) - .await? - .map_err(ErrorInternalServerError)? + .await?? } PutInput::EntryList(entries) => { - web::block(move || { + tokio::task::spawn_blocking(move || { connection.transaction::<_, anyhow::Error, _>(|| { for entry in entries { connection.insert_entry(process_inentry(entry)?)?; @@ -436,8 +457,8 @@ pub async fn put_object( Ok(()) }); - let connection = state.upend.connection().map_err(ErrorInternalServerError)?; - web::block(move || { + let connection = state.upend.connection()?; + tokio::task::spawn_blocking(move || { connection.transaction::<_, anyhow::Error, _>(|| { if connection.retrieve_object(&address)?.is_empty() { connection.insert_entry(Entry { @@ -462,8 +483,7 @@ pub async fn put_object( Ok((None, Some(address))) }) }) - .await? - .map_err(ErrorInternalServerError)? + .await?? } } }; @@ -471,10 +491,10 @@ pub async fn put_object( Ok(HttpResponse::Ok().json([entry_address, entity_address])) } -#[put("/api/blob")] +// #[put("/api/blob")] pub async fn put_blob( req: HttpRequest, - state: web::Data, + State(state): State>, mut payload: Multipart, ) -> Result { check_auth(&req, &state)?; @@ -495,7 +515,8 @@ pub async fn put_blob( let url = Url::parse(&url_buffer).map_err(ErrorBadRequest)?; let _url = url.clone(); - let (bytes, filename) = web::block(move || fetch_external(_url)).await??; + let (bytes, filename) = + tokio::task::spawn_blocking(move || fetch_external(_url)).await??; file.write_all(&bytes)?; ( @@ -504,7 +525,8 @@ pub async fn put_blob( ) } else { while let Some(chunk) = field.try_next().await? { - file = web::block(move || file.write_all(&chunk).map(|_| file)).await??; + file = tokio::task::spawn_blocking(move || file.write_all(&chunk).map(|_| file)) + .await??; } ( @@ -513,21 +535,20 @@ pub async fn put_blob( ) }; - let connection = state.upend.connection().map_err(ErrorInternalServerError)?; + let connection = state.upend.connection()?; let _store = state.store.clone(); let _filename = filename.clone(); - let hash = web::block(move || { + let hash = tokio::task::spawn_blocking(move || { _store.store(connection, Blob::from_filepath(file.path()), _filename) }) - .await? - .map_err(ErrorInternalServerError)?; + .await??; let address = Address::Hash(hash); - let connection = state.upend.connection().map_err(ErrorInternalServerError)?; + let connection = state.upend.connection()?; let _address = address.clone(); let _filename = filename.clone(); - let _ = web::block(move || { + let _ = tokio::task::spawn_blocking(move || { upend_insert_val!( &connection, _address, @@ -540,7 +561,7 @@ pub async fn put_blob( let _address = address.clone(); let _job_container = state.job_container.clone(); let _store = state.store.clone(); - let connection = state.upend.connection().map_err(ErrorInternalServerError)?; + let connection = state.upend.connection()?; block_background::<_, _, anyhow::Error>(move || { let entry_count = extractors::extract(&_address, &connection, _store, _job_container); debug!("Added {entry_count} extracted entries for {_address:?}"); @@ -552,19 +573,19 @@ pub async fn put_blob( } } -#[put("/api/obj/{address}/{attribute}")] +// #[put("/api/obj/{address}/{attribute}")] pub async fn put_object_attribute( req: HttpRequest, - state: web::Data, + State(state): State>, path: web::Path<(Address, String)>, value: web::Json, web::Query(query): web::Query, ) -> Result { check_auth(&req, &state)?; let (address, attribute) = path.into_inner(); - let connection = state.upend.connection().map_err(ErrorInternalServerError)?; + let connection = state.upend.connection()?; - let new_address = web::block(move || { + let new_address = tokio::task::spawn_blocking(move || { connection.transaction::<_, anyhow::Error, _>(|| { let existing_attr_entries = connection.query(format!(r#"(matches @{address} "{attribute}" ?)"#).parse()?)?; @@ -589,31 +610,29 @@ pub async fn put_object_attribute( connection.insert_entry(new_attr_entry) }) }) - .await? - .map_err(ErrorInternalServerError)?; + .await??; Ok(HttpResponse::Ok().json(new_address)) } -#[delete("/api/obj/{address_str}")] +// #[delete("/api/obj/{address_str}")] pub async fn delete_object( req: HttpRequest, - state: web::Data, + State(state): State>, address: web::Path
, ) -> Result { check_auth(&req, &state)?; - let connection = state.upend.connection().map_err(ErrorInternalServerError)?; - let _ = web::block(move || connection.remove_object(address.into_inner())) - .await - .map_err(ErrorInternalServerError)?; + let connection = state.upend.connection()?; + let _ = + tokio::task::spawn_blocking(move || connection.remove_object(address.into_inner())).await?; Ok(HttpResponse::Ok().finish()) } // #[post("api/obj/{address_str}")] // pub async fn update_attribute( -// state: web::Data, +// State(state): State>, // address_str: web::Path, // mut payload: web::Payload, // ) -> Result { @@ -622,7 +641,7 @@ pub async fn delete_object( // .map_err(error::ErrorBadRequest)?; // let entry_value = serde_json::from_slice::(&body).map_err(ErrorBadRequest)?; -// let connection = state.upend.connection().map_err(ErrorInternalServerError)?; +// let connection = state.upend.connection()?; // connection // .transaction::<_, anyhow::Error, _>(|| { @@ -631,12 +650,12 @@ pub async fn delete_object( // Ok(()) // }) -// .map_err(ErrorInternalServerError)?; +// ?; // Ok(HttpResponse::Ok().finish()) // } -#[get("/api/address")] +// #[get("/api/address")] pub async fn get_address( web::Query(query): web::Query>, ) -> Result { @@ -649,8 +668,8 @@ pub async fn get_address( ) } else if let Some(url) = query.get("url_content") { let url = Url::parse(url).map_err(ErrorBadRequest)?; - let (bytes, _) = web::block(|| fetch_external(url)).await??; - let hash_result = sha256hash(&bytes).map_err(ErrorInternalServerError)?; + let (bytes, _) = tokio::task::spawn_blocking(|| fetch_external(url)).await??; + let hash_result = sha256hash(&bytes)?; (Address::Hash(hash_result), false) } else if let Some(type_str) = query.get("type") { match type_str.as_str() { @@ -679,14 +698,12 @@ pub async fn get_address( Ok(response.json(format!("{}", address))) } -#[get("/api/all/attributes")] +// #[get("/api/all/attributes")] pub async fn get_all_attributes(state: web::Data) -> Result { - let connection = state.upend.connection().map_err(ErrorInternalServerError)?; - let attributes = web::block(move || connection.get_all_attributes()) - .await? - .map_err(ErrorInternalServerError)?; + let connection = state.upend.connection()?; + let attributes = tokio::task::spawn_blocking(move || connection.get_all_attributes()).await??; - let connection = state.upend.connection().map_err(ErrorInternalServerError)?; + let connection = state.upend.connection()?; let result: serde_json::Value = attributes .into_iter() .map(|attribute| { @@ -716,14 +733,14 @@ pub async fn get_all_attributes(state: web::Data) -> Result, + State(state): State>, path: web::Path, req: HttpRequest, ) -> Result { - let connection = state.upend.connection().map_err(ErrorInternalServerError)?; + let connection = state.upend.connection()?; if path.is_empty() { Ok(HttpResponse::MovedPermanently() .append_header((http::header::LOCATION, "../../api/hier_roots")) @@ -733,7 +750,7 @@ pub async fn list_hier( trace!(r#"Listing path "{}""#, upath); let create = !req.method().is_safe(); - let path = web::block(move || resolve_path(&connection, &upath, create)) + let path = tokio::task::spawn_blocking(move || resolve_path(&connection, &upath, create)) .await? .map_err(ErrorNotFound)?; match path.last() { @@ -745,21 +762,20 @@ pub async fn list_hier( } } -#[get("/api/hier_roots")] +// #[get("/api/hier_roots")] pub async fn list_hier_roots(state: web::Data) -> Result { - let connection = state.upend.connection().map_err(ErrorInternalServerError)?; + let connection = state.upend.connection()?; - let result = web::block(move || { + let result = tokio::task::spawn_blocking(move || { list_roots(&connection)? .into_iter() .map(|root| connection.retrieve_object(&root)) .collect::>>>() }) - .await? - .map_err(ErrorInternalServerError)? + .await?? .concat(); - Ok(HttpResponse::Ok().json(result.as_hash().map_err(ErrorInternalServerError)?)) + Ok(HttpResponse::Ok().json(result.as_hash()?)) } // #[derive(Deserialize)] @@ -767,10 +783,10 @@ pub async fn list_hier_roots(state: web::Data) -> Result, // } -#[post("/api/refresh")] +// #[post("/api/refresh")] pub async fn api_refresh( req: HttpRequest, - state: web::Data, + State(state): State>, // web::Query(query): web::Query, ) -> Result { check_auth(&req, &state)?; @@ -789,16 +805,16 @@ pub async fn api_refresh( Ok(HttpResponse::Ok().finish()) } -#[get("/api/stats/vault")] +// #[get("/api/stats/vault")] pub async fn vault_stats(state: web::Data) -> Result { - let connection = state.upend.connection().map_err(ErrorInternalServerError)?; - Ok(HttpResponse::Ok().json(connection.get_stats().map_err(ErrorInternalServerError)?)) + let connection = state.upend.connection()?; + Ok(HttpResponse::Ok().json(connection.get_stats()?)) } -#[get("/api/stats/store")] +// #[get("/api/stats/store")] pub async fn store_stats(state: web::Data) -> Result { Ok(HttpResponse::Ok().json(json!({ - "main": state.store.stats().map_err(ErrorInternalServerError)? + "main": state.store.stats()? }))) } @@ -807,15 +823,12 @@ pub struct JobsRequest { full: Option, } -#[get("/api/jobs")] +// #[get("/api/jobs")] pub async fn get_jobs( - state: web::Data, + State(state): State>, web::Query(query): web::Query, ) -> Result { - let jobs = state - .job_container - .get_jobs() - .map_err(ErrorInternalServerError)?; + let jobs = state.job_container.get_jobs()?; Ok(HttpResponse::Ok().json(if query.full.is_some() { jobs @@ -826,7 +839,7 @@ pub async fn get_jobs( })) } -#[get("/api/info")] +// #[get("/api/info")] pub async fn get_info(state: web::Data) -> Result { Ok(HttpResponse::Ok().json(json!({ "name": state.config.vault_name, @@ -841,15 +854,13 @@ pub async fn get_info(state: web::Data) -> Result { }))) } -#[get("/api/migration/user-entries")] +// #[get("/api/migration/user-entries")] pub async fn get_user_entries(state: web::Data) -> Result { - let connection = state.upend.connection().map_err(ErrorInternalServerError)?; + let connection = state.upend.connection()?; - let result = web::block(move || connection.get_explicit_entries()) - .await? - .map_err(ErrorInternalServerError)?; + let result = tokio::task::spawn_blocking(move || connection.get_explicit_entries()).await??; - Ok(HttpResponse::Ok().json(result.as_hash().map_err(ErrorInternalServerError)?)) + Ok(HttpResponse::Ok().json(result.as_hash()?)) } #[derive(Debug)] @@ -936,10 +947,10 @@ fn fetch_external(url: Url) -> Result<(bytes::Bytes, Option), ExternalFe mod tests { use std::fs::File; - use super::*; use anyhow::Result; use tempfile::TempDir; - use upend_base::hash::UpMultihash; + + use super::*; #[test] fn test_in_address() -> Result<()> { diff --git a/cli/src/serve.rs b/cli/src/serve.rs index 3f22e4a..6a5d23f 100644 --- a/cli/src/serve.rs +++ b/cli/src/serve.rs @@ -1,6 +1,8 @@ use crate::routes; use std::path::Path; +pub fn get_routes() {} + pub fn get_app( ui_path: Option

, allowed_origins: S,