From 13443af51d0f1fcfb259b31bf974bbb3cd02d976 Mon Sep 17 00:00:00 2001 From: Jeremy Wall Date: Tue, 9 Aug 2022 20:20:43 -0400 Subject: [PATCH] Switch to axum and use conditional compilation to handle the Send trait --- .vscode/settings.json | 3 +- Cargo.lock | 591 +++++++++++----------------------------- kitchen/Cargo.toml | 8 +- kitchen/src/main.rs | 2 +- kitchen/src/store.rs | 92 +++---- kitchen/src/web.rs | 150 +++++----- recipe-store/Cargo.toml | 1 + recipe-store/src/lib.rs | 61 ++--- web/Cargo.toml | 4 +- web/src/lib.rs | 1 + web/src/store.rs | 71 +++++ 11 files changed, 406 insertions(+), 578 deletions(-) create mode 100644 web/src/store.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index 9f01ac6..83ecb76 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,5 +1,6 @@ { "rust-analyzer.diagnostics.disabled": [ "macro-error" - ] + ], + "rust-analyzer.cargo.features": [] } \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index ee21281..c6c7ade 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -47,12 +47,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "anyhow" -version = "1.0.58" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb07d2053ccdbe10e2af2995a2f116c1330396493dc1269f6a91d0ae82e19704" - [[package]] name = "async-channel" version = "1.6.1" @@ -155,6 +149,17 @@ version = "4.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7a40729d2133846d9ed0ea60a8b9541bccddab49cd30f0715a1da672fe9a2524" +[[package]] +name = "async-trait" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76464446b8bc32758d7e88ee1a804d9914cd9b1cb264c029899680b0be29826f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "atomic-waker" version = "1.0.0" @@ -179,10 +184,49 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] -name = "base64" -version = "0.13.0" +name = "axum" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "9de18bc5f2e9df8f52da03856bf40e29b747de5a84e43aefff90e3dc4a21529b" +dependencies = [ + "async-trait", + "axum-core", + "bitflags", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "itoa 1.0.2", + "matchit", + "memchr", + "mime", + "percent-encoding", + "pin-project-lite", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "tokio", + "tower", + "tower-http", + "tower-layer", + "tower-service", +] + +[[package]] +name = "axum-core" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4f44a0e6200e9d11a1cdc989e4b358f6e3d354fbf48478f345a17f4e43f8635" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http", + "http-body", + "mime", +] [[package]] name = "bitflags" @@ -199,15 +243,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "block-buffer" -version = "0.10.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" -dependencies = [ - "generic-array", -] - [[package]] name = "blocking" version = "1.2.0" @@ -234,28 +269,12 @@ dependencies = [ "serde", ] -[[package]] -name = "buf_redux" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" -dependencies = [ - "memchr", - "safemem", -] - [[package]] name = "bumpalo" version = "3.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37ccbd214614c6783386c1af30caf03192f17891059cecc394b4fb119e363de3" -[[package]] -name = "byteorder" -version = "1.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" - [[package]] name = "bytes" version = "1.2.0" @@ -356,16 +375,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "crypto-common" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" -dependencies = [ - "generic-array", - "typenum", -] - [[package]] name = "csv" version = "1.1.6" @@ -407,16 +416,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "digest" -version = "0.10.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2fb860ca6fafa5552fb6d0e816a69c8e49f0908bf524e30a90d97c85892d506" -dependencies = [ - "block-buffer 0.10.2", - "crypto-common", -] - [[package]] name = "event-listener" version = "2.5.2" @@ -455,7 +454,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" dependencies = [ "futures-core", - "futures-sink", ] [[package]] @@ -504,11 +502,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" dependencies = [ "futures-core", - "futures-sink", "futures-task", "pin-project-lite", "pin-utils", - "slab", ] [[package]] @@ -575,56 +571,12 @@ dependencies = [ "web-sys", ] -[[package]] -name = "h2" -version = "0.3.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a82c6d637fc9515a4694bbf1cb2457b79d81ce52b3108bdeea58b07dd34a57" -dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap", - "slab", - "tokio", - "tokio-util 0.7.3", - "tracing", -] - [[package]] name = "hashbrown" version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -[[package]] -name = "headers" -version = "0.3.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cff78e5788be1e0ab65b04d306b2ed5092c815ec97ec70f4ebd5aee158aa55d" -dependencies = [ - "base64", - "bitflags", - "bytes", - "headers-core", - "http", - "httpdate", - "mime", - "sha-1 0.10.0", -] - -[[package]] -name = "headers-core" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" -dependencies = [ - "http", -] - [[package]] name = "hermit-abi" version = "0.1.19" @@ -656,6 +608,12 @@ dependencies = [ "pin-project-lite", ] +[[package]] +name = "http-range-header" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bfe8eed0a9285ef776bb792479ea3834e8b94e13d615c2f66d03dd50a435a29" + [[package]] name = "httparse" version = "1.7.1" @@ -678,7 +636,6 @@ dependencies = [ "futures-channel", "futures-core", "futures-util", - "h2", "http", "http-body", "httparse", @@ -692,40 +649,6 @@ dependencies = [ "want", ] -[[package]] -name = "idna" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "include_dir" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b56e147e6187d61e9d0f039f10e070d0c0a887e24fe0bb9ca3f29bfde62cab" -dependencies = [ - "include_dir_impl", - "proc-macro-hack", -] - -[[package]] -name = "include_dir_impl" -version = "0.6.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a0c890c85da4bab7bce4204c707396bbd3c6c8a681716a51c8814cfc2b682df" -dependencies = [ - "anyhow", - "proc-macro-hack", - "proc-macro2", - "quote", - "syn", -] - [[package]] name = "indexmap" version = "1.9.1" @@ -771,21 +694,25 @@ name = "kitchen" version = "0.2.9" dependencies = [ "async-std", + "async-trait", + "axum", "clap", "csv", + "mime_guess", "recipe-store", "recipes", - "static_dir", + "rust-embed", "tracing", "tracing-subscriber", - "warp", ] [[package]] name = "kitchen-wasm" version = "0.2.9" dependencies = [ + "async-trait", "console_error_panic_hook", + "recipe-store", "recipes", "reqwasm", "serde_json", @@ -906,6 +833,12 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" +[[package]] +name = "matchit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" + [[package]] name = "memchr" version = "2.5.0" @@ -940,24 +873,6 @@ dependencies = [ "windows-sys", ] -[[package]] -name = "multipart" -version = "0.18.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00dec633863867f29cb39df64a397cdf4a6354708ddd7759f70c7fb51c5f9182" -dependencies = [ - "buf_redux", - "httparse", - "log", - "mime", - "mime_guess", - "quick-error", - "rand", - "safemem", - "tempfile", - "twoway", -] - [[package]] name = "num-bigint" version = "0.4.3" @@ -1091,18 +1006,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "ppv-lite86" -version = "0.2.16" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" - -[[package]] -name = "proc-macro-hack" -version = "0.5.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5" - [[package]] name = "proc-macro2" version = "1.0.40" @@ -1112,12 +1015,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - [[package]] name = "quote" version = "1.0.20" @@ -1127,40 +1024,11 @@ dependencies = [ "proc-macro2", ] -[[package]] -name = "rand" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "libc", - "rand_chacha", - "rand_core", -] - -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core", -] - -[[package]] -name = "rand_core" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" -dependencies = [ - "getrandom", -] - [[package]] name = "recipe-store" version = "0.1.0" dependencies = [ + "async-trait", "recipes", ] @@ -1174,15 +1042,6 @@ dependencies = [ "num-rational", ] -[[package]] -name = "redox_syscall" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" -dependencies = [ - "bitflags", -] - [[package]] name = "regex" version = "1.6.0" @@ -1206,15 +1065,6 @@ version = "0.6.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a3f87b73ce11b1619a3c6332f45341e0047173771e8b8b73f87bfeefb7b56244" -[[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 = "reqwasm" version = "0.5.0" @@ -1224,6 +1074,40 @@ dependencies = [ "gloo-net", ] +[[package]] +name = "rust-embed" +version = "6.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a17e5ac65b318f397182ae94e532da0ba56b88dd1200b774715d36c4943b1c3" +dependencies = [ + "rust-embed-impl", + "rust-embed-utils", + "walkdir", +] + +[[package]] +name = "rust-embed-impl" +version = "6.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94e763e24ba2bf0c72bc6be883f967f794a019fafd1b86ba1daff9c91a7edd30" +dependencies = [ + "proc-macro2", + "quote", + "rust-embed-utils", + "syn", + "walkdir", +] + +[[package]] +name = "rust-embed-utils" +version = "7.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "756feca3afcbb1487a1d01f4ecd94cf8ec98ea074c55a69e7136d29fb6166029" +dependencies = [ + "sha2", + "walkdir", +] + [[package]] name = "ryu" version = "1.0.10" @@ -1231,16 +1115,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3f6f92acf49d1b98f7a81226834412ada05458b7364277387724a237f062695" [[package]] -name = "safemem" -version = "0.3.3" +name = "same-file" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" - -[[package]] -name = "scoped-tls" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea6a9290e3c9cf0f18145ef7ffa62d68ee0bf5fcd651017e586dc7fd5da448c2" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] [[package]] name = "serde" @@ -1286,29 +1167,18 @@ dependencies = [ ] [[package]] -name = "sha-1" -version = "0.9.8" +name = "sha2" +version = "0.9.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99cd6713db3cf16b6c84e06321e049a9b9f699826e16096d23bbcc44d15d51a6" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ - "block-buffer 0.9.0", + "block-buffer", "cfg-if", "cpufeatures", - "digest 0.9.0", + "digest", "opaque-debug", ] -[[package]] -name = "sha-1" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "028f48d513f9678cda28f6e4064755b3fbb2af6acd672f2c209b62323f7aea0f" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.3", -] - [[package]] name = "sharded-slab" version = "0.1.4" @@ -1349,23 +1219,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "static_dir" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8286dc044d09abcb8bf85440b94f2c41aee322733a58cd195cf830ee660cadf5" -dependencies = [ - "headers", - "http", - "hyper", - "include_dir", - "log", - "mime_guess", - "once_cell", - "urlencoding", - "warp", -] - [[package]] name = "strsim" version = "0.10.0" @@ -1429,18 +1282,10 @@ dependencies = [ ] [[package]] -name = "tempfile" -version = "3.3.0" +name = "sync_wrapper" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4" -dependencies = [ - "cfg-if", - "fastrand", - "libc", - "redox_syscall", - "remove_dir_all", - "winapi", -] +checksum = "20518fe4a4c9acf048008599e464deb21beeae3d3578418951a189c235a7a9a8" [[package]] name = "termcolor" @@ -1497,21 +1342,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "tinyvec" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" -dependencies = [ - "tinyvec_macros", -] - -[[package]] -name = "tinyvec_macros" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" - [[package]] name = "tokio" version = "1.20.0" @@ -1519,9 +1349,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57aec3cfa4c296db7255446efb4928a6be304b431a806216105542a67b6ca82e" dependencies = [ "autocfg", - "bytes", "libc", - "memchr", "mio", "num_cpus", "once_cell", @@ -1531,57 +1359,46 @@ dependencies = [ ] [[package]] -name = "tokio-stream" -version = "0.1.9" +name = "tower" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" dependencies = [ "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.15.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "511de3f85caf1c98983545490c3d09685fa8eb634e57eec22bb4db271f46cbd8" -dependencies = [ "futures-util", - "log", "pin-project", - "tokio", - "tungstenite", -] - -[[package]] -name = "tokio-util" -version = "0.6.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", - "log", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-util" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc463cd8deddc3770d20f9852143d50bf6094e640b485cb2e189a2099085ff45" -dependencies = [ - "bytes", - "futures-core", - "futures-sink", "pin-project-lite", "tokio", + "tower-layer", + "tower-service", "tracing", ] +[[package]] +name = "tower-http" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c530c8675c1dbf98facee631536fa116b5fb6382d7dd6dc1b118d970eafe3ba" +dependencies = [ + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "http-range-header", + "pin-project-lite", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "343bc9466d3fe6b0f960ef45960509f84480bf4fd96f92901afe7ff3df9d3a62" + [[package]] name = "tower-service" version = "0.3.2" @@ -1664,34 +1481,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" -[[package]] -name = "tungstenite" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0b2d8558abd2e276b0a8df5c05a2ec762609344191e5fd23e292c910e9165b5" -dependencies = [ - "base64", - "byteorder", - "bytes", - "http", - "httparse", - "log", - "rand", - "sha-1 0.9.8", - "thiserror", - "url", - "utf-8", -] - -[[package]] -name = "twoway" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" -dependencies = [ - "memchr", -] - [[package]] name = "typenum" version = "1.15.0" @@ -1707,51 +1496,12 @@ dependencies = [ "version_check", ] -[[package]] -name = "unicode-bidi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099b7128301d285f79ddd55b9a83d5e6b9e97c92e0ea0daebee7263e932de992" - [[package]] name = "unicode-ident" version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15c61ba63f9235225a22310255a29b806b907c9b8c964bcbd0a2c70f3f2deea7" -[[package]] -name = "unicode-normalization" -version = "0.1.21" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854cbdc4f7bc6ae19c820d44abdc3277ac3e1b2b93db20a636825d9322fb60e6" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "url" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" -dependencies = [ - "form_urlencoded", - "idna", - "matches", - "percent-encoding", -] - -[[package]] -name = "urlencoding" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a1f0175e03a0973cf4afd476bef05c26e228520400eb1fd473ad417b1c00ffb" - -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "valuable" version = "0.1.0" @@ -1780,6 +1530,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + [[package]] name = "want" version = "0.3.0" @@ -1790,36 +1551,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "warp" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cef4e1e9114a4b7f1ac799f16ce71c14de5778500c5450ec6b7b920c55b587e" -dependencies = [ - "bytes", - "futures-channel", - "futures-util", - "headers", - "http", - "hyper", - "log", - "mime", - "mime_guess", - "multipart", - "percent-encoding", - "pin-project", - "scoped-tls", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-stream", - "tokio-tungstenite", - "tokio-util 0.6.10", - "tower-service", - "tracing", -] - [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" diff --git a/kitchen/Cargo.toml b/kitchen/Cargo.toml index 8bd391e..90562c5 100644 --- a/kitchen/Cargo.toml +++ b/kitchen/Cargo.toml @@ -9,11 +9,13 @@ edition = "2021" [dependencies] tracing = "0.1.35" tracing-subscriber = "0.3.14" -recipes = {path = "../recipes" } +recipes = { path = "../recipes" } recipe-store = {path = "../recipe-store" } csv = "1.1.1" -warp = "0.3.2" -static_dir = "0.2.0" +axum = "0.5.13" +rust-embed="6.4.0" +mime_guess = "2.0.4" +async-trait = "0.1.57" [dependencies.clap] version = "3.2.16" diff --git a/kitchen/src/main.rs b/kitchen/src/main.rs index b9c2b17..32993ea 100644 --- a/kitchen/src/main.rs +++ b/kitchen/src/main.rs @@ -54,7 +54,7 @@ fn create_app<'a>() -> clap::App<'a> { #[instrument] fn main() { let matches = create_app().get_matches(); - let subscriber_builder = if let Some(verbosity) = matches.value_of("verbosity") { + let subscriber_builder = if let Some(verbosity) = matches.value_of("verbose") { // Se want verbosity level let level = match verbosity { "error" | "ERROR" => Level::ERROR, diff --git a/kitchen/src/store.rs b/kitchen/src/store.rs index 018142e..9d87090 100644 --- a/kitchen/src/store.rs +++ b/kitchen/src/store.rs @@ -12,15 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. use async_std::{ + fs::{read_dir, read_to_string, DirEntry, File}, io::{self, ReadExt}, path::PathBuf, stream::StreamExt, }; +use async_trait::async_trait; -use async_std::fs::{read_dir, read_to_string, DirEntry, File}; -use recipe_store::{MaybeAsync, RecipeStore}; use tracing::{info, instrument, warn}; +use recipe_store::RecipeStore; + pub struct AsyncFileStore { path: PathBuf, } @@ -31,63 +33,61 @@ impl AsyncFileStore { } } +#[async_trait] +// TODO(jwall): We need to model our own set of errors for this. impl RecipeStore for AsyncFileStore { - #[instrument(fields(path = ?self.path), skip_all)] - fn get_categories(&self) -> MaybeAsync, io::Error>> { + #[instrument(skip_all)] + async fn get_categories(&self) -> Result, io::Error> { let mut category_path = PathBuf::new(); category_path.push(&self.path); category_path.push("categories.txt"); - MaybeAsync::Async(Box::pin(async move { - let category_file = match File::open(&category_path).await { - Ok(f) => f, - Err(e) => { - if let io::ErrorKind::NotFound = e.kind() { - return Ok(None); - } - return Err(e); + let category_file = match File::open(&category_path).await { + Ok(f) => f, + Err(e) => { + if let io::ErrorKind::NotFound = e.kind() { + return Ok(None); } - }; - let mut buf_reader = io::BufReader::new(category_file); - let mut contents = Vec::new(); - if let Err(e) = buf_reader.read_to_end(&mut contents).await { return Err(e); } - match String::from_utf8(contents) { - Ok(s) => Ok(Some(s)), - Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)), - } - })) + }; + let mut buf_reader = io::BufReader::new(category_file); + let mut contents = Vec::new(); + if let Err(e) = buf_reader.read_to_end(&mut contents).await { + return Err(e); + } + match String::from_utf8(contents) { + Ok(s) => Ok(Some(s)), + Err(e) => Err(io::Error::new(io::ErrorKind::Other, e)), + } } - fn get_recipes(&self) -> MaybeAsync>, io::Error>> { + async fn get_recipes(&self) -> Result>, io::Error> { let mut recipe_path = PathBuf::new(); recipe_path.push(&self.path); recipe_path.push("recipes"); - MaybeAsync::Async(Box::pin(async move { - let mut entries = read_dir(&recipe_path).await?; - let mut entry_vec = Vec::new(); - // Special files that we ignore when fetching recipes - let filtered = vec!["menu.txt", "categories.txt"]; - while let Some(res) = entries.next().await { - let entry: DirEntry = res?; + let mut entries = read_dir(&recipe_path).await?; + let mut entry_vec = Vec::new(); + // Special files that we ignore when fetching recipes + let filtered = vec!["menu.txt", "categories.txt"]; + while let Some(res) = entries.next().await { + let entry: DirEntry = res?; - if !entry.file_type().await?.is_dir() - && !filtered - .iter() - .any(|&s| s == entry.file_name().to_string_lossy().to_string()) - { - // add it to the entry - info!("adding recipe file {}", entry.file_name().to_string_lossy()); - let recipe_contents = read_to_string(entry.path()).await?; - entry_vec.push(recipe_contents); - } else { - warn!( - file = %entry.path().to_string_lossy(), - "skipping file not a recipe", - ); - } + if !entry.file_type().await?.is_dir() + && !filtered + .iter() + .any(|&s| s == entry.file_name().to_string_lossy().to_string()) + { + // add it to the entry + info!("adding recipe file {}", entry.file_name().to_string_lossy()); + let recipe_contents = read_to_string(entry.path()).await?; + entry_vec.push(recipe_contents); + } else { + warn!( + file = %entry.path().to_string_lossy(), + "skipping file not a recipe", + ); } - Ok(Some(entry_vec)) - })) + } + Ok(Some(entry_vec)) } } diff --git a/kitchen/src/web.rs b/kitchen/src/web.rs index 364f4ac..8b50d99 100644 --- a/kitchen/src/web.rs +++ b/kitchen/src/web.rs @@ -13,13 +13,22 @@ // limitations under the License. use std::net::SocketAddr; use std::path::PathBuf; +use std::sync::Arc; use async_std::fs::{read_dir, read_to_string, DirEntry}; use async_std::stream::StreamExt; +use axum::{ + body::{boxed, Full}, + extract::Extension, + handler::Handler, + http::{header, StatusCode, Uri}, + response::{IntoResponse, Response}, + routing::{get, Router}, +}; +use mime_guess; use recipe_store::*; -use static_dir::static_dir; +use rust_embed::RustEmbed; use tracing::{info, instrument, warn}; -use warp::{http::StatusCode, hyper::Uri, Filter}; use crate::api::ParseError; use crate::store; @@ -52,67 +61,84 @@ pub async fn get_recipes(recipe_dir_path: PathBuf) -> Result, ParseE Ok(entry_vec) } +#[derive(RustEmbed)] +#[folder = "../web/dist"] +struct UiAssets; + +pub struct StaticFile(pub T); + +impl IntoResponse for StaticFile +where + T: Into, +{ + fn into_response(self) -> Response { + let path = self.0.into(); + + match UiAssets::get(path.as_str()) { + Some(content) => { + let body = boxed(Full::from(content.data)); + let mime = mime_guess::from_path(path).first_or_octet_stream(); + Response::builder() + .header(header::CONTENT_TYPE, mime.as_ref()) + .body(body) + .unwrap() + } + None => Response::builder() + .status(StatusCode::NOT_FOUND) + .body(boxed(Full::from("404"))) + .unwrap(), + } + } +} + +async fn ui_static_assets(uri: Uri) -> impl IntoResponse { + let path = uri + .path() + .trim_start_matches("/ui") + .trim_start_matches("/") + .to_string(); + + StaticFile(path) +} + +async fn api_recipes(Extension(store): Extension>) -> Response { + let recipe_future = store.get_recipes(); + let result: Result>, String> = + match recipe_future.await.map_err(|e| format!("Error: {:?}", e)) { + Ok(Some(recipes)) => Ok(axum::Json::from(recipes)), + Ok(None) => Ok(axum::Json::from(Vec::::new())), + Err(e) => Err(e), + }; + result.into_response() +} + +async fn api_categories(Extension(store): Extension>) -> Response { + let recipe_result = store + .get_categories() + .await + .map_err(|e| format!("Error: {:?}", e)); + let result: Result, String> = match recipe_result { + Ok(Some(categories)) => Ok(axum::Json::from(categories)), + Ok(None) => Ok(axum::Json::from(String::new())), + Err(e) => Err(e), + }; + result.into_response() +} + #[instrument(fields(recipe_dir=?recipe_dir_path,listen=?listen_socket), skip_all)] pub async fn ui_main(recipe_dir_path: PathBuf, listen_socket: SocketAddr) { - let root = warp::path::end().map(|| warp::redirect::found(Uri::from_static("/ui"))); - let ui = warp::path("ui").and(static_dir!("../web/dist")); let dir_path = recipe_dir_path.clone(); - - // recipes api path route - let recipe_path = warp::path("recipes").then(move || { - let dir_path = (&dir_path).clone(); - async { - let store = store::AsyncFileStore::new(dir_path); - let recipe_future = store.get_recipes().as_async(); - match recipe_future.await { - Ok(Ok(Some(recipes))) => { - warp::reply::with_status(warp::reply::json(&recipes), StatusCode::OK) - } - Ok(Ok(None)) => warp::reply::with_status( - warp::reply::json(&Vec::::new()), - StatusCode::OK, - ), - Ok(Err(e)) => warp::reply::with_status( - warp::reply::json(&format!("Error: {:?}", e)), - StatusCode::INTERNAL_SERVER_ERROR, - ), - Err(e) => warp::reply::with_status( - warp::reply::json(&format!("Error: {}", e)), - StatusCode::INTERNAL_SERVER_ERROR, - ), - } - } - }); - - // categories api path route - let categories_path = warp::path("categories").then(move || { - let dir_path = (&recipe_dir_path).clone(); - async move { - let store = store::AsyncFileStore::new(dir_path); - match store.get_categories().as_async().await { - Ok(Ok(Some(categories))) => { - warp::reply::with_status(warp::reply::json(&categories), StatusCode::OK) - } - Ok(Ok(None)) => warp::reply::with_status( - warp::reply::json(&Vec::::new()), - StatusCode::OK, - ), - Ok(Err(e)) => warp::reply::with_status( - warp::reply::json(&format!("Error: {:?}", e)), - StatusCode::INTERNAL_SERVER_ERROR, - ), - Err(e) => warp::reply::with_status( - warp::reply::json(&format!("Error: {}", e)), - StatusCode::INTERNAL_SERVER_ERROR, - ), - } - } - }); - let api = warp::path("api") - .and(warp::path("v1")) - .and(recipe_path.or(categories_path)); - - let routes = root.or(ui).or(api).with(warp::log("access log")); - - warp::serve(routes).run(listen_socket).await; + let store = Arc::new(store::AsyncFileStore::new(dir_path)); + //let dir_path = (&dir_path).clone(); + let mut router = Router::new() + .layer(Extension(store)) + .route("/ui", ui_static_assets.into_service()) + // recipes api path route + .route("/api/v1/recipes", get(api_recipes)) + // categories api path route + .route("/api/v1/categories", get(api_categories)); + axum::Server::bind(&listen_socket) + .serve(router.into_make_service()) + .await + .expect("Failed to start service"); } diff --git a/recipe-store/Cargo.toml b/recipe-store/Cargo.toml index 4e1a679..c19ac47 100644 --- a/recipe-store/Cargo.toml +++ b/recipe-store/Cargo.toml @@ -7,3 +7,4 @@ edition = "2021" [dependencies] recipes = {path = "../recipes" } +async-trait = "0.1.57" \ No newline at end of file diff --git a/recipe-store/src/lib.rs b/recipe-store/src/lib.rs index a6e05c4..0ea0d83 100644 --- a/recipe-store/src/lib.rs +++ b/recipe-store/src/lib.rs @@ -11,38 +11,7 @@ // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. -use std::{future::Future, pin::Pin}; - -pub enum MaybeAsync -where - T: Send, -{ - Sync(T), - // NOTE(jwall): For reasons I do not entirely understand yet - // You have to specify that this is both Future + Send because - // the compiler can't figure it out for you. - Async(Pin + Send>>), -} - -impl MaybeAsync -where - T: Send, -{ - pub async fn as_async(self) -> Result { - use MaybeAsync::{Async, Sync}; - match self { - Async(f) => Ok(f.await), - Sync(_) => Err("Something went very wrong. Attempted to use Sync as Async."), - } - } - pub fn as_sync(self) -> Result { - use MaybeAsync::{Async, Sync}; - match self { - Async(_) => Err("Something went very wrong. Attempted to use Async as Sync."), - Sync(v) => Ok(v), - } - } -} +use async_trait::async_trait; pub trait TenantStoreFactory where @@ -52,12 +21,36 @@ where fn get_user_store(&self, user: String) -> S; } +#[cfg(not(target_arch = "wasm32"))] +#[async_trait] +/// Define the shared interface to use for interacting with a store of recipes. pub trait RecipeStore where E: Send, { + // NOTE(jwall): For reasons I do not entirely understand yet + // You have to specify that these are both Future + Send below + // because the compiler can't figure it out for you. + /// Get categories text unparsed. - fn get_categories(&self) -> MaybeAsync, E>>; + async fn get_categories(&self) -> Result, E>; /// Get list of recipe text unparsed. - fn get_recipes(&self) -> MaybeAsync>, E>>; + async fn get_recipes(&self) -> Result>, E>; +} + +#[cfg(target_arch = "wasm32")] +#[async_trait(?Send)] +/// Define the shared interface to use for interacting with a store of recipes. +pub trait RecipeStore +where + E: Send, +{ + // NOTE(jwall): For reasons I do not entirely understand yet + // You have to specify that these are both Future + Send below + // because the compiler can't figure it out for you. + + /// Get categories text unparsed. + async fn get_categories(&self) -> Result, E>; + /// Get list of recipe text unparsed. + async fn get_recipes(&self) -> Result>, E>; } diff --git a/web/Cargo.toml b/web/Cargo.toml index 3b30397..e6d0cf7 100644 --- a/web/Cargo.toml +++ b/web/Cargo.toml @@ -13,13 +13,15 @@ default = ["web"] crate-type = ["cdylib", "rlib"] [dependencies] -recipes = {path = "../recipes" } +recipes = { path = "../recipes" } +recipe-store = { path = "../recipe-store" } reqwasm = "0.5.0" # This makes debugging panics more tractable. console_error_panic_hook = "0.1.7" serde_json = "1.0.79" tracing = "0.1.35" tracing-browser-subscriber = "0.1.0" +async-trait = "0.1.57" [dependencies.wasm-bindgen] # we need wasm-bindgen v0.2.81 exactly diff --git a/web/src/lib.rs b/web/src/lib.rs index ba81bbb..f414161 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -16,6 +16,7 @@ mod components; mod pages; mod router_integration; mod service; +mod store; mod web; use sycamore::prelude::*; diff --git a/web/src/store.rs b/web/src/store.rs new file mode 100644 index 0000000..dfdde26 --- /dev/null +++ b/web/src/store.rs @@ -0,0 +1,71 @@ +// Copyright 2022 Jeremy Wall (Jeremy@marzhilsltudios.com) +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +use async_trait::async_trait; +use std::sync::Arc; + +use reqwasm; +use tracing::debug; + +use recipe_store::RecipeStore; + +#[cfg(target_arch = "wasm32")] +pub struct HttpStore { + root: String, +} + +#[cfg(target_arch = "wasm32")] +impl HttpStore { + pub fn new(root: String) -> Self { + Self { root } + } +} + +#[cfg(target_arch = "wasm32")] +#[async_trait(?Send)] +impl RecipeStore for HttpStore { + async fn get_categories(&self) -> Result, String> { + let mut path = self.root.clone(); + path.push_str("/categories"); + let resp = match reqwasm::http::Request::get(&path).send().await { + Ok(resp) => resp, + Err(e) => return Err(format!("Error: {}", e)), + }; + if resp.status() == 404 { + debug!("Categories returned 404"); + Ok(None) + } else if resp.status() != 200 { + Err(format!("Status: {}", resp.status())) + } else { + debug!("We got a valid response back!"); + let resp = resp.text().await; + Ok(Some(resp.map_err(|e| format!("{}", e))?)) + } + } + + async fn get_recipes(&self) -> Result>, String> { + let mut path = self.root.clone(); + path.push_str("/recipes"); + let resp = match reqwasm::http::Request::get(&path).send().await { + Ok(resp) => resp, + Err(e) => return Err(format!("Error: {}", e)), + }; + if resp.status() != 200 { + Err(format!("Status: {}", resp.status())) + } else { + debug!("We got a valid response back!"); + Ok(resp.json().await.map_err(|e| format!("{}", e))?) + } + } + // +}