From f76c5b6389acc62c3c48bbdfa36acfbf4f100576 Mon Sep 17 00:00:00 2001 From: Anthony Dodd Date: Thu, 29 Jul 2021 11:10:04 -0500 Subject: [PATCH] Fully cut over to tokio Cut over to notify@0.5.0-pre.11. Much more simple interface, and works quite nicely with the async ecosystem. Cut over to axum for web server. Much better! The updated server stack is now more intelligently handling 404s. This is a common issue where users may end up making a request for some non-html static asset, but they get their path slightly wrong and are served the index.html instead of a 404. This typically results in users struggling to find the problem, and often times users have opened issues in GH. This updated algorithm will now evaluate 404s more closely and only respond with the index.html when the `accept` header allows for text/html or */*. Added an example demonstrating all proxy functionality. closes #198 closes #202 closes #209 --- .github/workflows/ci.yaml | 21 +- CHANGELOG.md | 14 +- Cargo.lock | 1857 ++++++++++------------------ Cargo.toml | 28 +- Trunk.toml | 4 +- examples/proxy/Cargo.lock | 210 ++++ examples/proxy/Cargo.toml | 11 + examples/proxy/README.md | 12 + examples/proxy/Trunk.toml | 28 + examples/proxy/docker-compose.yaml | 8 + examples/proxy/index.html | 10 + examples/proxy/src/main.rs | 19 + examples/seed/Cargo.toml | 2 +- examples/vanilla/Cargo.toml | 2 +- examples/yew/Cargo.toml | 2 +- src/build.rs | 20 +- src/cmd/clean.rs | 18 +- src/cmd/serve.rs | 15 +- src/cmd/watch.rs | 17 +- src/common.rs | 37 +- src/config/manifest.rs | 3 +- src/config/models.rs | 24 +- src/config/rt.rs | 4 +- src/main.rs | 2 +- src/pipelines/copy_dir.rs | 8 +- src/pipelines/copy_file.rs | 4 +- src/pipelines/css.rs | 4 +- src/pipelines/html.rs | 19 +- src/pipelines/icon.rs | 4 +- src/pipelines/inline.rs | 4 +- src/pipelines/mod.rs | 13 +- src/pipelines/rust_app.rs | 23 +- src/pipelines/rust_worker.rs | 10 +- src/pipelines/sass.rs | 9 +- src/proxy.rs | 278 +++-- src/serve.rs | 243 ++-- src/tools.rs | 155 ++- src/watch.rs | 118 +- 38 files changed, 1583 insertions(+), 1677 deletions(-) create mode 100644 examples/proxy/Cargo.lock create mode 100644 examples/proxy/Cargo.toml create mode 100644 examples/proxy/README.md create mode 100644 examples/proxy/Trunk.toml create mode 100644 examples/proxy/docker-compose.yaml create mode 100644 examples/proxy/index.html create mode 100644 examples/proxy/src/main.rs diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index 86a470dd..a912b0c4 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -86,9 +86,6 @@ jobs: uses: actions/checkout@v2 - name: Setup | Cache Cargo - # WHY? Because we are getting: error[E0463]: can't find crate for `structopt_derive` which `structopt` depends on - # only on macos when using the cache. - if: matrix.os != 'macos-latest' uses: actions/cache@v2 with: path: | @@ -102,10 +99,10 @@ jobs: - name: Setup | Cache Examples uses: actions/cache@v2 with: - path: examples/yew/target - key: wasm32-example-yew-debug-${{ hashFiles('examples/yew/Cargo.lock') }} + path: examples/proxy/target + key: wasm32-example-proxy-debug-${{ hashFiles('examples/proxy/Cargo.lock') }} restore-keys: | - wasm32-example-yew-debug- + wasm32-example-proxy-debug- - name: Setup | Cache Examples uses: actions/cache@v2 @@ -123,6 +120,14 @@ jobs: restore-keys: | wasm32-example-vanilla-debug- + - name: Setup | Cache Examples + uses: actions/cache@v2 + with: + path: examples/yew/target + key: wasm32-example-yew-debug-${{ hashFiles('examples/yew/Cargo.lock') }} + restore-keys: | + wasm32-example-yew-debug- + - name: Setup | Rust uses: actions-rs/toolchain@v1 with: @@ -139,8 +144,10 @@ jobs: # Build examples via our newly built debug artifact. - name: Build | Examples - run: ${{ matrix.binPath }} --config=examples/yew/Trunk.toml build + run: ${{ matrix.binPath }} --config=examples/proxy/Trunk.toml build - name: Build | Examples run: ${{ matrix.binPath }} --config=examples/seed/Trunk.toml build - name: Build | Examples run: ${{ matrix.binPath }} --config=examples/vanilla/Trunk.toml build + - name: Build | Examples + run: ${{ matrix.binPath }} --config=examples/yew/Trunk.toml build diff --git a/CHANGELOG.md b/CHANGELOG.md index 42bd3827..1b827410 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,8 +5,18 @@ This changelog follows the patterns described here: https://keepachangelog.com/e Subheadings to categorize changes are `added, changed, deprecated, removed, fixed, security`. ## Unreleased -### added -- Closed [#168](https://github.com/thedodd/trunk/issues/158): RSS feed for blog + +## 0.13.0 +- Trunk has been fully cut over to Tokio@1.x. +- As part of the Tokio cut over, the Trunk network stack is now fully based on Axum. +- All download utilities have been made fully async. This will likely help us in the future as we continue to leverage this functionality more and more. +- Added a new CLI option `trunk clean -t/--tools` which will optionally clean/remove any cached tools used by Trunk, such as `wasm-bindgen` & `wasm-opt`. This may be useful if there are ever issues with old tools which need to be removed. +- Fixed [#198](https://github.com/thedodd/trunk/issues/198) which was a long-standing issue with the static file server. In essence, Trunk will now check the `accept` header of any `GET` request matching the static file server, and if the requested asset does not exist and the `accept` header allows either `*/*` or `text/html`, then return the `index.html`. + - This is expected functionality for SPAs which are using client side routing. + - This reduces the friction which has often been observed with Trunk where a user is expecting a 404 to be served when requesting a static image, CSS, or some other asset. With this update, 404s will now be returned as expected, and the `index.html` should only be returned for applicable cases. +- Added a new `proxy` example which demonstrates all functionality of the Trunk proxy system. +- Fixed [#209](https://github.com/thedodd/trunk/issues/209) where the default Rust App pipeline was causing wasm-opt to be used even for debug builds when the Rust App HTML link was being omitted. +- Closed [#168](https://github.com/thedodd/trunk/issues/158): RSS feed for blog. ## 0.12.1 ### fixed diff --git a/Cargo.lock b/Cargo.lock index ce9de747..70d52faf 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -9,57 +9,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" [[package]] -name = "aead" -version = "0.3.2" +name = "aho-corasick" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fc95d1bdb8e6666b2b217308eeeb09f2d6728d104be3e31916cc74d15420331" +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" dependencies = [ - "generic-array", -] - -[[package]] -name = "aes" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "884391ef1066acaa41e766ba8f596341b96e93ce34f9a43e7d24bf0a0eaf0561" -dependencies = [ - "aes-soft", - "aesni", - "cipher", -] - -[[package]] -name = "aes-gcm" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5278b5fabbb9bd46e24aa69b2fdea62c99088e0a950a9be40e3e0101298f88da" -dependencies = [ - "aead", - "aes", - "cipher", - "ctr", - "ghash", - "subtle", -] - -[[package]] -name = "aes-soft" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be14c7498ea50828a38d0e24a765ed2effe92a705885b57d029cd67d45744072" -dependencies = [ - "cipher", - "opaque-debug", -] - -[[package]] -name = "aesni" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2e11f5e94c2f7d386164cc2aa1f97823fed6f259e486940a71c174dd01b0ce" -dependencies = [ - "cipher", - "opaque-debug", + "memchr", ] [[package]] @@ -68,7 +23,7 @@ version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -77,7 +32,7 @@ version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -87,251 +42,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" [[package]] -name = "arrayref" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" - -[[package]] -name = "arrayvec" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" - -[[package]] -name = "async-attributes" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3203e79f4dd9bdda415ed03cf14dae5a2bf775c683a00f94e9cd1faf0f596e5" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "async-channel" -version = "1.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2114d64672151c0c5eaa5e131ec84a74f06e1e559830dabba01ca30605d66319" -dependencies = [ - "concurrent-queue", - "event-listener", - "futures-core", -] - -[[package]] -name = "async-dup" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7427a12b8dc09291528cfb1da2447059adb4a257388c2acd6497a79d55cf6f7c" -dependencies = [ - "futures-io", - "simple-mutex", -] - -[[package]] -name = "async-executor" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "871f9bb5e0a22eeb7e8cf16641feb87c9dc67032ccf8ff49e772eb9941d3a965" -dependencies = [ - "async-task", - "concurrent-queue", - "fastrand", - "futures-lite", - "once_cell", - "slab", -] - -[[package]] -name = "async-global-executor" -version = "2.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9586ec52317f36de58453159d48351bc244bc24ced3effc1fce22f3d48664af6" -dependencies = [ - "async-channel", - "async-executor", - "async-io", - "async-mutex", - "blocking", - "futures-lite", - "num_cpus", - "once_cell", -] - -[[package]] -name = "async-h1" -version = "2.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc5142de15b549749cce62923a50714b0d7b77f5090ced141599e78899865451" -dependencies = [ - "async-channel", - "async-dup", - "async-std", - "byte-pool", - "futures-core", - "http-types", - "httparse", - "lazy_static", - "log", - "pin-project", -] - -[[package]] -name = "async-io" -version = "1.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a811e6a479f2439f0c04038796b5cfb3d2ad56c230e0f2d3f7b04d68cfee607b" -dependencies = [ - "concurrent-queue", - "futures-lite", - "libc", - "log", - "once_cell", - "parking", - "polling", - "slab", - "socket2", - "waker-fn", - "winapi 0.3.9", -] - -[[package]] -name = "async-lock" -version = "2.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6a8ea61bf9947a1007c5cada31e647dbc77b103c679858150003ba697ea798b" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-mutex" -version = "1.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" -dependencies = [ - "event-listener", -] - -[[package]] -name = "async-process" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f38756dd9ac84671c428afbf7c9f7495feff9ec5b0710f17100098e5b354ac" -dependencies = [ - "async-io", - "blocking", - "cfg-if 1.0.0", - "event-listener", - "futures-lite", - "libc", - "once_cell", - "signal-hook", - "winapi 0.3.9", -] - -[[package]] -name = "async-session" -version = "2.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "345022a2eed092cd105cc1b26fd61c341e100bd5fcbbd792df4baf31c2cc631f" -dependencies = [ - "anyhow", - "async-std", - "async-trait", - "base64 0.12.3", - "bincode", - "blake3", - "chrono", - "hmac 0.8.1", - "kv-log-macro", - "rand 0.7.3", - "serde", - "serde_json", - "sha2", -] - -[[package]] -name = "async-sse" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53bba003996b8fd22245cd0c59b869ba764188ed435392cf2796d03b805ade10" -dependencies = [ - "async-channel", - "async-std", - "http-types", - "log", - "memchr", - "pin-project-lite 0.1.12", -] - -[[package]] -name = "async-std" -version = "1.9.0" +name = "async-compression" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9f06685bad74e0570f5213741bea82158279a4103d988e57bfada11ad230341" +checksum = "5443ccbb270374a2b1055fc72da40e1f237809cd6bb0e97e66d264cd138473a6" dependencies = [ - "async-attributes", - "async-channel", - "async-global-executor", - "async-io", - "async-lock", - "async-process", - "crossbeam-utils", - "futures-channel", + "flate2", "futures-core", "futures-io", - "futures-lite", - "gloo-timers", - "kv-log-macro", - "log", "memchr", - "num_cpus", - "once_cell", - "pin-project-lite 0.2.7", - "pin-utils", - "slab", - "wasm-bindgen-futures", + "pin-project-lite", + "tokio", ] -[[package]] -name = "async-task" -version = "4.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91831deabf0d6d7ec49552e489aed63b7456a7a3c46cff62adad428110b0af0" - [[package]] name = "async-trait" -version = "0.1.50" +version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b98e84bbb4cbcdd97da190ba0c58a1bb0de2c1fdf67d159e192ed766aeca722" +checksum = "44318e776df68115a881de9a8fd1b9e53368d7a4a5ce4cc48517da3393233a5e" dependencies = [ "proc-macro2", "quote", "syn", ] -[[package]] -name = "async-tungstenite" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39eca8dd578b18e557361e50ca767df55c5e62f690a5e53868c3c7a8123145b7" -dependencies = [ - "async-std", - "futures-io", - "futures-util", - "log", - "pin-project", - "tungstenite", -] - -[[package]] -name = "atomic-waker" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065374052e7df7ee4047b1160cca5e1467a12351a40b3da123c870ba0b8eda2a" - [[package]] name = "atty" version = "0.2.14" @@ -340,7 +74,7 @@ checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ "hermit-abi", "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -350,16 +84,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" [[package]] -name = "base-x" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4521f3e3d031370679b3b140beb36dfe4801b09ac77e30c61941f97df3ef28b" - -[[package]] -name = "base64" -version = "0.12.3" +name = "axum" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" +checksum = "24f143b3839608f1254ac928abeffea9d654d9732162dcb6f0dd92bc022672f1" +dependencies = [ + "async-trait", + "base64", + "bytes", + "futures-util", + "http", + "http-body", + "hyper", + "pin-project", + "regex", + "serde", + "serde_json", + "serde_urlencoded", + "sha-1", + "tokio", + "tokio-tungstenite", + "tokio-util", + "tower", + "tower-http", +] [[package]] name = "base64" @@ -367,36 +115,12 @@ version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - [[package]] name = "bitflags" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -[[package]] -name = "blake3" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b64485778c4f16a6a5a9d335e80d449ac6c70cdd6a06d2af18a6f6f775a125b3" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if 0.1.10", - "constant_time_eq", - "crypto-mac 0.8.0", - "digest", -] - [[package]] name = "block-buffer" version = "0.9.0" @@ -406,67 +130,31 @@ dependencies = [ "generic-array", ] -[[package]] -name = "blocking" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e170dbede1f740736619b776d7251cb1b9095c435c34d8ca9f57fcd2f335e9" -dependencies = [ - "async-channel", - "async-task", - "atomic-waker", - "fastrand", - "futures-lite", - "once_cell", -] - [[package]] name = "bumpalo" version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" -[[package]] -name = "byte-pool" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c7230ddbb427b1094d477d821a99f3f54d36333178eeb806e279bcdcecf0ca" -dependencies = [ - "crossbeam-queue", - "stable_deref_trait", -] - [[package]] name = "byteorder" version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" -[[package]] -name = "bytes" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e4cec68f03f32e44924783795810fa50a7035d8c8ebe78580ad7e6c703fba38" - [[package]] name = "bytes" version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b700ce4376041dcd0a327fd0097c41095743c4c8af8887265942faf1100bd040" -[[package]] -name = "cache-padded" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "631ae5198c9be5e753e5cc215e1bd73c2b466a3565173db433f52bb9d3e66dba" - [[package]] name = "cargo-lock" version = "6.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6f16e7adc20969298b1e137ac21ab3a7e7a9412fec71f963ff2fdc41663d70f" dependencies = [ - "semver 0.11.0", + "semver", "serde", "toml", "url", @@ -488,8 +176,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7714a157da7991e23d90686b9524b9e12e0407a108647f52e9328f4b3d51ac7f" dependencies = [ "cargo-platform", - "semver 0.11.0", - "semver-parser 0.10.2", + "semver", + "semver-parser", "serde", "serde_json", ] @@ -500,12 +188,6 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e70cc2f62c6ce1868963827bd677764c62d07c3d9a3e1fb1177ee1a9ab199eb2" -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - [[package]] name = "cfg-if" version = "1.0.0" @@ -521,18 +203,8 @@ dependencies = [ "libc", "num-integer", "num-traits", - "serde", - "time 0.1.43", - "winapi 0.3.9", -] - -[[package]] -name = "cipher" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12f8e7987cbd042a63249497f41aed09f8e65add917ea6566effbc56578d6801" -dependencies = [ - "generic-array", + "time", + "winapi", ] [[package]] @@ -550,15 +222,6 @@ dependencies = [ "vec_map", ] -[[package]] -name = "concurrent-queue" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30ed07550be01594c6026cff2a1d7fe9c8f683caa798e12b68694ac9e88286a3" -dependencies = [ - "cache-padded", -] - [[package]] name = "console" version = "0.14.1" @@ -571,44 +234,15 @@ dependencies = [ "regex", "terminal_size", "unicode-width", - "winapi 0.3.9", + "winapi", ] -[[package]] -name = "const_fn" -version = "0.4.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f92cfa0fd5690b3cf8c1ef2cabbd9b7ef22fa53cf5e1f92b05103f6d5d1cf6e7" - -[[package]] -name = "constant_time_eq" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" - [[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.14.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03a5d7b21829bc7b4bf4754a978a241ae54ea55a40f92bb20216e54096f4b951" -dependencies = [ - "aes-gcm", - "base64 0.13.0", - "hkdf", - "hmac 0.10.1", - "percent-encoding", - "rand 0.8.4", - "sha2", - "time 0.2.27", - "version_check", -] - [[package]] name = "cpufeatures" version = "0.1.5" @@ -618,19 +252,13 @@ dependencies = [ "libc", ] -[[package]] -name = "cpuid-bool" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcb25d077389e53838a8158c8e99174c5a9d902dee4904320db714f3c653ffba" - [[package]] name = "crc32fast" version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] @@ -639,17 +267,17 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06ed27e177f16d65f0f0c22a213e17c696ace5dd64b14258b52f9417ccb52db4" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94af6efb46fef72616855b036a624cf27ba656ffc9be1b9a3c931cfc7749a9a9" +checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] @@ -660,53 +288,23 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec02e091aa634e2c3ada4a392989e7c3116673ef0ac5b72232439094d73b7fd" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crossbeam-utils", "lazy_static", "memoffset", "scopeguard", ] -[[package]] -name = "crossbeam-queue" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b10ddc024425c88c2ad148c1b0fd53f4c6d38db9697c9f1588381212fa657c9" -dependencies = [ - "cfg-if 1.0.0", - "crossbeam-utils", -] - [[package]] name = "crossbeam-utils" version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d82cfc11ce7f2c3faef78d8a684447b40d503d9681acebed6cb728d45940c4db" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "lazy_static", ] -[[package]] -name = "crypto-mac" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab" -dependencies = [ - "generic-array", - "subtle", -] - -[[package]] -name = "crypto-mac" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bff07008ec701e8028e2ceb8f83f0e4274ee62bd2dbdc4fefff2e9a91824081a" -dependencies = [ - "generic-array", - "subtle", -] - [[package]] name = "cssparser" version = "0.27.2" @@ -734,66 +332,6 @@ dependencies = [ "syn", ] -[[package]] -name = "ctor" -version = "0.1.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e98e2ad1a782e33928b96fc3948e7c355e5af34ba4de7670fe8bac2a3b2006d" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "ctr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb4a30d54f7443bf3d6191dcd486aca19e67cb3c49fa7a06a319966346707e7f" -dependencies = [ - "cipher", -] - -[[package]] -name = "curl" -version = "0.4.38" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "003cb79c1c6d1c93344c7e1201bb51c2148f24ec2bd9c253709d6b2efb796515" -dependencies = [ - "curl-sys", - "libc", - "openssl-probe", - "openssl-sys", - "schannel", - "socket2", - "winapi 0.3.9", -] - -[[package]] -name = "curl-sys" -version = "0.4.45+curl-7.78.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de9e5a72b1c744eb5dd20b2be4d7eb84625070bb5c4ab9b347b70464ab1e62eb" -dependencies = [ - "cc", - "libc", - "libnghttp2-sys", - "libz-sys", - "openssl-sys", - "pkg-config", - "vcpkg", - "winapi 0.3.9", -] - -[[package]] -name = "dashmap" -version = "4.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" -dependencies = [ - "cfg-if 1.0.0", - "num_cpus", -] - [[package]] name = "data-encoding" version = "2.3.2" @@ -809,7 +347,7 @@ dependencies = [ "convert_case", "proc-macro2", "quote", - "rustc_version 0.3.3", + "rustc_version", "syn", ] @@ -828,7 +366,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "339ee130d97a610ea5a5872d2bbb130fdf68884ff09d3028b81bec8a1ac23bbc" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "dirs-sys-next", ] @@ -840,15 +378,9 @@ checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" dependencies = [ "libc", "redox_users", - "winapi 0.3.9", + "winapi", ] -[[package]] -name = "discard" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d0f5754cb6769937f4501cc0e67f4f4483c8d2c3e1e922ee9edbe4ab4c7c0" - [[package]] name = "dtoa" version = "0.4.8" @@ -888,31 +420,28 @@ version = "0.8.28" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "80df024fbc5ac80f87dfef0d9f5209a252f2a497f7f42944cff24d8253cac065" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] -name = "envy" -version = "0.4.2" +name = "enum-as-inner" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f47e0157f2cb54f5ae1bd371b30a2ae4311e1c028f575cd4e81de7353215965" +checksum = "7c5f0096a91d210159eceb2ff5e1c4da18388a170e1e3ce948aac9c8fdbbf595" dependencies = [ - "serde", + "heck", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "event-listener" -version = "2.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7531096570974c3a9dcf9e4b8e1cede1ec26cf5046219fb3b9d897503b9be59" - -[[package]] -name = "fastrand" -version = "1.5.0" +name = "envy" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b394ed3d285a429378d3b384b9eb1285267e7df4b166df24b7a6939a04dc392e" +checksum = "3f47e0157f2cb54f5ae1bd371b30a2ae4311e1c028f575cd4e81de7353215965" dependencies = [ - "instant", + "serde", ] [[package]] @@ -921,10 +450,10 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d34cfa13a63ae058bfa601fe9e313bbdb3746427c1459185464ce0fcf62e1e8" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "redox_syscall", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -933,23 +462,12 @@ version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd3aec53de10fe96d7d8c565eb17f2c687bb5518a2ec453b5b1252964526abe0" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "crc32fast", "libc", "miniz_oxide", ] -[[package]] -name = "flume" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bebadab126f8120d410b677ed95eee4ba6eb7c6dd8e34a5ec88a08050e26132" -dependencies = [ - "futures-core", - "futures-sink", - "spinning_top", -] - [[package]] name = "fnv" version = "1.0.7" @@ -972,41 +490,15 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2022715d62ab30faffd124d40b76f4134a550a87792276512b18d63272333394" -[[package]] -name = "fsevent" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab7d1bd1bd33cc98b0889831b72da23c0aa4df9cec7e0702f46ecea04b35db6" -dependencies = [ - "bitflags", - "fsevent-sys", -] - [[package]] name = "fsevent-sys" -version = "2.0.1" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f41b048a94555da0f42f1d632e2e19510084fb8e303b0daa2816e733fb3644a0" +checksum = "5c0e564d24da983c053beff1bb7178e237501206840a3e6bf4e267b9e8ae734a" dependencies = [ "libc", ] -[[package]] -name = "fuchsia-zircon" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" -dependencies = [ - "bitflags", - "fuchsia-zircon-sys", -] - -[[package]] -name = "fuchsia-zircon-sys" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" - [[package]] name = "futf" version = "0.1.4" @@ -1065,21 +557,6 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b0e06c393068f3a6ef246c75cdca793d6a46347e75286933e5e75fd2fd11582" -[[package]] -name = "futures-lite" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694489acd39452c77daa48516b894c153f192c3578d5a839b62c58099fcbf48" -dependencies = [ - "fastrand", - "futures-core", - "futures-io", - "memchr", - "parking", - "pin-project-lite 0.2.7", - "waker-fn", -] - [[package]] name = "futures-macro" version = "0.3.16" @@ -1119,7 +596,7 @@ dependencies = [ "futures-sink", "futures-task", "memchr", - "pin-project-lite 0.2.7", + "pin-project-lite", "pin-utils", "proc-macro-hack", "proc-macro-nested", @@ -1151,7 +628,7 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi 0.9.0+wasi-snapshot-preview1", ] @@ -1162,33 +639,35 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "wasi 0.10.2+wasi-snapshot-preview1", ] [[package]] -name = "ghash" -version = "0.3.1" +name = "h2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97304e4cd182c3846f7575ced3890c53012ce534ad9114046b0a9e00bb30a375" +checksum = "825343c4eef0b63f541f8903f395dc5beb362a979b5799a84062527ef1e37726" dependencies = [ - "opaque-debug", - "polyval", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap", + "slab", + "tokio", + "tokio-util", + "tracing", ] [[package]] -name = "gloo-timers" -version = "0.2.1" +name = "hashbrown" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47204a46aaff920a1ea58b11d03dec6f704287d27561724a4631e450654a891f" -dependencies = [ - "futures-channel", - "futures-core", - "js-sys", - "wasm-bindgen", - "web-sys", -] +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" [[package]] name = "heck" @@ -1209,33 +688,14 @@ dependencies = [ ] [[package]] -name = "hkdf" -version = "0.10.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51ab2f639c231793c5f6114bdb9bbe50a7dbbfcd7c7c6bd8475dec2d991e964f" -dependencies = [ - "digest", - "hmac 0.10.1", -] - -[[package]] -name = "hmac" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840" -dependencies = [ - "crypto-mac 0.8.0", - "digest", -] - -[[package]] -name = "hmac" -version = "0.10.1" +name = "hostname" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1441c6b1e930e2817404b5046f1f989899143a12bf92de603b69f4e0aee1e15" +checksum = "3c731c3e10504cc8ed35cfe2f1db4c9274c3d35fa486e3b31df46f068ef3e867" dependencies = [ - "crypto-mac 0.10.1", - "digest", + "libc", + "match_cfg", + "winapi", ] [[package]] @@ -1258,53 +718,89 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "527e8c9ac747e28542699a951517aa9a6945af506cd1f2e1b53a576c17b6cc11" dependencies = [ - "bytes 1.0.1", + "bytes", "fnv", "itoa", ] [[package]] -name = "http-client" -version = "6.4.1" +name = "http-body" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce318d86a47d18d1db645c979214f809a6cd625202ad334ef75ca813b30dac80" +checksum = "60daa14be0e0786db0f03a9e57cb404c9d756eed2b6c62b9ea98ec5743ec75a9" dependencies = [ - "async-std", - "async-trait", - "cfg-if 1.0.0", - "dashmap", - "http-types", - "isahc", - "log", + "bytes", + "http", + "pin-project-lite", ] [[package]] -name = "http-types" -version = "2.11.1" +name = "httparse" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68" + +[[package]] +name = "httpdate" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6456b8a6c8f33fee7d958fcd1b60d55b11940a79e63ae87013e6d22e26034440" + +[[package]] +name = "hyper" +version = "0.14.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad077d89137cd3debdce53c66714dc536525ef43fe075d41ddc0a8ac11f85957" +checksum = "0b61cf2d1aebcf6e6352c97b81dc2244ca29194be1b276f5d8ad5c6330fffb11" dependencies = [ - "anyhow", - "async-channel", - "async-std", - "base64 0.13.0", - "cookie", - "futures-lite", - "infer", - "pin-project-lite 0.2.7", - "rand 0.7.3", - "serde", - "serde_json", - "serde_qs", - "serde_urlencoded", - "url", + "bytes", + "futures-channel", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "httparse", + "httpdate", + "itoa", + "pin-project-lite", + "socket2 0.4.1", + "tokio", + "tower-service", + "tracing", + "want", ] [[package]] -name = "httparse" -version = "1.4.1" +name = "hyper-rustls" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3a87b616e37e93c22fb19bcd386f02f3af5ea98a25670ad0fce773de23c5e68" +checksum = "5f9f7a97316d44c0af9b0301e65010573a853a9fc97046d7331d7f6bc0fd5a64" +dependencies = [ + "futures-util", + "hyper", + "log", + "rustls", + "tokio", + "tokio-rustls", + "webpki", +] + +[[package]] +name = "hyper-staticfile" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cf435f95723ba94d2e44991abf717dd547b73f505830a917dc442a9195df06b" +dependencies = [ + "chrono", + "futures-util", + "http", + "hyper", + "mime_guess", + "percent-encoding", + "tokio", + "url", + "winapi", +] [[package]] name = "idna" @@ -1318,16 +814,20 @@ dependencies = [ ] [[package]] -name = "infer" -version = "0.2.3" +name = "indexmap" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64e9829a50b42bb782c1df523f78d332fe371b10c661e78b7a3c34b0198e9fac" +checksum = "bc633605454125dec4b66843673f01c7df2b89479b32e0ed634e43a91cff62a5" +dependencies = [ + "autocfg", + "hashbrown", +] [[package]] name = "inotify" -version = "0.7.1" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4816c66d2c8ae673df83366c18341538f234a26d65a9ecea5c348b453ac1d02f" +checksum = "b031475cb1b103ee221afb806a23d35e0570bf7271d7588762ceba8127ed43b3" dependencies = [ "bitflags", "inotify-sys", @@ -1345,11 +845,11 @@ dependencies = [ [[package]] name = "input_buffer" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19a8a95243d5a0398cae618ec29477c6e3cb631152be5c19481f80bc71559754" +checksum = "f97967975f448f1a7ddb12b0bc41069d09ed6a1c161a92687e057325db35d413" dependencies = [ - "bytes 0.5.6", + "bytes", ] [[package]] @@ -1358,40 +858,26 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bee0328b1209d157ef001c94dd85b4f8f64139adb0eac2659f4b08382b2f474d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", ] [[package]] -name = "iovec" -version = "0.1.4" +name = "ipconfig" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e" +checksum = "f7e2f18aece9709094573a9f24f483c4f65caa4298e2f7ae1b71cc65d853fad7" dependencies = [ - "libc", + "socket2 0.3.19", + "widestring", + "winapi", + "winreg 0.6.2", ] [[package]] -name = "isahc" -version = "0.9.14" +name = "ipnet" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2948a0ce43e2c2ef11d7edf6816508998d99e13badd1150be0914205df9388a" -dependencies = [ - "bytes 0.5.6", - "crossbeam-utils", - "curl", - "curl-sys", - "flume", - "futures-lite", - "http", - "log", - "once_cell", - "slab", - "sluice", - "tracing", - "tracing-futures", - "url", - "waker-fn", -] +checksum = "68f2d64f2edebec4ce84ad108148e67e1064789bee435edc5b60ad398714a3a9" [[package]] name = "itoa" @@ -1401,30 +887,31 @@ checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736" [[package]] name = "js-sys" -version = "0.3.51" +version = "0.3.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" +checksum = "ce791b7ca6638aae45be056e068fc756d871eb3b3b10b8efa62d1c9cec616752" dependencies = [ "wasm-bindgen", ] [[package]] -name = "kernel32-sys" -version = "0.2.2" +name = "kqueue" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +checksum = "512705bfcaeb3d46379771adc69deab978355fc68fdf960f9fb11abc8d678a96" dependencies = [ - "winapi 0.2.8", - "winapi-build", + "kqueue-sys", + "libc", ] [[package]] -name = "kv-log-macro" -version = "1.0.7" +name = "kqueue-sys" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de8b303297635ad57c9f5059fd9cee7a47f8e8daa09df0fcd07dd39fb22977f" +checksum = "9803ae382091c10a5c7297ffb9fde284dbc9662b249f86eacef605d97ae92d99" dependencies = [ - "log", + "bitflags", + "libc", ] [[package]] @@ -1433,12 +920,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.98" @@ -1446,26 +927,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" [[package]] -name = "libnghttp2-sys" -version = "0.1.6+1.43.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0af55541a8827e138d59ec9e5877fb6095ece63fb6f4da45e7491b4fbd262855" -dependencies = [ - "cc", - "libc", -] - -[[package]] -name = "libz-sys" -version = "1.1.3" +name = "linked-hash-map" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de5435b8549c16d423ed0c03dbaafe57cf6c3344744f1242520d59c9d8ecec66" -dependencies = [ - "cc", - "libc", - "pkg-config", - "vcpkg", -] +checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" [[package]] name = "lock_api" @@ -1482,8 +947,16 @@ version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" dependencies = [ - "cfg-if 1.0.0", - "value-bag", + "cfg-if", +] + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", ] [[package]] @@ -1506,6 +979,12 @@ dependencies = [ "tendril", ] +[[package]] +name = "match_cfg" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" + [[package]] name = "matchers" version = "0.0.1" @@ -1564,56 +1043,24 @@ dependencies = [ [[package]] name = "mio" -version = "0.6.23" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4afd66f5b91bf2a3bc13fad0e21caedac168ca4c707504e75585648ae80e4cc4" +checksum = "8c2bdb6314ec10835cd3293dd268473a835c02b7b352e788be788b3c6ca6bb16" dependencies = [ - "cfg-if 0.1.10", - "fuchsia-zircon", - "fuchsia-zircon-sys", - "iovec", - "kernel32-sys", "libc", "log", "miow", - "net2", - "slab", - "winapi 0.2.8", -] - -[[package]] -name = "mio-extras" -version = "2.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19" -dependencies = [ - "lazycell", - "log", - "mio", - "slab", + "ntapi", + "winapi", ] [[package]] name = "miow" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebd808424166322d4a38da87083bfddd3ac4c131334ed55856112eb06d46944d" -dependencies = [ - "kernel32-sys", - "net2", - "winapi 0.2.8", - "ws2_32-sys", -] - -[[package]] -name = "net2" -version = "0.2.37" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "391630d12b68002ae1e25e8f974306474966550ad82dac6886fb8910c19568ae" +checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" dependencies = [ - "cfg-if 0.1.10", - "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -1643,20 +1090,29 @@ checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" [[package]] name = "notify" -version = "4.0.17" +version = "5.0.0-pre.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae03c8c853dba7bfd23e571ff0cff7bc9dceb40a4cd684cd1681824183f45257" +checksum = "c614e7ed2b1cf82ec99aeffd8cf6225ef5021b9951148eb161393c394855032c" dependencies = [ "bitflags", + "crossbeam-channel", "filetime", - "fsevent", "fsevent-sys", "inotify", + "kqueue", "libc", "mio", - "mio-extras", "walkdir", - "winapi 0.3.9", + "winapi", +] + +[[package]] +name = "ntapi" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f6bb902e437b6d86e03cce10a7e2af662292c5dfef23b65899ea3ac9354ad44" +dependencies = [ + "winapi", ] [[package]] @@ -1707,34 +1163,34 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcea7a30d6b81a2423cc59c43554880feff7b57d12916f231a79f8d6d9470201" dependencies = [ "pathdiff", - "winapi 0.3.9", + "winapi", ] [[package]] -name = "openssl-probe" -version = "0.1.4" +name = "parking_lot" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28988d872ab76095a6e6ac88d99b54fd267702734fd7ffe610ca27f533ddb95a" +checksum = "6d7744ac029df22dca6284efe4e898991d28e3085c706c972bcd7da4a27a15eb" +dependencies = [ + "instant", + "lock_api", + "parking_lot_core", +] [[package]] -name = "openssl-sys" -version = "0.9.65" +name = "parking_lot_core" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a7907e3bfa08bb85105209cdfcb6c63d109f8f6c1ed6ca318fff5c1853fbc1d" +checksum = "fa7a782938e745763fe6907fc6ba86946d72f49fe7e21de074e08128a99fb018" dependencies = [ - "autocfg", - "cc", + "cfg-if", + "instant", "libc", - "pkg-config", - "vcpkg", + "redox_syscall", + "smallvec", + "winapi", ] -[[package]] -name = "parking" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "427c3892f9e783d91cc128285287e70a59e206ca452770ece88a76f7a3eddd72" - [[package]] name = "pathdiff" version = "0.2.0" @@ -1830,12 +1286,6 @@ dependencies = [ "syn", ] -[[package]] -name = "pin-project-lite" -version = "0.1.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777" - [[package]] name = "pin-project-lite" version = "0.2.7" @@ -1854,30 +1304,6 @@ version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3831453b3449ceb48b6d9c7ad7c96d5ea673e9b470a1dc578c2ce6521230884c" -[[package]] -name = "polling" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92341d779fa34ea8437ef4d82d440d5e1ce3f3ff7f824aa64424cd481f9a1f25" -dependencies = [ - "cfg-if 1.0.0", - "libc", - "log", - "wepoll-ffi", - "winapi 0.3.9", -] - -[[package]] -name = "polyval" -version = "0.4.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eebcc4aa140b9abd2bc40d9c3f7ccec842679cd79045ac3a7ac698c1a064b7cd" -dependencies = [ - "cpuid-bool", - "opaque-debug", - "universal-hash", -] - [[package]] name = "ppv-lite86" version = "0.2.10" @@ -1935,6 +1361,12 @@ dependencies = [ "unicode-xid", ] +[[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.9" @@ -2085,6 +1517,8 @@ version = "1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" dependencies = [ + "aho-corasick", + "memchr", "regex-syntax", ] @@ -2109,7 +1543,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2121,22 +1555,68 @@ dependencies = [ "log", "num_cpus", "rayon", - "winapi 0.3.9", + "winapi", ] [[package]] -name = "route-recognizer" -version = "0.2.0" +name = "reqwest" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56770675ebc04927ded3e60633437841581c285dc6236109ea25fbf3beb7b59e" +checksum = "246e9f61b9bb77df069a947682be06e31ac43ea37862e244a69f177694ea6d22" +dependencies = [ + "base64", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "lazy_static", + "log", + "mime", + "percent-encoding", + "pin-project-lite", + "rustls", + "serde", + "serde_urlencoded", + "tokio", + "tokio-rustls", + "trust-dns-resolver", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots", + "winreg 0.7.0", +] [[package]] -name = "rustc_version" -version = "0.2.3" +name = "resolv-conf" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e44394d2086d010551b14b53b1f24e31647570cd1deb0379e2c21b329aba00" +dependencies = [ + "hostname", + "quick-error", +] + +[[package]] +name = "ring" +version = "0.16.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" dependencies = [ - "semver 0.9.0", + "cc", + "libc", + "once_cell", + "spin", + "untrusted", + "web-sys", + "winapi", ] [[package]] @@ -2145,7 +1625,20 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f0dfe2087c51c460008730de8b57e6a320782fbfb312e1f4d520e6c6fae155ee" dependencies = [ - "semver 0.11.0", + "semver", +] + +[[package]] +name = "rustls" +version = "0.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35edb675feee39aec9c99fa5ff985081995a06d594114ae14cbe797ad7b7a6d7" +dependencies = [ + "base64", + "log", + "ring", + "sct", + "webpki", ] [[package]] @@ -2185,22 +1678,22 @@ dependencies = [ "pkg-config", ] -[[package]] -name = "schannel" -version = "0.1.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f05ba609c234e60bee0d547fe94a4c7e9da733d1c962cf6e59efa4cd9c8bc75" -dependencies = [ - "lazy_static", - "winapi 0.3.9", -] - [[package]] name = "scopeguard" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "sct" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b362b83898e0e69f38515b82ee15aa80636befe47c3b6d3d89a911e78fc228ce" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "seahash" version = "4.1.0" @@ -2227,31 +1720,16 @@ dependencies = [ "thin-slice", ] -[[package]] -name = "semver" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" -dependencies = [ - "semver-parser 0.7.0", -] - [[package]] name = "semver" version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" dependencies = [ - "semver-parser 0.10.2", + "semver-parser", "serde", ] -[[package]] -name = "semver-parser" -version = "0.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" - [[package]] name = "semver-parser" version = "0.10.2" @@ -2263,18 +1741,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.126" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" +checksum = "f03b9878abf6d14e6779d3f24f07b2cfa90352cfec4acc5aab8f1ac7f146fae8" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.126" +version = "1.0.127" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" +checksum = "a024926d3432516606328597e0f224a51355a493b49fdd67e9209187cbe55ecc" dependencies = [ "proc-macro2", "quote", @@ -2283,27 +1761,15 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.64" +version = "1.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "799e97dc9fdae36a5c8b8f2cae9ce2ee9fdce2058c57a93e6099d919fd982f79" +checksum = "336b10da19a12ad094b59d870ebde26a45402e5b470add4b5fd03c5048a32127" dependencies = [ "itoa", "ryu", "serde", ] -[[package]] -name = "serde_qs" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5af82de3c6549b001bec34961ff2d6a54339a87bab37ce901b693401f27de6cb" -dependencies = [ - "data-encoding", - "percent-encoding", - "serde", - "thiserror", -] - [[package]] name = "serde_urlencoded" version = "0.7.0" @@ -2333,26 +1799,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1a0c8611594e2ab4ebbf06ec7cbbf0a99450b8570e96cbf5188b5d5f6ef18d81" dependencies = [ "block-buffer", - "cfg-if 1.0.0", - "cpufeatures", - "digest", - "opaque-debug", -] - -[[package]] -name = "sha1" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2579985fda508104f7587689507983eadd6a6e84dd35d6d115361f530916fa0d" - -[[package]] -name = "sha2" -version = "0.9.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b362ae5752fd2137731f9fa25fd4d9058af34666ca1966fb969119cc35719f12" -dependencies = [ - "block-buffer", - "cfg-if 1.0.0", + "cfg-if", "cpufeatures", "digest", "opaque-debug", @@ -2360,23 +1807,13 @@ dependencies = [ [[package]] name = "sharded-slab" -version = "0.1.1" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79c719719ee05df97490f80a45acfc99e5a30ce98a1e4fb67aee422745ae14e3" +checksum = "740223c51853f3145fe7c90360d2d4232f2b62e3449489c207eccde818979982" dependencies = [ "lazy_static", ] -[[package]] -name = "signal-hook" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "470c5a6397076fae0094aaf06a08e6ba6f37acb77d3b1b91ea92b4d6c8650c39" -dependencies = [ - "libc", - "signal-hook-registry", -] - [[package]] name = "signal-hook-registry" version = "1.4.0" @@ -2386,15 +1823,6 @@ dependencies = [ "libc", ] -[[package]] -name = "simple-mutex" -version = "1.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38aabbeafa6f6dead8cebf246fe9fae1f9215c8d29b3a69f93bd62a9e4a3dcd6" -dependencies = [ - "event-listener", -] - [[package]] name = "siphasher" version = "0.3.6" @@ -2407,17 +1835,6 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f173ac3d1a7e3b28003f40de0b5ce7fe2710f9b9dc3fc38664cebee46b3b6527" -[[package]] -name = "sluice" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fa0333a60ff2e3474a6775cc611840c2a55610c831dd366503474c02f1a28f5" -dependencies = [ - "futures-channel", - "futures-core", - "futures-io", -] - [[package]] name = "smallvec" version = "1.6.1" @@ -2426,86 +1843,36 @@ checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e" [[package]] name = "socket2" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dfc207c526015c632472a77be09cf1b6e46866581aecae5cc38fb4235dea2" -dependencies = [ - "libc", - "winapi 0.3.9", -] - -[[package]] -name = "spinning_top" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75adad84ee84b521fb2cca2d4fd0f1dab1d8d026bda3c5bea4ca63b5f9f9293c" -dependencies = [ - "lock_api", -] - -[[package]] -name = "stable_deref_trait" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" - -[[package]] -name = "standback" -version = "0.2.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e113fb6f3de07a243d434a56ec6f186dfd51cb08448239fe7bcae73f87ff28ff" -dependencies = [ - "version_check", -] - -[[package]] -name = "stdweb" -version = "0.4.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d022496b16281348b52d0e30ae99e01a73d737b2f45d38fed4edf79f9325a1d5" -dependencies = [ - "discard", - "rustc_version 0.2.3", - "stdweb-derive", - "stdweb-internal-macros", - "stdweb-internal-runtime", - "wasm-bindgen", -] - -[[package]] -name = "stdweb-derive" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c87a60a40fccc84bef0652345bbbbbe20a605bf5d0ce81719fc476f5c03b50ef" -dependencies = [ - "proc-macro2", - "quote", - "serde", - "serde_derive", - "syn", +version = "0.3.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "122e570113d28d773067fab24266b66753f6ea915758651696b6e35e49f88d6e" +dependencies = [ + "cfg-if", + "libc", + "winapi", ] [[package]] -name = "stdweb-internal-macros" -version = "0.2.9" +name = "socket2" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58fa5ff6ad0d98d1ffa8cb115892b6e69d67799f6763e162a1c9db421dc22e11" +checksum = "765f090f0e423d2b55843402a07915add955e7d60657db13707a159727326cad" dependencies = [ - "base-x", - "proc-macro2", - "quote", - "serde", - "serde_derive", - "serde_json", - "sha1", - "syn", + "libc", + "winapi", ] [[package]] -name = "stdweb-internal-runtime" -version = "0.1.5" +name = "spin" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "213701ba3370744dcd1a12960caa4843b3d68b4d1c0a5d575e0d65b2ee9d16c0" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "string_cache" @@ -2562,40 +1929,6 @@ dependencies = [ "syn", ] -[[package]] -name = "subtle" -version = "2.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" - -[[package]] -name = "surf" -version = "2.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a154d33ca6b5e1fe6fd1c760e5a5cc1202425f6cca2e13229f16a69009f6328" -dependencies = [ - "async-std", - "async-trait", - "cfg-if 1.0.0", - "encoding_rs", - "futures-util", - "http-client", - "http-types", - "log", - "mime_guess", - "once_cell", - "pin-project-lite 0.2.7", - "serde", - "serde_json", - "web-sys", -] - -[[package]] -name = "sval" -version = "1.0.0-alpha.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "45f6ee7c7b87caf59549e9fe45d6a69c75c8019e79e212a835c5da0e92f0ba08" - [[package]] name = "syn" version = "1.0.74" @@ -2607,29 +1940,18 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "tar" -version = "0.4.35" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d779dc6aeff029314570f666ec83f19df7280bb36ef338442cfa8c604021b80" -dependencies = [ - "filetime", - "libc", - "xattr", -] - [[package]] name = "tempfile" version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dac1c663cfc93810f88aed9b8941d48cabf856a1b111c29a40439018d870eb22" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "libc", "rand 0.8.4", "redox_syscall", "remove_dir_all 0.5.3", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2650,7 +1972,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "633c1a546cee861a1a6d0dc69ebeca693bf4296661ba7852b9d21d159e0506df" dependencies = [ "libc", - "winapi 0.3.9", + "winapi", ] [[package]] @@ -2698,107 +2020,125 @@ dependencies = [ ] [[package]] -name = "tide" -version = "0.16.0" +name = "time" +version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c459573f0dd2cc734b539047f57489ea875af8ee950860ded20cf93a79a1dee0" +checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" dependencies = [ - "async-h1", - "async-session", - "async-sse", - "async-std", - "async-trait", - "futures-util", - "http-client", - "http-types", - "kv-log-macro", - "log", - "pin-project-lite 0.2.7", - "route-recognizer", - "serde", - "serde_json", + "libc", + "winapi", ] [[package]] -name = "tide-websockets" -version = "0.3.0" +name = "tinyvec" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e779e18072c7b59c45bdd60a5611c27ee304c41b7c430532ac98de4d6e7d3a2d" +checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338" dependencies = [ - "async-dup", - "async-std", - "async-tungstenite", - "base64 0.13.0", - "futures-util", - "pin-project", - "serde", - "serde_json", - "sha-1", - "tide", + "tinyvec_macros", ] [[package]] -name = "time" -version = "0.1.43" +name = "tinyvec_macros" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" + +[[package]] +name = "tokio" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b7b349f11a7047e6d1276853e612d152f5e8a352c61917887cc2169e2366b4c" dependencies = [ + "autocfg", + "bytes", "libc", - "winapi 0.3.9", + "memchr", + "mio", + "num_cpus", + "once_cell", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "tokio-macros", + "winapi", ] [[package]] -name = "time" -version = "0.2.27" +name = "tokio-macros" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4752a97f8eebd6854ff91f1c1824cd6160626ac4bd44287f7f4ea2035a02a242" +checksum = "54473be61f4ebe4efd09cec9bd5d16fa51d70ea0192213d754d2d500457db110" dependencies = [ - "const_fn", - "libc", - "standback", - "stdweb", - "time-macros", - "version_check", - "winapi 0.3.9", + "proc-macro2", + "quote", + "syn", ] [[package]] -name = "time-macros" -version = "0.1.1" +name = "tokio-rustls" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "957e9c6e26f12cb6d0dd7fc776bb67a706312e7299aed74c8dd5b17ebb27e2f1" +checksum = "bc6844de72e57df1980054b38be3a9f4702aba4858be64dd700181a8a6d0e1b6" dependencies = [ - "proc-macro-hack", - "time-macros-impl", + "rustls", + "tokio", + "webpki", ] [[package]] -name = "time-macros-impl" -version = "0.1.2" +name = "tokio-stream" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3c141a1b43194f3f56a1411225df8646c55781d5f26db825b3d98507eb482f" +checksum = "7b2f3f698253f03119ac0102beaa64f67a67e08074d03a22d18784104543727f" dependencies = [ - "proc-macro-hack", - "proc-macro2", - "quote", - "standback", - "syn", + "futures-core", + "pin-project-lite", + "tokio", + "tokio-util", ] [[package]] -name = "tinyvec" -version = "1.3.1" +name = "tokio-tar" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "848a1e1181b9f6753b5e96a092749e29b11d19ede67dfbbd6c7dc7e0f49b5338" +checksum = "a50188549787c32c1c3d9c8c71ad7e003ccf2f102489c5a96e385c84760477f4" dependencies = [ - "tinyvec_macros", + "filetime", + "futures-core", + "libc", + "redox_syscall", + "tokio", + "tokio-stream", + "xattr", ] [[package]] -name = "tinyvec_macros" -version = "0.1.0" +name = "tokio-tungstenite" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1e96bb520beab540ab664bd5a9cfeaa1fcd846fa68c830b42e2c8963071251d2" +dependencies = [ + "futures-util", + "log", + "pin-project", + "tokio", + "tungstenite", +] + +[[package]] +name = "tokio-util" +version = "0.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1caa0b0c8d94a049db56b5acf8cba99dc0623aab1b26d5b5f5e2d945846b3592" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "tokio", +] [[package]] name = "toml" @@ -2809,15 +2149,60 @@ dependencies = [ "serde", ] +[[package]] +name = "tower" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60422bc7fefa2f3ec70359b8ff1caff59d785877eb70595904605bcc412470f" +dependencies = [ + "futures-core", + "futures-util", + "pin-project", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower-http" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b56efe69aa0ad2b5da6b942e57ea9f6fe683b7a314d4ff48662e2c8838de1" +dependencies = [ + "bytes", + "futures-core", + "futures-util", + "http", + "http-body", + "pin-project", + "tower-layer", + "tower-service", + "tracing", +] + +[[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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" + [[package]] name = "tracing" version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09adeb8c97449311ccd28a427f96fb563e7fd31aabf994189879d9da2394b89d" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "log", - "pin-project-lite 0.2.7", + "pin-project-lite", "tracing-attributes", "tracing-core", ] @@ -2842,16 +2227,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "tracing-futures" -version = "0.2.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97d095ae15e245a057c8e8451bab9b3ee1e1f68e9ba2b4fbc18d0ac5237835f2" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "tracing-log" version = "0.1.2" @@ -2897,59 +2272,114 @@ dependencies = [ [[package]] name = "trunk" -version = "0.12.1" +version = "0.13.0" dependencies = [ "ansi_term 0.12.1", "anyhow", - "async-process", - "async-std", - "async-tungstenite", + "async-compression", + "axum", + "bytes", "cargo-lock", "cargo_metadata", "console", "directories-next", "dunce", "envy", - "flate2", "fs_extra", "futures", - "http-types", + "http", + "hyper", + "hyper-staticfile", "lazy_static", "nipper", "notify", "open", "remove_dir_all 0.6.1", + "reqwest", "sass-rs", "seahash", "serde", "structopt", "structopt-derive", - "surf", - "tar", "tempfile", - "tide", - "tide-websockets", + "tokio", + "tokio-stream", + "tokio-tar", + "tokio-tungstenite", "toml", + "tower-http", "tracing", "tracing-subscriber", "which", ] +[[package]] +name = "trust-dns-proto" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0d7f5db438199a6e2609debe3f69f808d074e0a2888ee0bccb45fe234d03f4" +dependencies = [ + "async-trait", + "cfg-if", + "data-encoding", + "enum-as-inner", + "futures-channel", + "futures-io", + "futures-util", + "idna", + "ipnet", + "lazy_static", + "log", + "rand 0.8.4", + "smallvec", + "thiserror", + "tinyvec", + "tokio", + "url", +] + +[[package]] +name = "trust-dns-resolver" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ad17b608a64bd0735e67bde16b0636f8aa8591f831a25d18443ed00a699770" +dependencies = [ + "cfg-if", + "futures-util", + "ipconfig", + "lazy_static", + "log", + "lru-cache", + "parking_lot", + "resolv-conf", + "smallvec", + "thiserror", + "tokio", + "trust-dns-proto", +] + +[[package]] +name = "try-lock" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" + [[package]] name = "tungstenite" -version = "0.11.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0308d80d86700c5878b9ef6321f020f29b1bb9d5ff3cab25e75e23f3a492a23" +checksum = "5fe8dada8c1a3aeca77d6b51a4f1314e0f4b8e438b7b1b71e3ddaca8080e4093" dependencies = [ - "base64 0.12.3", + "base64", "byteorder", - "bytes 0.5.6", + "bytes", "http", "httparse", "input_buffer", "log", - "rand 0.7.3", + "rand 0.8.4", "sha-1", + "thiserror", "url", "utf-8", ] @@ -3012,14 +2442,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" [[package]] -name = "universal-hash" -version = "0.4.1" +name = "untrusted" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" -dependencies = [ - "generic-array", - "subtle", -] +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" [[package]] name = "url" @@ -3031,7 +2457,6 @@ dependencies = [ "idna", "matches", "percent-encoding", - "serde", ] [[package]] @@ -3040,23 +2465,6 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" -[[package]] -name = "value-bag" -version = "1.0.0-alpha.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd320e1520f94261153e96f7534476ad869c14022aee1e59af7c778075d840ae" -dependencies = [ - "ctor", - "sval", - "version_check", -] - -[[package]] -name = "vcpkg" -version = "0.2.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" - [[package]] name = "vec_map" version = "0.8.2" @@ -3069,12 +2477,6 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" -[[package]] -name = "waker-fn" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5b2c62b4012a3e1eca5a7e077d13b3bf498c4073e33ccd58626607748ceeca" - [[package]] name = "walkdir" version = "2.3.2" @@ -3082,10 +2484,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" dependencies = [ "same-file", - "winapi 0.3.9", + "winapi", "winapi-util", ] +[[package]] +name = "want" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +dependencies = [ + "log", + "try-lock", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -3100,19 +2512,21 @@ checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" [[package]] name = "wasm-bindgen" -version = "0.2.74" +version = "0.2.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" +checksum = "b608ecc8f4198fe8680e2ed18eccab5f0cd4caaf3d83516fa5fb2e927fda2586" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", + "serde", + "serde_json", "wasm-bindgen-macro", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.74" +version = "0.2.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" +checksum = "580aa3a91a63d23aac5b6b267e2d13cb4f363e31dce6c352fca4752ae12e479f" dependencies = [ "bumpalo", "lazy_static", @@ -3125,11 +2539,11 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.24" +version = "0.4.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fba7978c679d53ce2d0ac80c8c175840feb849a161664365d1287b41f2e67f1" +checksum = "16646b21c3add8e13fdb8f20172f8a28c3dbf62f45406bcff0233188226cfe0c" dependencies = [ - "cfg-if 1.0.0", + "cfg-if", "js-sys", "wasm-bindgen", "web-sys", @@ -3137,9 +2551,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.74" +version = "0.2.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" +checksum = "171ebf0ed9e1458810dfcb31f2e766ad6b3a89dbda42d8901f2b268277e5f09c" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -3147,9 +2561,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.74" +version = "0.2.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" +checksum = "6c2657dd393f03aa2a659c25c6ae18a13a4048cebd220e147933ea837efc589f" dependencies = [ "proc-macro2", "quote", @@ -3160,44 +2574,55 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.74" +version = "0.2.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" +checksum = "2e0c4a743a309662d45f4ede961d7afa4ba4131a59a639f29b0069c3798bbcc2" [[package]] name = "web-sys" -version = "0.3.51" +version = "0.3.52" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582" +checksum = "01c70a82d842c9979078c772d4a1344685045f1a5628f677c2b2eab4dd7d2696" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "wepoll-ffi" -version = "0.1.2" +name = "webpki" +version = "0.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d743fdedc5c64377b5fc2bc036b01c7fd642205a0d96356034ae3404d49eb7fb" +checksum = "b8e38c0608262c46d4a56202ebabdeb094cef7e560ca7a226c6bf055188aa4ea" dependencies = [ - "cc", + "ring", + "untrusted", +] + +[[package]] +name = "webpki-roots" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aabe153544e473b775453675851ecc86863d2a81d786d741f6b76778f2a48940" +dependencies = [ + "webpki", ] [[package]] name = "which" -version = "4.1.0" +version = "4.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b55551e42cbdf2ce2bedd2203d0cc08dba002c27510f86dab6d0ce304cba3dfe" +checksum = "ea187a8ef279bc014ec368c27a920da2024d2a711109bfbe3440585d5cf27ad9" dependencies = [ "either", + "lazy_static", "libc", ] [[package]] -name = "winapi" -version = "0.2.8" +name = "widestring" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" +checksum = "c168940144dd21fd8046987c16a46a33d5fc84eec29ef9dcddc2ac9e31526b7c" [[package]] name = "winapi" @@ -3209,12 +2634,6 @@ dependencies = [ "winapi-x86_64-pc-windows-gnu", ] -[[package]] -name = "winapi-build" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" - [[package]] name = "winapi-i686-pc-windows-gnu" version = "0.4.0" @@ -3227,7 +2646,7 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" dependencies = [ - "winapi 0.3.9", + "winapi", ] [[package]] @@ -3237,13 +2656,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "ws2_32-sys" -version = "0.2.1" +name = "winreg" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2986deb581c4fe11b621998a5e53361efe6b48a151178d0cd9eeffa4dc6acc9" +dependencies = [ + "winapi", +] + +[[package]] +name = "winreg" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" +checksum = "0120db82e8a1e0b9fb3345a539c478767c0048d842860994d96113d5b667bd69" dependencies = [ - "winapi 0.2.8", - "winapi-build", + "winapi", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 01c26714..3e520062 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "trunk" -version = "0.12.1" +version = "0.13.0" edition = "2018" description = "Build, bundle & ship your Rust WASM application to the web." license = "MIT/Apache-2.0" @@ -18,34 +18,38 @@ panic = "abort" [dependencies] ansi_term = "0.12" anyhow = "1" -async-process = "1" -async-std = { version = "1.9", default-features = false, features = ["attributes", "std", "unstable"] } -async-tungstenite = { version = "0.10", default-features = false, features = ["async-std-runtime"] } +async-compression = { version = "0.3", default-features = false, features = ["deflate", "futures-io", "gzip", "tokio"] } +axum = { version = "0.1", features = ["ws"] } +bytes = "1" cargo-lock = "6" cargo_metadata = "0.12" console = "0.14" directories-next = "2" dunce = "1" envy = "0.4" -flate2 = "1" fs_extra = "1" futures = "0.3" -http-types = "2" +http = "0.2" +hyper = "0.14" +hyper-staticfile = "0.6" lazy_static = "1" -nipper = "0.1.9" -notify = "4" +nipper = "0.1" +notify = "5.0.0-pre.11" open = "1" remove_dir_all = "0.6" +reqwest = { version = "0.11", default-features = false, features = ["rustls-tls", "stream", "trust-dns"] } sass-rs = "0.2" seahash = "4" serde = { version = "1", features = ["derive"] } structopt = "0.3" structopt-derive = "0.4" -surf = "2" -tar = "0.4" -tide = { version = "0.16.0", default-features = false, features = ["h1-server", "sessions", "unstable"] } -tide-websockets = "0.3.0" +# See https://docs.rs/tokio/latest/tokio/#feature-flags - we basically use all of the features. +tokio = { version = "1", default-features = false, features = ["full"] } +tokio-stream = { version = "0.1", default-features = false, features = ["fs", "time", "net", "signal", "sync"] } +tokio-tar = "0.3" +tokio-tungstenite = "0.14" toml = "0.5" +tower-http = { version = "0.1", features = ["trace"] } tracing = "0.1" tracing-subscriber = "0.2" which = "4" diff --git a/Trunk.toml b/Trunk.toml index c853cb5c..22903917 100644 --- a/Trunk.toml +++ b/Trunk.toml @@ -11,8 +11,8 @@ dist = "dist" public_url = "/" [watch] -# Paths to watch, defaults to build target parent folder. -path = ["src"] +# Paths to watch. The `build.target`'s parent folder is watched by default. +watch = [] # Paths to ignore. ignore = [] diff --git a/examples/proxy/Cargo.lock b/examples/proxy/Cargo.lock new file mode 100644 index 00000000..ecf62342 --- /dev/null +++ b/examples/proxy/Cargo.lock @@ -0,0 +1,210 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "bumpalo" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c59e7af012c713f529e7a3ee57ce9b31ddd858d4b512923602f74608b009631" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "console_error_panic_hook" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8d976903543e0c48546a91908f21588a680a8c8f984df9a5d69feccb2b2a211" +dependencies = [ + "cfg-if 0.1.10", + "wasm-bindgen", +] + +[[package]] +name = "js-sys" +version = "0.3.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83bdfbace3a0e81a4253f73b49e960b053e396a11012cbd49b9b74d6a2b67062" +dependencies = [ + "wasm-bindgen", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.98" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if 1.0.0", +] + +[[package]] +name = "memory_units" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8452105ba047068f40ff7093dd1d9da90898e63dd61736462e9cdda6a90ad3c3" + +[[package]] +name = "proc-macro2" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c7ed8b8c7b886ea3ed7dde405212185f423ab44682667c8c6dd14aa1d9f6612" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "proxy-example" +version = "0.1.0" +dependencies = [ + "console_error_panic_hook", + "wasm-bindgen", + "web-sys", + "wee_alloc", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "syn" +version = "1.0.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1873d832550d4588c3dbc20f01361ab00bfe741048f71e3fecf145a7cc18b29c" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "unicode-xid" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" + +[[package]] +name = "wasm-bindgen" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54ee1d4ed486f78874278e63e4069fc1ab9f6a18ca492076ffb90c5eb2997fd" +dependencies = [ + "cfg-if 1.0.0", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b33f6a0694ccfea53d94db8b2ed1c3a8a4c86dd936b13b9f0a15ec4a451b900" +dependencies = [ + "bumpalo", + "lazy_static", + "log", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "088169ca61430fe1e58b8096c24975251700e7b1f6fd91cc9d59b04fb9b18bd4" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be2241542ff3d9f241f5e2cb6dd09b37efe786df8851c54957683a49f0987a97" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7cff876b8f18eed75a66cf49b65e7f967cb354a7aa16003fb55dbfd25b44b4f" + +[[package]] +name = "web-sys" +version = "0.3.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e828417b379f3df7111d3a2a9e5753706cae29c41f7c4029ee9fd77f3e09e582" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "wee_alloc" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbb3b5a6b2bb17cb6ad44a2e68a43e8d2722c997da10e928665c72ec6c0a0b8e" +dependencies = [ + "cfg-if 0.1.10", + "libc", + "memory_units", + "winapi", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/examples/proxy/Cargo.toml b/examples/proxy/Cargo.toml new file mode 100644 index 00000000..f96a8ffe --- /dev/null +++ b/examples/proxy/Cargo.toml @@ -0,0 +1,11 @@ +[package] +name = "proxy-example" +version = "0.1.0" +authors = ["Anthony Dodd "] +edition = "2018" + +[dependencies] +console_error_panic_hook = "0.1" +web-sys = { version = "0.3", features = ["Window", "Document", "HtmlElement", "Node", "Text"] } +wasm-bindgen = "=0.2.74" +wee_alloc = "0.4" diff --git a/examples/proxy/README.md b/examples/proxy/README.md new file mode 100644 index 00000000..f52825c5 --- /dev/null +++ b/examples/proxy/README.md @@ -0,0 +1,12 @@ +Trunk Proxy +=========== +An example demonstrating how to use the Trunk proxy system for various HTTP endpoints as well as WebSockets. + +There isn't much going on in this example as far as WASM is concerned, but have a look at the [`Trunk.toml`](./Trunk.toml) in this directory for exhaustive examples on how to configure and use Trunk proxies. + +## Setup +First, in a shell terminal, execute `docker compose run --service-ports echo-server`. This will start an echo server container which we will use as a generic backend for the proxies we've defined in this example. + +Next, in a different shell tab or window, execute `trunk serve`. This will build the demo application and will ultimately start the Trunk proxies defined in the [`Trunk.toml`](./Trunk.toml). + +From here, use cURL, xh, websocat or any other tool you would like to verify the proxies' functionality. All normal HTTP requests will be echoed back, and all WebSocket messages will be echoed back. diff --git a/examples/proxy/Trunk.toml b/examples/proxy/Trunk.toml new file mode 100644 index 00000000..b5dfd7fd --- /dev/null +++ b/examples/proxy/Trunk.toml @@ -0,0 +1,28 @@ +[build] +target = "index.html" +dist = "dist" + +[[proxy]] +# This WebSocket proxy example has a backend and ws field. This example will listen for +# WebSocket connections at `/api/ws` and proxy them to `ws://localhost:9000/api/ws`. +backend = "ws://localhost:9090/api/ws" +ws = true + +[[proxy]] +# Same as above, except it will listen at `/api/websocket` and will +# proxy to `ws://localhost:9000/api/ws`. +rewrite = "/api/websocket" +backend = "ws://localhost:9090/api/ws" +ws = true + +[[proxy]] +# This proxy example has a backend and a rewrite field. Requests received on `rewrite` will be +# proxied to the backend after stripping the `rewrite`. +# E.G., `/api/v1/resource/x/y/z` -> `/resource/x/y/z` +rewrite = "/api/v1/" +backend = "http://localhost:9090/" + +[[proxy]] +# This proxy specifies only the backend, which is the only required field. In this example, +# request URIs are not modified when proxied. +backend = "http://localhost:9090/api/v2/" diff --git a/examples/proxy/docker-compose.yaml b/examples/proxy/docker-compose.yaml new file mode 100644 index 00000000..a1e5d0b1 --- /dev/null +++ b/examples/proxy/docker-compose.yaml @@ -0,0 +1,8 @@ +version: "3.9" +services: + echo-server: + image: jmalloc/echo-server:latest + ports: + - "9090:9090" + environment: + PORT: "9090" diff --git a/examples/proxy/index.html b/examples/proxy/index.html new file mode 100644 index 00000000..40b3c16f --- /dev/null +++ b/examples/proxy/index.html @@ -0,0 +1,10 @@ + + + + + + Trunk Proxy + + + + diff --git a/examples/proxy/src/main.rs b/examples/proxy/src/main.rs new file mode 100644 index 00000000..fcbdb581 --- /dev/null +++ b/examples/proxy/src/main.rs @@ -0,0 +1,19 @@ +#![recursion_limit = "1024"] + +#[global_allocator] +static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; + +use console_error_panic_hook::set_once as set_panic_hook; +use web_sys::window; + +fn start_app() { + let document = window().and_then(|win| win.document()).expect("could not access document"); + let body = document.body().expect("could not access document.body"); + let text_node = document.create_text_node("Trunk Proxy Demo App"); + body.append_child(text_node.as_ref()).expect("failed to append text"); +} + +fn main() { + set_panic_hook(); + start_app(); +} diff --git a/examples/seed/Cargo.toml b/examples/seed/Cargo.toml index eca51121..523eaa84 100644 --- a/examples/seed/Cargo.toml +++ b/examples/seed/Cargo.toml @@ -10,4 +10,4 @@ serde = "1.0" uuid = { version = "0.8", features = ["serde", "v4", "wasm-bindgen"] } indexmap = { version = "1", features = ["serde-1"] } enclose = "1" -wasm-bindgen = "=0.2.74" # This is pinned primarily for CI stability. +wasm-bindgen = "=0.2.74" diff --git a/examples/vanilla/Cargo.toml b/examples/vanilla/Cargo.toml index 2b62959b..810c814c 100644 --- a/examples/vanilla/Cargo.toml +++ b/examples/vanilla/Cargo.toml @@ -7,5 +7,5 @@ edition = "2018" [dependencies] console_error_panic_hook = "0.1" web-sys = { version = "0.3", features = ["Window", "Document", "HtmlElement", "Node", "Text"] } -wasm-bindgen = "=0.2.74" # This is pinned primarily for CI stability. +wasm-bindgen = "=0.2.74" wee_alloc = "0.4" diff --git a/examples/yew/Cargo.toml b/examples/yew/Cargo.toml index 930d4770..389e6b0f 100644 --- a/examples/yew/Cargo.toml +++ b/examples/yew/Cargo.toml @@ -6,7 +6,7 @@ edition = "2018" [dependencies] console_error_panic_hook = "0.1.6" -wasm-bindgen = "=0.2.74" # This is pinned primarily for CI stability. +wasm-bindgen = "=0.2.74" wee_alloc = "0.4.5" ybc = "0.2" yew = "0.18" diff --git a/src/build.rs b/src/build.rs index 8030b010..b16da43e 100644 --- a/src/build.rs +++ b/src/build.rs @@ -4,9 +4,10 @@ use std::path::PathBuf; use std::sync::Arc; use anyhow::{Context, Result}; -use async_std::fs; -use futures::channel::mpsc::Sender; -use futures::stream::StreamExt; +use futures::prelude::*; +use tokio::fs; +use tokio::sync::mpsc; +use tokio_stream::wrappers::ReadDirStream; use crate::common::{remove_dir_all, BUILDING, ERROR, SUCCESS}; use crate::config::{RtcBuild, STAGE_DIR}; @@ -30,7 +31,7 @@ impl BuildSystem { /// /// Reducing the number of assumptions here should help us to stay flexible when adding new /// commands, refactoring and the like. - pub async fn new(cfg: Arc, ignore_chan: Option>) -> Result { + pub async fn new(cfg: Arc, ignore_chan: Option>) -> Result { let html_pipeline = Arc::new(HtmlPipeline::new(cfg.clone(), ignore_chan)?); Ok(Self { cfg, html_pipeline }) } @@ -69,6 +70,7 @@ impl BuildSystem { .clone() .spawn() .await + .context("error joining HTML pipeline")? .context("error from HTML pipeline")?; // Move distribution from staging dist to final dist @@ -117,6 +119,7 @@ impl BuildSystem { let mut entries = fs::read_dir(&staging_dist) .await + .map(ReadDirStream::new) .context("error reading staging dist dir")?; while let Some(entry) = entries.next().await { let entry = entry.context("error reading contents of staging dist dir")?; @@ -133,7 +136,10 @@ impl BuildSystem { async fn clean_final(&self) -> Result<()> { let final_dist = self.cfg.final_dist.clone(); - let mut entries = fs::read_dir(&final_dist).await.context("error reading final dist dir")?; + let mut entries = fs::read_dir(&final_dist) + .await + .map(ReadDirStream::new) + .context("error reading final dist dir")?; while let Some(entry) = entries.next().await { let entry = entry.context("error reading contents of final dist dir")?; if entry.file_name() == STAGE_DIR { @@ -145,9 +151,7 @@ impl BuildSystem { .await .context("error reading metadata of file in final dist dir")?; if file_type.is_dir() { - remove_dir_all(entry.path().into()) - .await - .context("error cleaning final dist")?; + remove_dir_all(entry.path()).await.context("error cleaning final dist")?; } else if file_type.is_symlink() || file_type.is_file() { fs::remove_file(entry.path()).await.context("error cleaning final dist")?; } diff --git a/src/cmd/clean.rs b/src/cmd/clean.rs index a4fda933..b20d7d8e 100644 --- a/src/cmd/clean.rs +++ b/src/cmd/clean.rs @@ -1,11 +1,13 @@ use std::path::PathBuf; +use std::process::Stdio; -use anyhow::{ensure, Result}; -use async_process::{Command, Stdio}; +use anyhow::{ensure, Context, Result}; use structopt::StructOpt; +use tokio::process::Command; use crate::common::remove_dir_all; use crate::config::{ConfigOpts, ConfigOptsClean}; +use crate::tools::cache_dir; /// Clean output artifacts. #[derive(StructOpt)] @@ -13,6 +15,12 @@ use crate::config::{ConfigOpts, ConfigOptsClean}; pub struct Clean { #[structopt(flatten)] pub clean: ConfigOptsClean, + /// Optionally clean any cached tools used by Trunk + /// + /// These tools are cached in a platform dependent "projects" dir. Removing them will cause + /// them to be downloaded by Trunk next time they are needed. + #[structopt(short, long)] + pub tools: bool, } impl Clean { @@ -21,6 +29,7 @@ impl Clean { let cfg = ConfigOpts::rtc_clean(self.clean, config)?; let _ = remove_dir_all(cfg.dist.clone()).await; if cfg.cargo { + tracing::debug!("cleaning cargo dir"); let output = Command::new("cargo") .arg("clean") .stdout(Stdio::piped()) @@ -29,6 +38,11 @@ impl Clean { .await?; ensure!(output.status.success(), "{}", String::from_utf8_lossy(&output.stderr)); } + if self.tools { + tracing::debug!("cleaning trunk tools cache dir"); + let path = cache_dir().await.context("error getting cache dir path")?; + remove_dir_all(path).await?; + } Ok(()) } } diff --git a/src/cmd/serve.rs b/src/cmd/serve.rs index fd643a44..e2217972 100644 --- a/src/cmd/serve.rs +++ b/src/cmd/serve.rs @@ -1,7 +1,8 @@ use std::path::PathBuf; -use anyhow::Result; +use anyhow::{Context, Result}; use structopt::StructOpt; +use tokio::sync::broadcast; use crate::config::{ConfigOpts, ConfigOptsBuild, ConfigOptsServe, ConfigOptsWatch}; use crate::serve::ServeSystem; @@ -21,9 +22,17 @@ pub struct Serve { impl Serve { #[tracing::instrument(level = "trace", skip(self, config))] pub async fn run(self, config: Option) -> Result<()> { + let (shutdown_tx, _) = broadcast::channel(1); let cfg = ConfigOpts::rtc_serve(self.build, self.watch, self.serve, config)?; - let system = ServeSystem::new(cfg).await?; - system.run().await?; + let system = ServeSystem::new(cfg, shutdown_tx.clone()).await?; + + let system_handle = tokio::spawn(system.run()); + let _res = tokio::signal::ctrl_c().await.context("error awaiting shutdown signal")?; + tracing::debug!("received shutdown signal"); + let _res = shutdown_tx.send(()); + drop(shutdown_tx); // Ensure other components see the drop to avoid race conditions. + system_handle.await.context("error awaiting system shutdown")??; + Ok(()) } } diff --git a/src/cmd/watch.rs b/src/cmd/watch.rs index 1733fb21..812295e4 100644 --- a/src/cmd/watch.rs +++ b/src/cmd/watch.rs @@ -1,7 +1,8 @@ use std::path::PathBuf; -use anyhow::Result; +use anyhow::{Context, Result}; use structopt::StructOpt; +use tokio::sync::broadcast; use crate::config::{ConfigOpts, ConfigOptsBuild, ConfigOptsWatch}; use crate::watch::WatchSystem; @@ -19,10 +20,18 @@ pub struct Watch { impl Watch { #[tracing::instrument(level = "trace", skip(self, config))] pub async fn run(self, config: Option) -> Result<()> { + let (shutdown_tx, _shutdown_rx) = broadcast::channel(1); let cfg = ConfigOpts::rtc_watch(self.build, self.watch, config)?; - let mut system = WatchSystem::new(cfg).await?; - system.build().await; - system.run().await; + let mut system = WatchSystem::new(cfg, shutdown_tx.clone()).await?; + + let _res = system.build().await; + let system_handle = tokio::spawn(system.run()); + let _res = tokio::signal::ctrl_c().await.context("error awaiting shutdown signal")?; + tracing::debug!("received shutdown signal"); + let _res = shutdown_tx.send(()); + drop(shutdown_tx); // Ensure other components see the drop to avoid race conditions. + system_handle.await.context("error awaiting system shutdown")?; + Ok(()) } } diff --git a/src/common.rs b/src/common.rs index 87dcfb1a..1abf6263 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,12 +1,13 @@ //! Common functionality and types. +use std::fs::Metadata; use std::path::{Path, PathBuf}; +use std::process::Stdio; use std::{ffi::OsStr, io::ErrorKind}; use anyhow::{anyhow, bail, Context, Result}; -use async_process::{Command, Stdio}; -use async_std::fs; -use async_std::task::spawn_blocking; +use tokio::fs; +use tokio::process::Command; use console::Emoji; @@ -32,7 +33,7 @@ pub async fn copy_dir_recursive(from_dir: PathBuf, to_dir: PathBuf) -> Result<() return Err(anyhow!("directory can not be copied as it does not exist {:?}", &from_dir)); } - spawn_blocking(move || -> Result<()> { + tokio::task::spawn_blocking(move || -> Result<()> { let opts = fs_extra::dir::CopyOptions { overwrite: true, content_only: true, @@ -42,6 +43,7 @@ pub async fn copy_dir_recursive(from_dir: PathBuf, to_dir: PathBuf) -> Result<() Ok(()) }) .await + .context("error awaiting spawned copy dir call")? .context("error copying directory") } @@ -53,21 +55,38 @@ pub async fn remove_dir_all(from_dir: PathBuf) -> Result<()> { if !path_exists(&from_dir).await? { return Ok(()); } - spawn_blocking(move || { + tokio::task::spawn_blocking(move || { ::remove_dir_all::remove_dir_all(from_dir.as_path()).context("error removing directory")?; Ok(()) }) .await + .context("error awaiting spawned remove dir call")? } /// Checks if path exists. pub async fn path_exists(path: impl AsRef) -> Result { - let exists = fs::metadata(path.as_ref()) + fs::metadata(path.as_ref()) .await .map(|_| true) .or_else(|error| if error.kind() == ErrorKind::NotFound { Ok(false) } else { Err(error) }) - .with_context(|| format!("error checking for existance of path at {:?}", path.as_ref()))?; - Ok(exists) + .with_context(|| format!("error checking for existance of path at {:?}", path.as_ref())) +} + +/// Check whether a given path exists, is a file and marked as executable. +pub async fn is_executable(path: impl AsRef) -> Result { + #[cfg(unix)] + let has_executable_flag = |meta: Metadata| { + use std::os::unix::fs::PermissionsExt; + meta.permissions().mode() & 0o100 != 0 + }; + #[cfg(not(unix))] + let has_executable_flag = |meta: Metadata| true; + + fs::metadata(path.as_ref()) + .await + .map(|meta| meta.is_file() && has_executable_flag(meta)) + .or_else(|error| if error.kind() == ErrorKind::NotFound { Ok(false) } else { Err(error) }) + .with_context(|| format!("error checking file mode for file {:?}", path.as_ref())) } /// Strip the CWD prefix from the given path. @@ -90,7 +109,7 @@ pub async fn run_command(name: &str, path: &Path, args: &[impl AsRef]) -> .stderr(Stdio::inherit()) .spawn() .with_context(|| format!("error spawning {} call", name))? - .status() + .wait() .await .with_context(|| format!("error during {} call", name))?; if !status.success() { diff --git a/src/config/manifest.rs b/src/config/manifest.rs index fb60544b..9420b0e0 100644 --- a/src/config/manifest.rs +++ b/src/config/manifest.rs @@ -1,8 +1,8 @@ use std::path::Path; use anyhow::{Context, Result}; -use async_std::task::spawn_blocking; use cargo_metadata::{Metadata, MetadataCommand, Package}; +use tokio::task::spawn_blocking; /// A wrapper around the cargo project's metadata. #[derive(Clone, Debug)] @@ -22,6 +22,7 @@ impl CargoMetadata { cmd.manifest_path(dunce::simplified(manifest)); let metadata = spawn_blocking(move || cmd.exec()) .await + .context("error awaiting spawned cargo metadata task")? .context("error getting cargo metadata")?; let package = metadata diff --git a/src/config/models.rs b/src/config/models.rs index 6bac4c38..7ad41eb0 100644 --- a/src/config/models.rs +++ b/src/config/models.rs @@ -1,9 +1,10 @@ use std::path::PathBuf; +use std::str::FromStr; use std::sync::Arc; use anyhow::{Context, Result}; -use http_types::Url; -use serde::Deserialize; +use http::Uri; +use serde::{Deserialize, Deserializer}; use structopt::StructOpt; use crate::common::parse_public_url; @@ -50,8 +51,8 @@ pub struct ConfigOptsServe { pub open: bool, /// A URL to which requests will be proxied [default: None] #[structopt(long = "proxy-backend")] - #[serde(default)] - pub proxy_backend: Option, + #[serde(default, deserialize_with = "deserialize_uri")] + pub proxy_backend: Option, /// The URI on which to accept requests which are to be rewritten and proxied to backend /// [default: None] #[structopt(long = "proxy-rewrite")] @@ -92,7 +93,8 @@ pub struct ConfigOptsTools { #[derive(Clone, Debug, Deserialize)] pub struct ConfigOptsProxy { /// The URL of the backend to which requests are to be proxied. - pub backend: Url, + #[serde(deserialize_with = "deserialize_uri")] + pub backend: Uri, /// An optional URI prefix which is to be used as the base URI for proxying requests, which /// defaults to the URI of the backend. /// @@ -104,6 +106,18 @@ pub struct ConfigOptsProxy { pub ws: bool, } +/// Deserialize a Uri from a string. +fn deserialize_uri<'de, D, T>(data: D) -> std::result::Result +where + D: Deserializer<'de>, + T: std::convert::From, +{ + let val = String::deserialize(data)?; + Uri::from_str(val.as_str()) + .map(Into::into) + .map_err(|err| serde::de::Error::custom(err.to_string())) +} + /// A model of all potential configuration options for the Trunk CLI system. #[derive(Clone, Debug, Default, Deserialize)] pub struct ConfigOpts { diff --git a/src/config/rt.rs b/src/config/rt.rs index b716fe27..c796e29c 100644 --- a/src/config/rt.rs +++ b/src/config/rt.rs @@ -2,7 +2,7 @@ use std::path::PathBuf; use std::sync::Arc; use anyhow::{anyhow, Context, Result}; -use http_types::Url; +use http::Uri; use crate::config::{ConfigOptsBuild, ConfigOptsClean, ConfigOptsProxy, ConfigOptsServe, ConfigOptsTools, ConfigOptsWatch}; @@ -123,7 +123,7 @@ pub struct RtcServe { /// Open a browser tab once the initial build is complete. pub open: bool, /// A URL to which requests will be proxied. - pub proxy_backend: Option, + pub proxy_backend: Option, /// The URI on which to accept requests which are to be rewritten and proxied to backend. pub proxy_rewrite: Option, /// Configure the proxy for handling WebSockets. diff --git a/src/main.rs b/src/main.rs index 495dd260..92e6ef2c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -16,7 +16,7 @@ use anyhow::{Context, Result}; use structopt::StructOpt; use tracing_subscriber::prelude::*; -#[async_std::main] +#[tokio::main] async fn main() -> Result<()> { let cli = Trunk::from_args(); diff --git a/src/pipelines/copy_dir.rs b/src/pipelines/copy_dir.rs index cc45e3b4..44773ecc 100644 --- a/src/pipelines/copy_dir.rs +++ b/src/pipelines/copy_dir.rs @@ -4,9 +4,9 @@ use std::path::PathBuf; use std::sync::Arc; use anyhow::{Context, Result}; -use async_std::fs; -use async_std::task::{spawn, JoinHandle}; use nipper::Document; +use tokio::fs; +use tokio::task::JoinHandle; use super::ATTR_HREF; use super::{LinkAttrs, TrunkLinkPipelineOutput}; @@ -42,7 +42,7 @@ impl CopyDir { /// Spawn the pipeline for this asset type. #[tracing::instrument(level = "trace", skip(self))] pub fn spawn(self) -> JoinHandle> { - spawn(self.run()) + tokio::spawn(self.run()) } /// Run this pipeline. @@ -58,7 +58,7 @@ impl CopyDir { .file_name() .with_context(|| format!("could not get directory name of dir {:?}", &canonical_path))?; let dir_out = self.cfg.staging_dist.join(dir_name); - copy_dir_recursive(canonical_path.into(), dir_out).await?; + copy_dir_recursive(canonical_path, dir_out).await?; tracing::info!(path = ?rel_path, "finished copying directory"); Ok(TrunkLinkPipelineOutput::CopyDir(CopyDirOutput(self.id))) diff --git a/src/pipelines/copy_file.rs b/src/pipelines/copy_file.rs index b689b516..eee7ff17 100644 --- a/src/pipelines/copy_file.rs +++ b/src/pipelines/copy_file.rs @@ -4,8 +4,8 @@ use std::path::PathBuf; use std::sync::Arc; use anyhow::{Context, Result}; -use async_std::task::{spawn, JoinHandle}; use nipper::Document; +use tokio::task::JoinHandle; use super::ATTR_HREF; use super::{AssetFile, LinkAttrs, TrunkLinkPipelineOutput}; @@ -38,7 +38,7 @@ impl CopyFile { /// Spawn the pipeline for this asset type. #[tracing::instrument(level = "trace", skip(self))] pub fn spawn(self) -> JoinHandle> { - spawn(self.run()) + tokio::spawn(self.run()) } /// Run this pipeline. diff --git a/src/pipelines/css.rs b/src/pipelines/css.rs index 871ab2cd..f14a6aea 100644 --- a/src/pipelines/css.rs +++ b/src/pipelines/css.rs @@ -4,8 +4,8 @@ use std::path::PathBuf; use std::sync::Arc; use anyhow::{Context, Result}; -use async_std::task::{spawn, JoinHandle}; use nipper::Document; +use tokio::task::JoinHandle; use super::ATTR_HREF; use super::{AssetFile, HashedFileOutput, LinkAttrs, TrunkLinkPipelineOutput}; @@ -38,7 +38,7 @@ impl Css { /// Spawn the pipeline for this asset type. #[tracing::instrument(level = "trace", skip(self))] pub fn spawn(self) -> JoinHandle> { - spawn(self.run()) + tokio::spawn(self.run()) } /// Run this pipeline. diff --git a/src/pipelines/html.rs b/src/pipelines/html.rs index 354bd37b..ed734ac1 100644 --- a/src/pipelines/html.rs +++ b/src/pipelines/html.rs @@ -4,11 +4,12 @@ use std::path::PathBuf; use std::sync::Arc; use anyhow::{ensure, Context, Result}; -use async_std::fs; -use async_std::task::{spawn_local, JoinHandle}; -use futures::channel::mpsc::Sender; use futures::stream::{FuturesUnordered, StreamExt}; use nipper::Document; +use tokio::fs; +use tokio::runtime::Handle; +use tokio::sync::mpsc; +use tokio::task::JoinHandle; use crate::config::RtcBuild; use crate::pipelines::rust_app::RustApp; @@ -30,12 +31,12 @@ pub struct HtmlPipeline { /// The parent directory of `target_html_path`. target_html_dir: Arc, /// An optional channel to be used to communicate ignore paths to the watcher. - ignore_chan: Option>, + ignore_chan: Option>, } impl HtmlPipeline { /// Create a new instance. - pub fn new(cfg: Arc, ignore_chan: Option>) -> Result { + pub fn new(cfg: Arc, ignore_chan: Option>) -> Result { let target_html_path = cfg .target .canonicalize() @@ -58,7 +59,9 @@ impl HtmlPipeline { /// Spawn a new pipeline. #[tracing::instrument(level = "trace", skip(self))] pub fn spawn(self: Arc) -> JoinHandle> { - spawn_local(self.run()) + // NOTE WELL: this is a pattern to spawn a blocking thread, and then execute a !Send + // future on the current thread. This is needed because nipper's internals are !Send. + tokio::task::spawn_blocking(move || Handle::current().block_on(self.run())) } /// Run this pipeline. @@ -115,7 +118,9 @@ impl HtmlPipeline { /// Finalize asset pipelines & prep the DOM for final output. async fn finalize_asset_pipelines(&self, target_html: &mut Document, mut pipelines: AssetPipelineHandles) -> Result<()> { while let Some(asset_res) = pipelines.next().await { - let asset = asset_res.context("failed to spawn assets finalization")?; + let asset = asset_res + .context("failed to await asset finalization")? + .context("error from asset pipeline")?; asset.finalize(target_html).await?; } Ok(()) diff --git a/src/pipelines/icon.rs b/src/pipelines/icon.rs index 53fe9721..f589b89d 100644 --- a/src/pipelines/icon.rs +++ b/src/pipelines/icon.rs @@ -4,8 +4,8 @@ use std::path::PathBuf; use std::sync::Arc; use anyhow::{Context, Result}; -use async_std::task::{spawn, JoinHandle}; use nipper::Document; +use tokio::task::JoinHandle; use super::ATTR_HREF; use super::{AssetFile, HashedFileOutput, LinkAttrs, TrunkLinkPipelineOutput}; @@ -38,7 +38,7 @@ impl Icon { /// Spawn the pipeline for this asset type. #[tracing::instrument(level = "trace", skip(self))] pub fn spawn(self) -> JoinHandle> { - spawn(self.run()) + tokio::spawn(self.run()) } /// Run this pipeline. diff --git a/src/pipelines/inline.rs b/src/pipelines/inline.rs index 45d3f842..172afe4b 100644 --- a/src/pipelines/inline.rs +++ b/src/pipelines/inline.rs @@ -5,8 +5,8 @@ use std::str::FromStr; use std::sync::Arc; use anyhow::{bail, Context, Result}; -use async_std::task::{spawn, JoinHandle}; use nipper::Document; +use tokio::task::JoinHandle; use super::{AssetFile, LinkAttrs, TrunkLinkPipelineOutput, ATTR_HREF, ATTR_TYPE}; @@ -41,7 +41,7 @@ impl Inline { /// Spawn the pipeline for this asset type. #[tracing::instrument(level = "trace", skip(self))] pub fn spawn(self) -> JoinHandle> { - spawn(self.run()) + tokio::spawn(self.run()) } /// Run this pipeline. diff --git a/src/pipelines/mod.rs b/src/pipelines/mod.rs index bdaca68e..0c4637f1 100644 --- a/src/pipelines/mod.rs +++ b/src/pipelines/mod.rs @@ -14,11 +14,12 @@ use std::path::{Path, PathBuf}; use std::sync::Arc; use anyhow::{bail, ensure, Context, Result}; -use async_std::fs; -use async_std::task::JoinHandle; -use futures::channel::mpsc::Sender; use nipper::Document; +use tokio::fs; +use tokio::sync::mpsc; +use tokio::task::JoinHandle; +use crate::common::path_exists; use crate::config::RtcBuild; use crate::pipelines::copy_dir::{CopyDir, CopyDirOutput}; use crate::pipelines::copy_file::{CopyFile, CopyFileOutput}; @@ -62,7 +63,7 @@ pub enum TrunkLink { impl TrunkLink { /// Construct a new instance. pub async fn from_html( - cfg: Arc, html_dir: Arc, ignore_chan: Option>, attrs: LinkAttrs, id: usize, + cfg: Arc, html_dir: Arc, ignore_chan: Option>, attrs: LinkAttrs, id: usize, ) -> Result { let rel = attrs .get(ATTR_REL) @@ -159,7 +160,7 @@ impl AssetFile { let path = fs::canonicalize(&path) .await .with_context(|| format!("error getting canonical path for {:?}", &path))?; - ensure!(path.is_file().await, "target file does not appear to exist on disk {:?}", &path); + ensure!(path_exists(&path).await?, "target file does not appear to exist on disk {:?}", &path); let file_name = match path.file_name() { Some(file_name) => file_name.to_owned(), None => bail!("asset has no file name {:?}", &path), @@ -169,7 +170,7 @@ impl AssetFile { None => bail!("asset has no file name stem {:?}", &path), }; let ext = path.extension().map(|ext| ext.to_owned().to_string_lossy().to_string()); - Ok(Self { path: path.into(), file_name, file_stem, ext }) + Ok(Self { path, file_name, file_stem, ext }) } /// Copy this asset to the target dir. diff --git a/src/pipelines/rust_app.rs b/src/pipelines/rust_app.rs index c37868de..c208413d 100644 --- a/src/pipelines/rust_app.rs +++ b/src/pipelines/rust_app.rs @@ -3,16 +3,17 @@ use std::borrow::Cow; use std::iter::Iterator; use std::path::{Path, PathBuf}; +use std::process::Stdio; use std::str::FromStr; use std::sync::Arc; use anyhow::{anyhow, bail, Context, Result}; -use async_process::{Command, Stdio}; -use async_std::fs; -use async_std::task::{spawn, JoinHandle}; use cargo_lock::Lockfile; -use futures::channel::mpsc::Sender; use nipper::Document; +use tokio::fs; +use tokio::process::Command; +use tokio::sync::mpsc; +use tokio::task::JoinHandle; use super::{LinkAttrs, TrunkLinkPipelineOutput}; use super::{ATTR_HREF, SNIPPETS_DIR}; @@ -31,7 +32,7 @@ pub struct RustApp { /// All metadata associated with the target Cargo project. manifest: CargoMetadata, /// An optional channel to be used to communicate paths to ignore back to the watcher. - ignore_chan: Option>, + ignore_chan: Option>, /// An optional binary name which will cause cargo & wasm-bindgen to process only the target /// binary. bin: Option, @@ -48,7 +49,9 @@ pub struct RustApp { impl RustApp { pub const TYPE_RUST_APP: &'static str = "rust"; - pub async fn new(cfg: Arc, html_dir: Arc, ignore_chan: Option>, attrs: LinkAttrs, id: usize) -> Result { + pub async fn new( + cfg: Arc, html_dir: Arc, ignore_chan: Option>, attrs: LinkAttrs, id: usize, + ) -> Result { // Build the path to the target asset. let manifest_href = attrs .get(ATTR_HREF) @@ -89,7 +92,7 @@ impl RustApp { }) } - pub async fn new_default(cfg: Arc, html_dir: Arc, ignore_chan: Option>) -> Result { + pub async fn new_default(cfg: Arc, html_dir: Arc, ignore_chan: Option>) -> Result { let path = html_dir.join("Cargo.toml"); let manifest = CargoMetadata::new(&path).await?; Ok(Self { @@ -101,14 +104,14 @@ impl RustApp { bin: None, keep_debug: false, no_demangle: false, - wasm_opt: WasmOptLevel::default(), + wasm_opt: WasmOptLevel::Off, }) } /// Spawn a new pipeline. #[tracing::instrument(level = "trace", skip(self))] pub fn spawn(self) -> JoinHandle> { - spawn(self.build()) + tokio::spawn(self.build()) } #[tracing::instrument(level = "trace", skip(self))] @@ -165,7 +168,7 @@ impl RustApp { .stderr(Stdio::piped()) .spawn() .context("error spawning cargo build artifacts task")? - .output() + .wait_with_output() .await .context("error getting cargo build artifacts info")?; if !artifacts_out.status.success() { diff --git a/src/pipelines/rust_worker.rs b/src/pipelines/rust_worker.rs index d4664f18..e7124e34 100644 --- a/src/pipelines/rust_worker.rs +++ b/src/pipelines/rust_worker.rs @@ -6,9 +6,9 @@ use std::path::PathBuf; use std::sync::Arc; use anyhow::{bail, Result}; -use async_std::task::JoinHandle; -use futures::channel::mpsc::Sender; use nipper::Document; +use tokio::sync::mpsc; +use tokio::task::JoinHandle; use super::{LinkAttrs, TrunkLinkPipelineOutput}; use crate::config::{CargoMetadata, RtcBuild}; @@ -22,13 +22,15 @@ pub struct RustWorker { /// All metadata associated with the target Cargo project. manifest: CargoMetadata, /// An optional channel to be used to communicate ignore paths to the watcher. - ignore_chan: Option>, + ignore_chan: Option>, } impl RustWorker { pub const TYPE_RUST_WORKER: &'static str = "rust-worker"; - pub async fn new(cfg: Arc, html_dir: Arc, ignore_chan: Option>, attrs: LinkAttrs, id: usize) -> Result { + pub async fn new( + cfg: Arc, html_dir: Arc, ignore_chan: Option>, attrs: LinkAttrs, id: usize, + ) -> Result { bail!(r#"the rust web worker asset type `` is not yet supported"#) } diff --git a/src/pipelines/sass.rs b/src/pipelines/sass.rs index 92d4fc95..9ab7cbd0 100644 --- a/src/pipelines/sass.rs +++ b/src/pipelines/sass.rs @@ -4,9 +4,9 @@ use std::path::PathBuf; use std::sync::Arc; use anyhow::{anyhow, Context, Result}; -use async_std::fs; -use async_std::task::{spawn, spawn_blocking, JoinHandle}; use nipper::Document; +use tokio::fs; +use tokio::task::JoinHandle; use super::{AssetFile, HashedFileOutput, LinkAttrs, TrunkLinkPipelineOutput}; use super::{ATTR_HREF, ATTR_INLINE}; @@ -43,7 +43,7 @@ impl Sass { /// Spawn the pipeline for this asset type. #[tracing::instrument(level = "trace", skip(self))] pub fn spawn(self) -> JoinHandle> { - spawn(self.run()) + tokio::spawn(self.run()) } /// Run this pipeline. @@ -57,8 +57,9 @@ impl Sass { if self.cfg.release { opts.output_style = sass_rs::OutputStyle::Compressed; } - let css = spawn_blocking(move || sass_rs::compile_file(&path_str, opts)) + let css = tokio::task::spawn_blocking(move || sass_rs::compile_file(&path_str, opts)) .await + .context("error awaiting spawned sass compilation task")? .map_err(|err| { eprintln!("{}", err); anyhow!("error compiling sass for {:?}", &self.asset.path) diff --git a/src/proxy.rs b/src/proxy.rs index 321a3c7a..d2bfff1e 100644 --- a/src/proxy.rs +++ b/src/proxy.rs @@ -1,186 +1,192 @@ use std::sync::Arc; use anyhow::Context; -use async_std::task::spawn; -use async_tungstenite::async_std::connect_async; +use axum::routing::BoxRoute; +use axum::ws::{ws, Message as MsgAxm, WebSocket}; +use axum::{prelude::*, AddExtensionLayer}; use futures::prelude::*; -use http_types::{Method, Url}; -use tide::{Request, Result, Server}; -use tide_websockets::{WebSocket, WebSocketConnection}; - -use crate::serve::State; - -/// All HTTP methods, used for registering proxy endpoints with proper precedence. -static HTTP_METHODS: [Method; 9] = [ - Method::Get, - Method::Head, - Method::Post, - Method::Put, - Method::Delete, - Method::Connect, - Method::Options, - Method::Trace, - Method::Patch, -]; - -/// Proxy handler functionality. -pub trait ProxyHandler { - /// The path on which this proxy handler is to listen. - fn path(&self) -> &str; - /// Register this proxy handler on the given app. - fn register(self: Arc, app: &mut Server); -} +use http::Uri; +use hyper::{Body, Request, Response}; +use reqwest::header::HeaderValue; +use tokio_tungstenite::{connect_async, tungstenite::Message as MsgTng}; +use tower_http::trace::TraceLayer; + +use crate::serve::ServerResult; /// A handler used for proxying HTTP requests to a backend. -pub struct ProxyHandlerHttp { +pub(crate) struct ProxyHandlerHttp { + /// The client to use for proxy logic. + client: reqwest::Client, /// The URL of the backend to which requests are to be proxied. - backend: Url, + backend: Uri, /// An optional rewrite path to be used as the listening URI prefix, but which will be /// stripped before being sent to the proxy backend. rewrite: Option, } -impl ProxyHandler for ProxyHandlerHttp { - fn path(&self) -> &str { - self.rewrite - .as_ref() - .map(AsRef::as_ref) - .unwrap_or_else(|| self.backend.path()) +impl ProxyHandlerHttp { + /// Construct a new instance. + pub fn new(client: reqwest::Client, backend: Uri, rewrite: Option) -> Arc { + Arc::new(Self { client, backend, rewrite }) } - fn register(self: Arc, app: &mut Server) { - // NOTE: we are using this loop instead of `.any` due to precedence issues in registering - // routes, as described here https://github.com/thedodd/trunk/issues/95#issuecomment-753508639 - for method in HTTP_METHODS.iter() { - let handler = self.clone(); - app.at(handler.path()) - .strip_prefix() - .method(*method, move |req: Request| { - let handler = handler.clone(); - async move { handler.proxy_request(req).await } - }); - } + /// Build the sub-router for this proxy. + pub fn register(self: Arc, router: BoxRoute) -> BoxRoute { + router + .nest( + self.path(), + any(Self::proxy_http_request + .layer(AddExtensionLayer::new(self.clone())) + .layer(TraceLayer::new_for_http())), + ) + .boxed() } -} -impl ProxyHandlerHttp { - /// Create a new instance. - pub fn new(backend: Url, rewrite: Option) -> Self { - Self { backend, rewrite } + /// The path which this proxy backend listens at. + pub fn path(&self) -> &str { + self.rewrite.as_deref().unwrap_or_else(|| self.backend.path()) } /// Proxy the given request to the target backend. - async fn proxy_request(&self, mut req: Request) -> Result { - // Prep the backend URL for proxied request. - let req_url = req.url(); - let req_path = req_url.path(); - let mut url = self.backend.clone(); - if let Ok(mut segments) = url.path_segments_mut() { - // Don't extend if empty. - if req_path != "/" { - segments.pop_if_empty().extend(req_path.trim_start_matches('/').split('/')); - } + #[tracing::instrument(level = "debug", skip(req))] + async fn proxy_http_request(req: Request) -> ServerResult> { + let state = req + .extensions() + .get::>() + .cloned() + .context("error accessing proxy handler state")?; + + // 0, ensure the path always begins with `/`, this is required for a well-formed URI. + // 1, the router always strips the value `state.path()`, so interpolate the backend path. + // 2, pass along the remaining path segment which was preserved by the router. + let mut segments = ["/", "", "", "", ""]; + segments[1] = state.backend.path().trim_start_matches('/'); + if state.backend.path().ends_with('/') { + segments[2] = req.uri().path().trim_start_matches('/'); + } else { + segments[2] = req.uri().path(); } - url.set_query(req_url.query()); - - // Build a new request to be sent to the proxy backend. - let mut request = surf::RequestBuilder::new(req.method(), url).body(req.take_body()); - for (hname, hval) in req.iter() { - request = request.header(hname, hval); + // 3 & 4, pass along the query if applicable. + if let Some(query) = req.uri().query() { + segments[3] = "?"; + segments[4] = query; } - // Ensure the host header is set to target the backend itself. - if let Some(host) = self.backend.host_str() { - request = request.header("host", host); + let path_and_query = segments.join(""); + + // Construct the outbound URI & build a new request to be sent to the proxy backend. + let outbound_uri = Uri::builder() + .scheme(state.backend.scheme_str().unwrap_or_default()) + .authority(state.backend.authority().map(|val| val.as_str()).unwrap_or_default()) + .path_and_query(path_and_query) + .build() + .context("error building proxy request to backend")?; + let mut outbound_req = state + .client + .request(req.method().clone(), outbound_uri.to_string()) + .headers(req.headers().clone()) + .body(req.into_body()) + .build() + .context("error building outbound request to proxy backend")?; + + // Ensure the host header is set to target the backend. + if let Some(host) = state.backend.authority().map(|authority| authority.host()) { + if let Ok(host) = HeaderValue::from_str(host) { + outbound_req.headers_mut().insert("host", host); + } } // Send the request & unpack the response. - let mut res = request.send().await?; - let mut response = tide::Response::builder(res.status()).body(res.take_body()); - for (hname, hval) in res.iter() { - response = response.header(hname, hval); + let backend_res = state + .client + .execute(outbound_req) + .await + .context("error proxying request to proxy backend")?; + let mut res = http::Response::builder().status(backend_res.status()); + for (key, val) in backend_res.headers() { + res = res.header(key, val); } - Ok(response.build()) + Ok(res + .body(Body::wrap_stream(backend_res.bytes_stream())) + .context("error building proxy response")?) } } /// A handler used for proxying WebSockets to a backend. pub struct ProxyHandlerWebSocket { /// The URL of the backend to which requests are to be proxied. - backend: Url, + backend: Uri, /// An optional rewrite path to be used as the listening URI prefix, but which will be /// stripped before being sent to the proxy backend. rewrite: Option, - /// An HTTP handler used for proxying requests which are not actually WebSocket related. - http_handler: ProxyHandlerHttp, } -impl ProxyHandler for ProxyHandlerWebSocket { - fn path(&self) -> &str { - self.rewrite - .as_ref() - .map(AsRef::as_ref) - .unwrap_or_else(|| self.backend.path()) +impl ProxyHandlerWebSocket { + /// Construct a new instance. + pub fn new(backend: Uri, rewrite: Option) -> Arc { + Arc::new(Self { backend, rewrite }) } - fn register(self: Arc, app: &mut Server) { - let handler = self.clone(); - app.at(self.path()) - .strip_prefix() - .with(WebSocket::new(move |req, sock| self.clone().proxy_request(req, sock))) - .get(move |req| { - let handler = handler.clone(); - async move { handler.http_handler.proxy_request(req).await } - }); + /// Build the sub-router for this proxy. + pub fn register(self: Arc, router: BoxRoute) -> BoxRoute { + let proxy = self.clone(); + router + .route( + self.path(), + ws(move |ws: WebSocket| async move { proxy.clone().proxy_ws_request(ws).await }), + ) + .boxed() } -} -impl ProxyHandlerWebSocket { - /// Create a new instance. - pub fn new(backend: Url, rewrite: Option) -> Self { - let http_handler = ProxyHandlerHttp::new(backend.clone(), rewrite.clone()); - Self { backend, rewrite, http_handler } + /// The path which this proxy backend listens at. + pub fn path(&self) -> &str { + self.rewrite.as_deref().unwrap_or_else(|| self.backend.path()) } - /// Proxy the given request to the target backend. - async fn proxy_request(self: Arc, req: Request, frontend: WebSocketConnection) -> Result<()> { - // Prep the backend URL for opening the backend WebSocket connection. - let req_url = req.url(); - let req_path = req_url.path(); - let mut backend_url = self.backend.clone(); - if let Ok(mut segments) = backend_url.path_segments_mut() { - // Don't extend if empty. - if req_path != "/" { - segments.pop_if_empty().extend(req_path.trim_start_matches('/').split('/')); + /// Proxy the given WebSocket request to the target backend. + #[tracing::instrument(level = "debug", skip(self, ws))] + async fn proxy_ws_request(self: Arc, ws: WebSocket) { + tracing::debug!("new websocket connection"); + + // Establish WS connection to backend. + let (backend, _res) = match connect_async(self.backend.clone()).await { + Ok(backend) => backend, + Err(err) => { + tracing::error!(error = ?err, "error establishing WebSocket connection to backend {:?} for proxy", &self.backend); + return; } - } - - // Open a WebSocket connection to the backend. - let (mut backend_sink, mut backend_source) = connect_async(&backend_url) - .await - .with_context(|| format!("error establishing WebSocket connection to {:?}", backend_url))? - .0 - .split(); - - // Spawn a task for processing frontend messages. - let mut frontend_source = frontend.clone(); - let frontend_handle = spawn(async move { - while let Some(Ok(msg)) = frontend_source.next().await { - if let Err(err) = backend_sink.send(msg).await { - eprintln!("error forwarding frontend WebSocket message to backend: {:?}", err); + }; + let (mut backend_sink, mut backend_stream) = backend.split(); + let (mut frontend_sink, mut frontend_stream) = ws.split(); + + // Stream frontend messages to backend. + let stream_to_backend = async move { + while let Some(Ok(msg)) = frontend_stream.next().await { + if let Err(err) = backend_sink.send(MsgTng::from(msg.as_bytes())).await { + tracing::error!(error = ?err, "error forwarding frontend WebSocket message to backend"); + return; } } - }); - - // Spawn a task for processing backend messages. - let backend_handle = spawn(async move { - while let Some(Ok(msg)) = backend_source.next().await { - if let Err(err) = frontend.send(msg).await { - eprintln!("error forwarding backend WebSocket message to frontend: {:?}", err); + }; + + // Stream backend messages to frontend. + let stream_to_frontend = async move { + while let Some(Ok(msg)) = backend_stream.next().await { + let msg_axm = match msg { + MsgTng::Binary(val) => MsgAxm::binary(val), + MsgTng::Text(val) => MsgAxm::text(val), + MsgTng::Ping(val) => MsgAxm::ping(val), + MsgTng::Pong(val) => MsgAxm::pong(val), + MsgTng::Close(Some(frame)) => MsgAxm::close_with(frame.code, frame.reason), + MsgTng::Close(None) => MsgAxm::close(), + }; + if let Err(err) = frontend_sink.send(msg_axm).await { + tracing::error!(error = ?err, "error forwarding backend WebSocket message to frontend"); + return; } } - }); + }; - futures::join!(frontend_handle, backend_handle); - Ok(()) + futures::join!(stream_to_backend, stream_to_frontend); + tracing::debug!("websocket connection closed"); } } diff --git a/src/serve.rs b/src/serve.rs index 33f364bc..01e7a1c5 100644 --- a/src/serve.rs +++ b/src/serve.rs @@ -1,39 +1,46 @@ -use std::path::{Path, PathBuf}; +use std::net::SocketAddr; +use std::path::PathBuf; use std::sync::Arc; -use anyhow::Result; -use async_std::fs; -use async_std::task::{spawn, spawn_local, JoinHandle}; -use tide::http::mime; -use tide::{Middleware, Next, Request, Response, StatusCode}; +use anyhow::{Context, Result}; +use axum::routing::{nest, BoxRoute}; +use axum::{prelude::*, AddExtensionLayer}; +use hyper::{Body, Request, Response, Server, StatusCode}; +use hyper_staticfile::{resolve_path, ResolveResult, ResponseBuilder}; +use tokio::sync::broadcast; +use tokio::task::JoinHandle; +use tower_http::trace::TraceLayer; use crate::common::SERVER; use crate::config::RtcServe; -use crate::proxy::{ProxyHandler, ProxyHandlerHttp, ProxyHandlerWebSocket}; +use crate::proxy::{ProxyHandlerHttp, ProxyHandlerWebSocket}; use crate::watch::WatchSystem; +const INDEX_HTML: &str = "index.html"; + /// A system encapsulating a build & watch system, responsible for serving generated content. pub struct ServeSystem { cfg: Arc, watch: WatchSystem, http_addr: String, + shutdown_tx: broadcast::Sender<()>, } impl ServeSystem { /// Construct a new instance. - pub async fn new(cfg: Arc) -> Result { - let watch = WatchSystem::new(cfg.watch.clone()).await?; + pub async fn new(cfg: Arc, shutdown: broadcast::Sender<()>) -> Result { + let watch = WatchSystem::new(cfg.watch.clone(), shutdown.clone()).await?; let http_addr = format!("http://127.0.0.1:{}{}", cfg.port, &cfg.watch.build.public_url); - Ok(Self { cfg, watch, http_addr }) + Ok(Self { cfg, watch, http_addr, shutdown_tx: shutdown }) } /// Run the serve system. #[tracing::instrument(level = "trace", skip(self))] pub async fn run(mut self) -> Result<()> { // Spawn the watcher & the server. - self.watch.build().await; - let watch_handle = spawn_local(self.watch.run()); - let server_handle = Self::spawn_server(self.cfg.clone(), self.http_addr.clone())?; + let _build_res = self.watch.build().await; // TODO: only open after a successful build. + let watch_handle = tokio::spawn(self.watch.run()); + let server_handle = Self::spawn_server(self.cfg.clone(), self.shutdown_tx.subscribe())?; // Open the browser. if self.cfg.open { @@ -41,96 +48,160 @@ impl ServeSystem { tracing::error!(error = ?err, "error opening browser"); } } - - server_handle.await; - watch_handle.await; + drop(self.shutdown_tx); // Drop the broadcast channel to ensure it does not keep the system alive. + if let Err(err) = watch_handle.await { + tracing::error!(error = ?err, "error joining watch system handle"); + } + if let Err(err) = server_handle.await { + tracing::error!(error = ?err, "error joining server handle"); + } Ok(()) } - #[tracing::instrument(level = "trace", skip(cfg, http_addr))] - fn spawn_server(cfg: Arc, http_addr: String) -> Result> { - // Prep state. - let listen_addr = format!("0.0.0.0:{}", cfg.port); - let index = Arc::new(cfg.watch.build.final_dist.join("index.html")); - - // Build app. - let mut app = tide::with_state(State { index }); - app.with(TracingMiddleware) - .with(IndexHtmlMiddleware) - .at(&cfg.watch.build.public_url) - .serve_dir(cfg.watch.build.final_dist.to_string_lossy().as_ref())?; - - // Build proxies. - if let Some(backend) = &cfg.proxy_backend { - let handler: Arc = if cfg.proxy_ws { - Arc::new(ProxyHandlerWebSocket::new(backend.clone(), cfg.proxy_rewrite.clone())) - } else { - Arc::new(ProxyHandlerHttp::new(backend.clone(), cfg.proxy_rewrite.clone())) - }; - tracing::info!("{} proxying {} -> {}", SERVER, handler.path(), &backend); - handler.register(&mut app); - } else if let Some(proxies) = &cfg.proxies { - for proxy in proxies.iter() { - let handler: Arc = if proxy.ws { - Arc::new(ProxyHandlerWebSocket::new(proxy.backend.clone(), proxy.rewrite.clone())) - } else { - Arc::new(ProxyHandlerHttp::new(proxy.backend.clone(), proxy.rewrite.clone())) - }; - tracing::info!("{} proxying {} -> {}", SERVER, handler.path(), &proxy.backend); - handler.register(&mut app); - } - } - - // Listen and serve. - tracing::info!("{} server running at {}", SERVER, &http_addr); - Ok(spawn(async move { - if let Err(err) = app.listen(listen_addr).await { - tracing::error!(error = ?err, "error from proxy"); + #[tracing::instrument(level = "trace", skip(cfg, shutdown_rx))] + fn spawn_server(cfg: Arc, mut shutdown_rx: broadcast::Receiver<()>) -> Result> { + // Build a shutdown signal for the warp server. + let shutdown_fut = async move { + // Any event on this channel, even a drop, should trigger shutdown. + let _res = shutdown_rx.recv().await; + tracing::debug!("server is shutting down"); + }; + + // Build the proxy client. + let client = reqwest::ClientBuilder::new() + .build() + .context("error building proxy client")?; + + // Build the server. + let state = Arc::new(State::new(cfg.watch.build.final_dist.clone(), cfg.watch.build.public_url.clone(), client)); + let router = router(state, cfg.clone()); + let addr = SocketAddr::from(([0, 0, 0, 0], cfg.port)); + let server = Server::bind(&addr) + .serve(router.into_make_service()) + .with_graceful_shutdown(shutdown_fut); + + // Block this routine on the server's completion. + tracing::info!("{} server listening at 0.0.0.0:{}", SERVER, &cfg.port); + Ok(tokio::spawn(async move { + if let Err(err) = server.await { + tracing::error!(error = ?err, "error from server task"); } })) } } /// Server state. -#[derive(Clone, Debug)] pub struct State { - /// The path to the index.html file. - pub index: Arc, + /// A client instance used by proxies. + pub client: reqwest::Client, + /// The location of the dist dir. + pub dist_dir: PathBuf, + /// The public URL from which assets are being served. + pub public_url: String, +} + +impl State { + /// Construct a new instance. + pub fn new(dist_dir: PathBuf, public_url: String, client: reqwest::Client) -> Self { + Self { client, dist_dir, public_url } + } } -async fn load_index_html(index: &Path) -> tide::Result> { - Ok(fs::read(index).await?) +/// Serve the static dist dir. +#[tracing::instrument(level = "debug", skip(req))] +async fn serve_dist(req: Request) -> ServerResult> { + let state = req + .extensions() + .get::>() + .context("error accessing request state")?; + let accept_header_opt = req.headers().get("accept").map(|val| val.to_str()); + let res = resolve_path(state.dist_dir.as_path(), req.uri().path()) + .await + .context("error serving from dist dir")?; + + // If the target file was not found, we have an accept header, and that accept header allows + // for HTML to be returned, then move on to attempt to serve the index.html. Else, respond. + match (&res, accept_header_opt) { + // If accept does not contain `*/*` or `text/html`, then return. + (ResolveResult::NotFound, Some(Ok(accept_header))) if accept_header.contains("*/*") || accept_header.contains("text/html") => (), + _ => { + return Ok(ResponseBuilder::new() + .request(&req) + .build(res) + .context("error serving from dist dir")?) + } + }; + + // At this point, we have a 404 with an accept header allowing HTML, so attempt to serve the index. + let res = resolve_path(state.dist_dir.as_path(), INDEX_HTML) + .await + .context("error serving index.html from dist dir")?; + Ok(ResponseBuilder::new() + .request(&req) + .build(res) + .context("error serving index.html from dist dir")?) } -/// Middleware for accessing the index.html from any request which needs it. -struct IndexHtmlMiddleware; - -#[tide::utils::async_trait] -impl Middleware for IndexHtmlMiddleware { - async fn handle(&self, req: Request, next: Next<'_, State>) -> tide::Result { - let index = req.state().index.clone(); - let res = next.run(req).await; - Ok(match res.status() { - StatusCode::NotFound => Response::builder(StatusCode::Ok) - .content_type(mime::HTML) - .body(load_index_html(&index).await?) - .build(), - _ => res, - }) +/// Build the Trunk router, this includes that static file server, the WebSocket server, +/// (for autoreload & HMR in the future), as well as any user-defined proxies. +fn router(state: Arc, cfg: Arc) -> BoxRoute { + // Build static file server, middleware, error handler & WS route for reloads. + let mut router = nest( + &state.public_url, + get(serve_dist + .layer(AddExtensionLayer::new(state.clone())) + .layer(TraceLayer::new_for_http())), + ) + // NOTE: @kcking let's add the auto-reload WS handler here. + .boxed(); + + tracing::info!("{} serving static assets at -> {}", SERVER, state.public_url.as_str()); + + // Build proxies. + if let Some(backend) = &cfg.proxy_backend { + if cfg.proxy_ws { + let handler = ProxyHandlerWebSocket::new(backend.clone(), cfg.proxy_rewrite.clone()); + router = handler.clone().register(router); + tracing::info!("{} proxying websocket {} -> {}", SERVER, handler.path(), &backend); + } else { + let handler = ProxyHandlerHttp::new(state.client.clone(), backend.clone(), cfg.proxy_rewrite.clone()); + router = handler.clone().register(router); + tracing::info!("{} proxying {} -> {}", SERVER, handler.path(), &backend); + } + } else if let Some(proxies) = &cfg.proxies { + for proxy in proxies.iter() { + if proxy.ws { + let handler = ProxyHandlerWebSocket::new(proxy.backend.clone(), proxy.rewrite.clone()); + router = handler.clone().register(router); + tracing::info!("{} proxying websocket {} -> {}", SERVER, handler.path(), &proxy.backend); + } else { + let handler = ProxyHandlerHttp::new(state.client.clone(), proxy.backend.clone(), proxy.rewrite.clone()); + router = handler.clone().register(router); + tracing::info!("{} proxying {} -> {}", SERVER, handler.path(), &proxy.backend); + }; + } } + + router } -/// Middleware for logging errors via tracing. -struct TracingMiddleware; +/// A result type used to work seamlessly with axum. +pub(crate) type ServerResult = std::result::Result; -#[tide::utils::async_trait] -impl Middleware for TracingMiddleware { - #[tracing::instrument(level = "trace", skip(self, req, next))] - async fn handle(&self, req: Request, next: Next<'_, State>) -> tide::Result { - let res = next.run(req).await; - if let Some(err) = res.error() { - tracing::error!("error from proxy\n{:?}", err); - } - Ok(res) +/// A newtype to make anyhow errors work with axum. +pub(crate) struct ServerError(pub anyhow::Error); + +impl From for ServerError { + fn from(src: anyhow::Error) -> Self { + ServerError(src) + } +} + +impl axum::response::IntoResponse for ServerError { + fn into_response(self) -> Response { + tracing::error!(error = ?self.0, "error handling request"); + let mut res = Response::new(Body::empty()); + *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; + res } } diff --git a/src/tools.rs b/src/tools.rs index f1cbbd99..39be3162 100644 --- a/src/tools.rs +++ b/src/tools.rs @@ -1,19 +1,18 @@ //! Download management for external tools and applications. Locate and automatically download //! applications (if needed) to use them in the build pipeline. -use std::{ - fs::{File, Metadata}, - io::{Read, Seek, SeekFrom}, - path::{Path, PathBuf}, -}; - -use anyhow::{bail, ensure, Context, Result}; -use async_process::Command; -use async_std::{fs::File as AsyncFile, io}; +use std::path::{Path, PathBuf}; + +use anyhow::{anyhow, bail, ensure, Context, Result}; +use async_compression::tokio::bufread::GzipDecoder; use directories_next::ProjectDirs; -use flate2::read::GzDecoder; -use surf::middleware::Redirect; -use tar::Archive as TarArchive; +use futures::prelude::*; +use tokio::fs::File; +use tokio::io::{AsyncRead, AsyncSeekExt, AsyncWriteExt, BufReader, SeekFrom}; +use tokio::process::Command; +use tokio_tar::{Archive, Entry}; + +use crate::common::is_executable; /// The application to locate and eventually download when calling [`get`]. #[derive(Clone, Copy, Debug, PartialEq, Eq)] @@ -121,25 +120,20 @@ pub async fn get(app: Application, version: Option<&str>) -> Result { return Ok(path); } - let cache_dir = cache_dir()?; + let cache_dir = cache_dir().await?; let app_dir = cache_dir.join(format!("{}-{}", app.name(), version)); let bin_path = app_dir.join(app.path()); - if !is_executable(&bin_path) { + if !is_executable(&bin_path).await? { let path = download(app, version) .await .context("failed downloading release archive")?; - let path2 = path.clone(); - - async_std::task::spawn_blocking(move || -> Result<_> { - let mut file = File::open(path2).context("failed opening downloaded file")?; - install(app, &mut file, &app_dir)?; - - Ok(()) - }) - .await?; - std::fs::remove_file(path).context("failed deleting temporary archive")?; + let mut file = File::open(&path).await.context("failed opening downloaded file")?; + install(app, &mut file, &app_dir).await?; + tokio::fs::remove_file(path) + .await + .context("failed deleting temporary archive")?; } Ok(bin_path) @@ -169,41 +163,26 @@ async fn find_system(app: Application, version: &str) -> Option { match result().await { Ok((path, system_version)) => (system_version == version).then(|| path), Err(e) => { - tracing::debug!("system version not found: {}", e); + tracing::debug!("system version not found for {}: {}", app.name(), e); None } } } -/// Check whether a given path exists, is a file and marked as executable (unix only). -fn is_executable(path: &Path) -> bool { - #[cfg(unix)] - let has_executable_flag = |meta: Metadata| { - use std::os::unix::fs::PermissionsExt; - meta.permissions().mode() & 0o100 != 0 - }; - #[cfg(not(unix))] - let has_executable_flag = |meta: Metadata| true; - - path.metadata() - .map(|meta| meta.is_file() && has_executable_flag(meta)) - .unwrap_or_default() -} - /// Download a file from its remote location in the given version, extract it and make it ready for /// execution at the given location. #[tracing::instrument(level = "trace")] async fn download(app: Application, version: &str) -> Result { tracing::info!(version = version, "downloading {}", app.name()); - let cache_dir = cache_dir().context("failed getting the cache directory")?; - let client = surf::client().with(Redirect::new(5)); + let cache_dir = cache_dir().await.context("failed getting the cache directory")?; + let temp_out = cache_dir.join(format!("{}-{}.tmp", app.name(), version)); + let mut file = File::create(&temp_out) + .await + .context("failed creating temporary output file")?; - let mut resp = client - .get(app.url(version)?) - .send() + let resp = reqwest::get(app.url(version)?) .await - .map_err(|e| e.into_inner()) .context("error sending HTTP request")?; ensure!( resp.status().is_success(), @@ -211,15 +190,11 @@ async fn download(app: Application, version: &str) -> Result { resp.status(), app.url(version)? ); - - let temp_out = cache_dir.join(format!("{}-{}.tmp", app.name(), version)); - let mut file = AsyncFile::create(&temp_out) - .await - .context("failed creating temporary output file")?; - - io::copy(resp.take_body().into_reader(), &mut file) - .await - .context("failed downloading the archive")?; + let mut res_bytes = resp.bytes_stream(); + while let Some(chunk_res) = res_bytes.next().await { + let chunk = chunk_res.context("error reading chunk from download")?; + let _res = file.write(chunk.as_ref()).await; + } Ok(temp_out) } @@ -227,64 +202,79 @@ async fn download(app: Application, version: &str) -> Result { /// Install an application from a downloaded archive locating and copying it to the given target /// location. #[tracing::instrument(level = "trace")] -fn install(app: Application, archive_file: &mut File, target: &Path) -> Result<()> { +async fn install(app: Application, archive_file: &mut File, target: &Path) -> Result<()> { tracing::info!("installing {}", app.name()); - let mut archive = TarArchive::new(GzDecoder::new(archive_file)); - let mut file = extract_file(&mut archive, target, Path::new(app.path()))?; + let mut archive = Archive::new(GzipDecoder::new(BufReader::new(archive_file))); + let mut file = extract_file(&mut archive, target, Path::new(app.path())).await?; - set_executable_flag(&mut file)?; + set_executable_flag(&mut file).await?; for path in app.extra_paths() { - // archive must be opened for each entry as tar files don't allow jumping forth and back. - let archive_file = archive.into_inner().into_inner(); - archive_file.seek(SeekFrom::Start(0))?; + // Archive must be opened for each entry as tar files don't allow jumping forth and back. + let mut archive_file = archive + .into_inner() + .map_err(|_| anyhow!("error seeking app archive"))? + .into_inner(); + archive_file + .seek(SeekFrom::Start(0)) + .await + .context("error seeking to beginning of archive")?; - archive = TarArchive::new(GzDecoder::new(archive_file)); - extract_file(&mut archive, target, Path::new(path))?; + archive = Archive::new(GzipDecoder::new(archive_file)); + extract_file(&mut archive, target, Path::new(path)).await?; } Ok(()) } /// Extract a single file from the given archive and put it into the target location. -fn extract_file(archive: &mut TarArchive, target: &Path, file: &Path) -> Result +async fn extract_file(archive: &mut Archive, target: &Path, file: &Path) -> Result where - R: Read, + R: AsyncRead + Unpin + Send + Sync, { - let mut tar_file = find_tar_entry(archive, file)?.context("file not found in archive")?; + let mut tar_file = find_tar_entry(archive, file).await?.context("file not found in archive")?; let out = target.join(file); if let Some(parent) = out.parent() { - std::fs::create_dir_all(parent).context("failed creating output directory")?; + tokio::fs::create_dir_all(parent) + .await + .context("failed creating output directory")?; } - let mut out = File::create(target.join(file)).context("failed creating output file")?; - std::io::copy(&mut tar_file, &mut out).context("failed copying over final output file from archive")?; + let mut out = File::create(target.join(file)) + .await + .context("failed creating output file")?; + tokio::io::copy(&mut tar_file, &mut out) + .await + .context("failed copying over final output file from archive")?; Ok(out) } /// Locate the cache dir for trunk and make sure it exists. -fn cache_dir() -> Result { +pub async fn cache_dir() -> Result { let path = ProjectDirs::from("dev", "trunkrs", "trunk") .context("failed finding project directory")? .cache_dir() .to_owned(); - std::fs::create_dir_all(&path).context("failed creating cache directory")?; - + tokio::fs::create_dir_all(&path) + .await + .context("failed creating cache directory")?; Ok(path) } /// Set the executable flag for a file. Only has an effect on UNIX platforms. -fn set_executable_flag(file: &mut File) -> Result<()> { +async fn set_executable_flag(file: &mut File) -> Result<()> { #[cfg(unix)] { use std::os::unix::fs::PermissionsExt; - let mut perms = file.metadata().context("failed getting metadata")?.permissions(); + let mut perms = file.metadata().await.context("failed getting metadata")?.permissions(); perms.set_mode(perms.mode() | 0o100); - file.set_permissions(perms).context("failed setting the executable flag")?; + file.set_permissions(perms) + .await + .context("failed setting the executable flag")?; } Ok(()) @@ -292,8 +282,12 @@ fn set_executable_flag(file: &mut File) -> Result<()> { /// Find an entry in a TAR archive by name and open it for reading. The first part of the path is /// dropped as that's usually the folder name it was created from. -fn find_tar_entry(archive: &mut TarArchive, path: impl AsRef) -> Result> { - for entry in archive.entries().context("failed getting archive entries")? { +async fn find_tar_entry(archive: &mut Archive, path: impl AsRef) -> Result>>> +where + R: AsyncRead + Unpin + Send + Sync, +{ + let mut entries = archive.entries().context("failed getting archive entries")?; + while let Some(entry) = entries.next().await { let entry = entry.context("error while getting archive entry")?; let name = entry.path().context("invalid entry path")?; @@ -313,7 +307,7 @@ mod tests { use super::*; use anyhow::{Context, Result}; - #[async_std::test] + #[tokio::test] async fn download_and_install_binaries() -> Result<()> { let dir = tempfile::tempdir().context("error creating temporary dir")?; @@ -321,7 +315,8 @@ mod tests { let path = download(app, app.default_version()) .await .context("error downloading app")?; - install(app, &mut File::open(&path).context("error opening file")?, dir.path()).context("error installing app")?; + let mut file = File::open(&path).await.context("error opening file")?; + install(app, &mut file, dir.path()).await.context("error installing app")?; std::fs::remove_file(path).context("error during cleanup")?; } Ok(()) diff --git a/src/watch.rs b/src/watch.rs index 7d26e798..38e708ac 100644 --- a/src/watch.rs +++ b/src/watch.rs @@ -2,10 +2,10 @@ use std::path::PathBuf; use std::sync::Arc; use anyhow::{Context, Result}; -use async_std::task::{spawn_blocking, JoinHandle}; -use futures::channel::mpsc::{channel, Receiver, Sender}; use futures::prelude::*; -use notify::{watcher, DebouncedEvent, RecommendedWatcher, RecursiveMode, Watcher}; +use notify::{recommended_watcher, Event, EventKind, RecommendedWatcher, RecursiveMode, Watcher}; +use tokio::sync::{broadcast, mpsc}; +use tokio_stream::wrappers::BroadcastStream; use crate::build::BuildSystem; use crate::config::RtcWatch; @@ -20,19 +20,21 @@ pub struct WatchSystem { /// The current vector of paths to be ignored. ignored_paths: Vec, /// A channel of FS watch events. - watch_rx: Receiver, + watch_rx: mpsc::Receiver, /// A channel of new paths to ignore from the build system. - build_rx: Receiver, + build_rx: mpsc::Receiver, /// The watch system used for watching the filesystem. - _watcher: (JoinHandle<()>, RecommendedWatcher), + _watcher: RecommendedWatcher, + /// The application shutdown channel. + shutdown: BroadcastStream<()>, } impl WatchSystem { /// Create a new instance. - pub async fn new(cfg: Arc) -> Result { + pub async fn new(cfg: Arc, shutdown: broadcast::Sender<()>) -> Result { // Create a channel for being able to listen for new paths to ignore while running. - let (watch_tx, watch_rx) = channel(1); - let (build_tx, build_rx) = channel(1); + let (watch_tx, watch_rx) = mpsc::channel(1); + let (build_tx, build_rx) = mpsc::channel(1); // Build the watcher. let _watcher = build_watcher(watch_tx, cfg.paths.clone())?; @@ -45,63 +47,65 @@ impl WatchSystem { watch_rx, build_rx, _watcher, + shutdown: BroadcastStream::new(shutdown.subscribe()), }) } /// Run a build. #[tracing::instrument(level = "trace", skip(self))] - pub async fn build(&mut self) { - let _ = self.build.build().await; + pub async fn build(&mut self) -> Result<()> { + self.build.build().await } /// Run the watch system, responding to events and triggering builds. #[tracing::instrument(level = "trace", skip(self))] pub async fn run(mut self) { loop { - futures::select! { - ign_res = self.build_rx.next() => if let Some(ign) = ign_res { - self.update_ignore_list(ign); - }, - ev_res = self.watch_rx.next() => if let Some(ev) = ev_res { - self.handle_watch_event(ev).await; - }, + tokio::select! { + Some(ign) = self.build_rx.recv() => self.update_ignore_list(ign), + Some(ev) = self.watch_rx.recv() => self.handle_watch_event(ev).await, + _ = self.shutdown.next() => break, // Any event, even a drop, will trigger shutdown. } } + + tracing::debug!("watcher system has shut down"); } #[tracing::instrument(level = "trace", skip(self, event))] - async fn handle_watch_event(&mut self, event: DebouncedEvent) { - let mut ev_path = match event { - DebouncedEvent::Create(path) | DebouncedEvent::Write(path) | DebouncedEvent::Remove(path) | DebouncedEvent::Rename(_, path) => path, - _ => return, - }; + async fn handle_watch_event(&mut self, event: Event) { + if matches!(&event.kind, EventKind::Access(_) | EventKind::Any | EventKind::Other) { + return; // Nothing to do with these. + } - ev_path = match ev_path.canonicalize() { - Ok(path) => path, - // Ignore errors here, as this would only take place for a resource which has - // been removed, which will happen for each of our dist/.stage entries. - Err(_) => return, - }; + for ev_path in event.paths { + let ev_path = match tokio::fs::canonicalize(&ev_path).await { + Ok(ev_path) => ev_path, + // Ignore errors here, as this would only take place for a resource which has + // been removed, which will happen for each of our dist/.stage entries. + Err(_) => continue, + }; + + // Check ignored paths. + if ev_path + .ancestors() + .any(|path| self.ignored_paths.iter().any(|ignored_path| ignored_path == path)) + { + continue; // Don't emit a notification if path is ignored. + } - // Check ignored paths. - if ev_path - .ancestors() - .any(|path| self.ignored_paths.iter().any(|ignored_path| ignored_path == path)) - { - return; // Don't emit a notification if path is ignored. - } + // Check blacklisted paths. + if ev_path + .components() + .filter_map(|segment| segment.as_os_str().to_str()) + .any(|segment| BLACKLIST.contains(&segment)) + { + continue; // Don't emit a notification as path is on the blacklist. + } - // Check blacklisted paths. - if ev_path - .components() - .filter_map(|segment| segment.as_os_str().to_str()) - .any(|segment| BLACKLIST.contains(&segment)) - { - return; // Don't emit a notification as path is on the blacklist. + tracing::debug!("change detected in {:?}", ev_path); + let _res = self.build.build().await; + return; // If one of the paths triggers a build, then we're done. } - - tracing::info!("change detected in {:?}", ev_path); - let _ = self.build.build().await; } fn update_ignore_list(&mut self, arg_path: PathBuf) { @@ -116,9 +120,17 @@ impl WatchSystem { } } -fn build_watcher(mut watch_tx: Sender, paths: Vec) -> Result<(JoinHandle<()>, RecommendedWatcher)> { - let (tx, rx) = std::sync::mpsc::channel(); - let mut watcher = watcher(tx, std::time::Duration::from_secs(1)).context("failed to build file system watcher")?; +/// Build a FS watcher, when the watcher is dropped, it will stop watching for events. +fn build_watcher(watch_tx: mpsc::Sender, paths: Vec) -> Result { + let event_handler = move |event_res: notify::Result| match event_res { + Ok(event) => { + let _res = watch_tx.try_send(event); + } + Err(err) => { + tracing::error!(error = ?err, "error from FS watcher"); + } + }; + let mut watcher = recommended_watcher(event_handler).context("failed to build file system watcher")?; // Create a recursive watcher on each of the given paths. // NOTE WELL: it is expected that all given paths are canonical. The Trunk config @@ -130,11 +142,5 @@ fn build_watcher(mut watch_tx: Sender, paths: Vec) -> R .context(format!("failed to watch {:?} for file system changes", path))?; } - let handle = spawn_blocking(move || loop { - if let Ok(event) = rx.recv() { - let _ = watch_tx.try_send(event); - } - }); - - Ok((handle, watcher)) + Ok(watcher) }