From 5dd33c9dcdbf0445fde1193f63eeb6fd4f11534b Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Thu, 15 Feb 2024 14:31:32 -0800 Subject: [PATCH 01/17] Remove outdated docs --- notes/ARCHITECTURE.md | 73 ---------------------- notes/CHANGELOG.md | 138 ------------------------------------------ 2 files changed, 211 deletions(-) delete mode 100644 notes/ARCHITECTURE.md delete mode 100644 notes/CHANGELOG.md diff --git a/notes/ARCHITECTURE.md b/notes/ARCHITECTURE.md deleted file mode 100644 index ab06d8cd8..000000000 --- a/notes/ARCHITECTURE.md +++ /dev/null @@ -1,73 +0,0 @@ -# Signals - -Signals provide a way of forcing updates directly through Dioxus without having to go through the diffing phase. - -When diffing is too slow for your use-case, signals can be faster. Signals run at a higher priority than regular diffing, acting as a hint to Dioxus that a signal update needs to take precedence over a subtree update. This can be useful in real-time systems where getting data from a websocket to the screen ASAP is extremely important. - -- High -- Medium -- Low - -## Signals: - -Producer -> Receiver - -- The Dioxus VirtualDOM provides built-in receivers for signals. -- Elements themselves act as receivers. -- Any use of a signal schedules the current element and its children for updates. -- Attributes are valid receivers -- Text nodes are valid receivers -- Receivers may not be passed into child components (must be de-referenced) -- When receivers are derefed in a component's properties, the props will be updated in place and the component will re-render with the new value. - -```rust -let sig = use_signal(|| 0); - -// any updates to the signal will cause the child to re-render completely -Comp { - prop: *sig -} -``` - -Using 3 separate signals - -```rust -let width = use_signal(|| 0); - -cx.request_next_frame(move |frame| async { - sig1 += 1; - frame.again(); -}) - -div { - h2 { "{sig1}" } - h3 { "{sig2}" } - h4 { "{sig3}" } -} -``` - - -## Subtree memoization - -The rsx! macro needs to be *really* smart. If it detects that no dynamics are pumped into the macro, then it opts to use the "const" flavors of the element build functions we know and love. This has to be done at build time rather than runtime since components may return basically anything. Using the const flavor enables is_static which encourages Dioxus to do a ptr compare instead of a value compare to short circuit through the diffing. Due to const folding in Rust, entire subtrees can be ruled out at compile time. - -It would be interesting to fix the issue of dynamic subtrees by hashing each structure (or just the const structures) or the macro call itself. That way, each call gets its own identifier and we can make sure that two unique structures have different IDs and aren't just opaque to dioxus. - -```rust -let s1 = LazyNodes::new("1", move |_| { - if rand() { - f.element() - } else { - f.element() - } -}); -let s2 = LazyNodes::new("1", move |f| { - if rand() { - f.element() - } else { - f.element() - } -}); -// produces the same ID with different structures -// perhaps just make this -``` diff --git a/notes/CHANGELOG.md b/notes/CHANGELOG.md deleted file mode 100644 index ac6a0cf2a..000000000 --- a/notes/CHANGELOG.md +++ /dev/null @@ -1,138 +0,0 @@ -# Dioxus v0.1.0 - -Welcome to the first iteration of the Dioxus Virtual DOM! This release brings support for: - -- Web via Wasm -- Desktop via webview integration -- Server-rendering with custom ToString implementation -- State management -- Build CLI -- Foundational hooks -- Context API -- Basic suspense -- Controlled components - ---- - -## Project: Initial VDOM support (TBD) - -> Get the initial VDom + Event System + Patching + Diffing + Component framework up and running -> Get a demo working using just the web - -- [x] (Core) Migrate virtual node into new VNode type -- [x] (Core) Arena allocate VNodes -- [x] (Core) Allow VNodes to borrow arena contents -- [x] (Core) Introduce the VDOM and patch API for 3rd party renderers -- [x] (Core) Implement lifecycle -- [x] (Core) Implement an event system -- [x] (Core) Implement child nodes, scope creation -- [x] (Core) Implement dirty tagging and compression - -## Project: QOL - -> Make it easier to write components - -- [x] (Macro) Tweak event syntax to not be dependent on wasm32 target (just return regular closures which get boxed/alloced) -- [x] (Macro) Tweak component syntax to accept a new custom element -- [ ] (Macro) Allow components to specify their props as function args - -## Project: Hooks + Context + Subscriptions (TBD) - -> Implement the foundations for state management - -- [x] Implement context object -- [x] Implement use_state (rewrite to use the use_reducer api like rei) -- [x] Implement use_ref -- [x] Implement use_context (only the API, not the state management solution) -- [ ] Implement use_reducer (WIP) - -## Project: String Render (TBD) - -> Implement a light-weight string renderer with basic caching - -- [x] (Macro) Make VText nodes automatically capture and format IE allow "Text is {blah}" -- [x] (SSR) Implement stateful 3rd party string renderer - -## Project: Web_sys renderer (TBD) - -- [x] WebSys edit interpreter -- [x] Event system using async channels -- [ ] Implement conversion of all event types into synthetic events - -## Project: Web-View 🤲 🍨 - -> Proof of concept: stream render edits from server to client - -- [x] Prove that the diffing and patching framework can support patch streaming - -## Project: Examples - -> Get _all_ the examples - -- [ ] (Examples) Tide example with templating - -## Project: State management - -> Get some global state management installed with the hooks + context API - -## Project: Concurrency (TBD) - -> Ensure the concurrency model works well, play with lifetimes to check if it can be multithreaded + halted -> ? - -## Project: Mobile exploration - -## Project: Live-View 🤲 🍨 - -> Combine the server and client into a single file :) - -## Project: Sanitization (TBD) - -> Improve code health - -- [ ] (Macro) Clippy sanity for html macro -- [ ] (Macro) Error sanitization - -## Outstanding todos: - -> anything missed so far - -- [x] keys on components -- [x] Allow paths for components -- [x] todo mvc -- [x] Tweak macro parsing for better errors -- [x] dirty tagging, compression -- [x] code health -- [x] static str slice optimization -- [x] name spacing so svg works - - [x] A handful of svg elements are automatically namespaced - - [ ] Allow hierarchical namespacing (all children share a parent's namespace) - TBD in macro impl -- [ ] fix keys on elements -- [ ] controlled components (kinda tuff since we need all these different platforms) - - [ ] Their own crate - - [ ] Re-exported through the `dioxus` crate (not core) -- [ ] Hooks - - [ ] Re-exported through the `dioxus` crate (not essential to core virtualdom) -- [x] fragments -- [x] pass-thru components - -## Less-essential todos - -- [ ] HTML doesn't require strings between elements (copy-paste from internet) -- [ ] Beef up the dioxus CLI tool to report build progress -- [ ] Extract arena logic out for better safety guarantees -- [ ] Extract BumpFrame logic out for better safety guarantees -- [ ] make SSR follow HTML spec -- [ ] MIRI tests -- [ ] all synthetic events filled out -- [ ] double check event targets and stuff -- [ ] Documentation overhaul -- [ ] Website - -lower priority features - -- [x] Attributes on elements should implement format_args instead of string fmt -- [ ] node refs (postpone for future release?) -- [ ] styling built-in (future release?) -- [ ] key handler? -- [ ] FC macro? From 214a907adc0efec1922f086a182c726d6c2eb219 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Thu, 15 Feb 2024 18:05:30 -0800 Subject: [PATCH 02/17] Upgrade to axum 0.7, drop 3rd party adapters --- .vscode/settings.json | 4 +- Cargo.lock | 1639 ++++------------- Cargo.toml | 19 +- packages/cli-config/Cargo.toml | 2 +- packages/cli/Cargo.toml | 14 +- packages/cli/src/main.rs | 6 +- packages/cli/src/server/web/mod.rs | 12 +- packages/cli/src/server/web/proxy.rs | 7 +- packages/dioxus/Cargo.toml | 6 - packages/dioxus/build.rs | 4 +- packages/dioxus/src/launch.rs | 18 +- packages/dioxus/src/lib.rs | 53 +- packages/fullstack/Cargo.toml | 20 +- packages/fullstack/README.md | 46 +- .../fullstack/examples/axum-auth/Cargo.toml | 17 +- .../fullstack/examples/axum-auth/src/main.rs | 6 +- .../examples/axum-desktop/Cargo.toml | 4 +- .../examples/axum-desktop/src/client.rs | 4 +- .../fullstack/examples/axum-router/Cargo.toml | 2 +- .../examples/salvo-hello-world/.gitignore | 4 - .../examples/salvo-hello-world/Cargo.toml | 25 - .../examples/salvo-hello-world/src/main.rs | 57 - .../examples/warp-hello-world/.gitignore | 4 - .../examples/warp-hello-world/Cargo.toml | 20 - .../examples/warp-hello-world/src/main.rs | 54 - .../fullstack/src/adapters/axum_adapter.rs | 8 +- packages/fullstack/src/adapters/mod.rs | 12 +- .../fullstack/src/adapters/salvo_adapter.rs | 581 ------ .../fullstack/src/adapters/warp_adapter.rs | 417 ----- packages/fullstack/src/config.rs | 67 +- packages/fullstack/src/layer.rs | 26 +- packages/fullstack/src/lib.rs | 70 +- packages/fullstack/src/server_context.rs | 2 +- packages/fullstack/src/server_fn.rs | 12 +- packages/liveview/.vscode/settings.json | 5 - packages/liveview/Cargo.toml | 41 +- packages/liveview/README.md | 3 - packages/liveview/examples/rocket.rs | 76 - packages/liveview/examples/salvo.rs | 67 - packages/liveview/examples/warp.rs | 56 - .../liveview/src/adapters/axum_adapter.rs | 6 +- packages/liveview/src/adapters/mod.rs | 15 - .../liveview/src/adapters/rocket_adapter.rs | 113 -- .../liveview/src/adapters/salvo_adapter.rs | 108 -- .../liveview/src/adapters/warp_adapter.rs | 25 - packages/liveview/src/launch.rs | 4 - packages/liveview/src/lib.rs | 6 +- packages/playwright-tests/liveview/Cargo.toml | 2 +- packages/router/Cargo.toml | 2 +- packages/router/examples/simple_routes.rs | 16 +- packages/router/src/history/liveview.rs | 14 +- packages/router/src/router_cfg.rs | 91 +- packages/ssr/Cargo.toml | 11 +- 53 files changed, 643 insertions(+), 3260 deletions(-) delete mode 100644 packages/fullstack/examples/salvo-hello-world/.gitignore delete mode 100644 packages/fullstack/examples/salvo-hello-world/Cargo.toml delete mode 100644 packages/fullstack/examples/salvo-hello-world/src/main.rs delete mode 100644 packages/fullstack/examples/warp-hello-world/.gitignore delete mode 100644 packages/fullstack/examples/warp-hello-world/Cargo.toml delete mode 100644 packages/fullstack/examples/warp-hello-world/src/main.rs delete mode 100644 packages/fullstack/src/adapters/salvo_adapter.rs delete mode 100644 packages/fullstack/src/adapters/warp_adapter.rs delete mode 100644 packages/liveview/.vscode/settings.json delete mode 100644 packages/liveview/examples/rocket.rs delete mode 100644 packages/liveview/examples/salvo.rs delete mode 100644 packages/liveview/examples/warp.rs delete mode 100644 packages/liveview/src/adapters/rocket_adapter.rs delete mode 100644 packages/liveview/src/adapters/salvo_adapter.rs delete mode 100644 packages/liveview/src/adapters/warp_adapter.rs diff --git a/.vscode/settings.json b/.vscode/settings.json index 836fb0116..e386d4b4c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -4,5 +4,7 @@ "editor.formatOnSave": false }, "rust-analyzer.check.workspace": true, - "rust-analyzer.checkOnSave.allTargets": false, + "rust-analyzer.check.features": "all", + "rust-analyzer.cargo.features": "all", + "rust-analyzer.check.allTargets": true } diff --git a/Cargo.lock b/Cargo.lock index 478626fa8..8fda26cd9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -35,9 +35,9 @@ dependencies = [ [[package]] name = "aes" -version = "0.8.3" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac1f845298e95f983ff1944b728ae08b8cebab80d684f0a832ed0fc74dfa27e2" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", @@ -60,9 +60,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ "getrandom 0.2.12", "once_cell", @@ -71,9 +71,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" +checksum = "42cd52102d3df161c77a887b608d7a4897d7cc112886a9537b738a887a03aaff" dependencies = [ "cfg-if", "const-random", @@ -256,7 +256,7 @@ checksum = "0ae92a5119aa49cdbcf6b9f893fe4e1d98b04ccbf82ee0584ad948a44a734dea" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -278,7 +278,7 @@ dependencies = [ "argh_shared", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -339,9 +339,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.3.15" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" +checksum = "a116f46a969224200a0a97f29cfd4c50e7534e4b4826bd23ea2c3c533039c82c" dependencies = [ "brotli", "flate2", @@ -349,19 +349,8 @@ dependencies = [ "memchr", "pin-project-lite", "tokio", -] - -[[package]] -name = "async-compression" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a116f46a969224200a0a97f29cfd4c50e7534e4b4826bd23ea2c3c533039c82c" -dependencies = [ - "flate2", - "futures-core", - "memchr", - "pin-project-lite", - "tokio", + "zstd 0.13.0", + "zstd-safe 7.0.0", ] [[package]] @@ -474,7 +463,7 @@ checksum = "5fd55a5ba1179988837d24ab4c7cc8ed6efdeff578ede0416b4225a5fca35bd0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -495,28 +484,6 @@ dependencies = [ "windows-sys 0.48.0", ] -[[package]] -name = "async-stream" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16e62a023e7c117e27523144c5d2459f4397fcc3cab0085af8e2224f643a0193" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - [[package]] name = "async-task" version = "4.7.0" @@ -531,7 +498,7 @@ checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -566,21 +533,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "atomic" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c59bdb34bc650a32731b31bd8f0829cc15d24a708ee31559e0bb34f2bc320cba" - -[[package]] -name = "atomic" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d818003e740b63afc82337e3160717f4f63078720a810b7b903e70a5d1d2994" -dependencies = [ - "bytemuck", -] - [[package]] name = "atomic-waker" version = "1.1.2" @@ -651,57 +603,23 @@ dependencies = [ [[package]] name = "axum" -version = "0.5.17" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acee9fd5073ab6b045a275b3e709c163dd36c90685219cb21804a147b58dba43" +checksum = "1236b4b292f6c4d6dc34604bb5120d85c3fe1d1aa596bd5cc52ca054d13e7b9e" dependencies = [ "async-trait", - "axum-core 0.2.9", - "base64 0.13.1", - "bitflags 1.3.2", - "bytes", - "futures-util", - "headers 0.3.9", - "http 0.2.11", - "http-body 0.4.6", - "hyper 0.14.28", - "itoa 1.0.10", - "matchit 0.5.0", - "memchr", - "mime", - "percent-encoding", - "pin-project-lite", - "serde", - "serde_json", - "serde_urlencoded", - "sha-1", - "sync_wrapper", - "tokio", - "tokio-tungstenite 0.17.2", - "tower", - "tower-http 0.3.5", - "tower-layer", - "tower-service", -] - -[[package]] -name = "axum" -version = "0.6.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b829e4e32b91e643de6eafe82b1d90675f5874230191a4ffbc1b336dec4d6bf" -dependencies = [ - "async-trait", - "axum-core 0.3.4", + "axum-core 0.4.3", "axum-macros", - "base64 0.21.7", - "bitflags 1.3.2", + "base64", "bytes", "futures-util", - "http 0.2.11", - "http-body 0.4.6", - "hyper 0.14.28", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.1.0", + "hyper-util", "itoa 1.0.10", - "matchit 0.7.3", + "matchit", "memchr", "mime", "percent-encoding", @@ -714,10 +632,11 @@ dependencies = [ "sha1", "sync_wrapper", "tokio", - "tokio-tungstenite 0.20.1", + "tokio-tungstenite", "tower", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -726,36 +645,20 @@ version = "0.1.0" dependencies = [ "anyhow", "async-trait", - "axum 0.6.20", - "axum_session", + "axum", + "axum_session 0.3.5", "axum_session_auth", "dioxus", "dioxus-fullstack", "dioxus-web", "execute", - "http 0.2.11", + "http 1.0.0", "serde", "simple_logger", "sqlx", "tokio", "tower", - "tower-http 0.4.4", -] - -[[package]] -name = "axum-core" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37e5939e02c56fecd5c017c37df4238c0a839fa76b7f97acdd7efb804fd181cc" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 0.2.11", - "http-body 0.4.6", - "mime", - "tower-layer", - "tower-service", + "tower-http", ] [[package]] @@ -775,11 +678,32 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-core" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15c63fd72d41492dc4f497196f5da1fb04fb7529e631d73630d1b491e47a2e3" +dependencies = [ + "async-trait", + "bytes", + "futures-util", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "mime", + "pin-project-lite", + "rustversion", + "sync_wrapper", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "axum-desktop" version = "0.1.0" dependencies = [ - "axum 0.6.20", + "axum", "dioxus", "serde", "tokio", @@ -800,21 +724,21 @@ dependencies = [ [[package]] name = "axum-macros" -version = "0.3.8" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdca6a10ecad987bda04e95606ef85a5417dcaac1a78455242d72e031e2b6b62" +checksum = "00c055ee2d014ae5981ce1016374e8213682aa14d9bf40e48ab48b5f3ef20eaa" dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] name = "axum-router" version = "0.1.0" dependencies = [ - "axum 0.6.20", + "axum", "dioxus", "serde", "tokio", @@ -834,7 +758,7 @@ dependencies = [ "hyper 0.14.28", "pin-project-lite", "rustls 0.21.10", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "tokio", "tokio-rustls 0.24.1", "tower-service", @@ -849,7 +773,7 @@ dependencies = [ "aes-gcm", "async-trait", "axum-core 0.3.4", - "base64 0.21.7", + "base64", "bytes", "chrono", "cookie 0.17.0", @@ -870,26 +794,59 @@ dependencies = [ ] [[package]] -name = "axum_session_auth" -version = "0.3.1" +name = "axum_session" +version = "0.12.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88d26b395b86d34230970c09fee81cad335704d5b6b797714a9ebb8a51cc4fa6" +checksum = "d0f0035d1d5a70ac279e80a75e60592023ba8b327c929c3827f6c5ed749b9f8b" +dependencies = [ + "aes-gcm", + "async-trait", + "axum", + "base64", + "bytes", + "chrono", + "cookie 0.18.0", + "dashmap", + "forwarded-header-value", + "futures", + "hmac", + "http 1.0.0", + "http-body 1.0.0", + "rand 0.8.5", + "serde", + "serde_json", + "sha2", + "sqlx", + "thiserror", + "tokio", + "tower-layer", + "tower-service", + "tracing", + "uuid", +] + +[[package]] +name = "axum_session_auth" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd4c620e865c92d9fca3ad57efeb4baef271f3ccdba163928002f13489952660" dependencies = [ "anyhow", "async-recursion", "async-trait", - "axum-core 0.3.4", - "axum_session", + "axum-core 0.4.3", + "axum_session 0.12.4", "bytes", "chrono", "dashmap", "futures", - "http 0.2.11", - "http-body 0.4.6", + "http 1.0.0", + "http-body 1.0.0", "serde", "tokio", "tower-layer", "tower-service", + "tracing", ] [[package]] @@ -907,12 +864,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "base64" -version = "0.13.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" - [[package]] name = "base64" version = "0.21.7" @@ -954,12 +905,6 @@ dependencies = [ "num-traits", ] -[[package]] -name = "binascii" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "383d29d513d8764dcdc42ea295d979eb99c3c9f00607b3692cf68a431f7dca72" - [[package]] name = "bincode" version = "1.3.3" @@ -1071,7 +1016,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", "syn_derive", ] @@ -1112,7 +1057,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" dependencies = [ "memchr", - "regex-automata 0.4.5", + "regex-automata", "serde", ] @@ -1142,9 +1087,9 @@ checksum = "38d17f4d6e4dc36d1a02fbedc2753a096848e7c1b0772f7654eab8e2c927dd53" [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "d32a994c2b3ca201d9b263612a374263f05e7adde37c4707f693dcd375076d1f" [[package]] name = "bytecheck" @@ -1259,7 +1204,7 @@ dependencies = [ "heck 0.4.1", "home", "ignore", - "indexmap 2.2.2", + "indexmap 2.2.3", "indicatif", "liquid", "liquid-core", @@ -1449,9 +1394,9 @@ checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" [[package]] name = "chrono" -version = "0.4.33" +version = "0.4.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" +checksum = "5bc015644b92d5890fab7489e49d21f879d5c990186827d42ec511919404f38b" dependencies = [ "android-tzdata", "iana-time-zone", @@ -1541,7 +1486,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -1761,7 +1706,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24" dependencies = [ "aes-gcm", - "base64 0.21.7", + "base64", "percent-encoding", "rand 0.8.5", "subtle", @@ -1776,11 +1721,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3cd91cf61412820176e137621345ee43b3f4423e589e7ae4e50d601d93e35ef8" dependencies = [ "aes-gcm", - "base64 0.21.7", - "hmac", + "base64", "percent-encoding", "rand 0.8.5", - "sha2", "subtle", "time", "version_check", @@ -1852,9 +1795,9 @@ checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] @@ -2017,16 +1960,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "cruet" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6132609543972496bc97b1e01f1ce6586768870aeb4cabeb3385f4e05b5caead" -dependencies = [ - "once_cell", - "regex", -] - [[package]] name = "crunchy" version = "0.2.2" @@ -2090,7 +2023,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "13b588ba4ac1a99f7f2964d24b3d896ddc6bf847ee3855dbd4366f058cfcd331" dependencies = [ "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -2121,7 +2054,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30d2b3721e861707777e3195b0158f950ae6dc4a27e4d02ff9f67e3eb3de199e" dependencies = [ "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -2154,9 +2087,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.5" +version = "0.20.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc5d6b04b3fd0ba9926f945895de7d806260a2d7431ba82e7edaecb043c4c6b8" +checksum = "c376d08ea6aa96aafe61237c7200d1241cb177b7d3a542d791f2d118e9cbb955" dependencies = [ "darling_core", "darling_macro", @@ -2164,27 +2097,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.5" +version = "0.20.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04e48a959bcd5c761246f5d090ebc2fbf7b9cd527a492b07a67510c108f1e7e3" +checksum = "33043dcd19068b8192064c704b3f83eb464f91f1ff527b44a4e2b08d9cdb8855" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] name = "darling_macro" -version = "0.20.5" +version = "0.20.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d1545d67a2149e1d93b7e5c7752dce5a7426eb5d1357ddcfd89336b94444f77" +checksum = "c5a91391accf613803c2a9bf9abccdbaa07c54b4244a5b64883f9c3c137c86be" dependencies = [ "darling_core", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -2260,39 +2193,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "devise" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6eacefd3f541c66fc61433d65e54e0e46e0a029a819a7dbbc7a7b489e8a85f8" -dependencies = [ - "devise_codegen", - "devise_core", -] - -[[package]] -name = "devise_codegen" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8cf4b8dd484ede80fd5c547592c46c3745a617c8af278e2b72bea86b2dfed6" -dependencies = [ - "devise_core", - "quote", -] - -[[package]] -name = "devise_core" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35b50dba0afdca80b187392b24f2499a88c336d5a8493e4b4ccfb608708be56a" -dependencies = [ - "bitflags 2.4.2", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn 2.0.48", -] - [[package]] name = "dialoguer" version = "0.11.0" @@ -2363,7 +2263,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -2384,7 +2284,7 @@ version = "0.4.3" dependencies = [ "anyhow", "atty", - "axum 0.5.17", + "axum", "axum-server", "cargo-generate", "cargo_metadata 0.18.1", @@ -2405,10 +2305,10 @@ dependencies = [ "flate2", "fs_extra", "futures-util", - "headers 0.3.9", + "headers", "html_parser", - "hyper 0.14.28", - "hyper-rustls 0.23.2", + "hyper 1.1.0", + "hyper-rustls 0.26.0", "ignore", "indicatif", "interprocess-docfix", @@ -2425,7 +2325,7 @@ dependencies = [ "serde", "serde_json", "subprocess", - "syn 2.0.48", + "syn 2.0.49", "tar", "tauri-bundler", "tempfile", @@ -2434,7 +2334,7 @@ dependencies = [ "toml 0.8.10", "toml_edit 0.21.1", "tower", - "tower-http 0.2.5", + "tower-http", "walkdir", "wasm-bindgen-cli-support", "zip", @@ -2451,7 +2351,7 @@ dependencies = [ "serde_json", "tauri-bundler", "tauri-utils", - "toml 0.5.11", + "toml 0.8.10", "tracing", ] @@ -2493,7 +2393,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.48", + "syn 2.0.49", "trybuild", ] @@ -2558,7 +2458,6 @@ dependencies = [ "serde", "serde_json", "tokio", - "warp", ] [[package]] @@ -2577,8 +2476,8 @@ version = "0.4.3" dependencies = [ "anymap 0.12.1", "async-trait", - "axum 0.6.20", - "base64 0.21.7", + "axum", + "base64", "bytes", "ciborium", "dioxus-cli-config", @@ -2590,12 +2489,10 @@ dependencies = [ "dioxus-web", "dioxus_server_macro", "futures-util", - "http 0.2.11", - "http-body-util", - "hyper 0.14.28", + "http 1.0.0", + "hyper 1.1.0", "once_cell", "pin-project", - "salvo", "serde", "serde_json", "server_fn", @@ -2604,11 +2501,10 @@ dependencies = [ "tokio-stream", "tokio-util", "tower", - "tower-http 0.4.4", + "tower-http", "tower-layer", "tracing", "tracing-futures", - "warp", "web-sys", ] @@ -2676,7 +2572,7 @@ dependencies = [ "convert_case 0.6.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", "trybuild", ] @@ -2711,8 +2607,7 @@ dependencies = [ name = "dioxus-liveview" version = "0.4.3" dependencies = [ - "async-trait", - "axum 0.6.20", + "axum", "dioxus", "dioxus-cli-config", "dioxus-core", @@ -2723,12 +2618,8 @@ dependencies = [ "futures-util", "generational-box", "minify-js", - "once_cell", "pretty_env_logger", - "rocket", - "rocket_ws", "rustc-hash", - "salvo", "serde", "serde_json", "slab", @@ -2738,7 +2629,6 @@ dependencies = [ "tokio-util", "tower", "tracing", - "warp", ] [[package]] @@ -2779,7 +2669,7 @@ dependencies = [ "quote", "rustc-hash", "smallvec", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -2794,7 +2684,7 @@ dependencies = [ name = "dioxus-playwright-liveview-test" version = "0.0.1" dependencies = [ - "axum 0.6.20", + "axum", "dioxus", "dioxus-liveview", "tokio", @@ -2825,7 +2715,7 @@ dependencies = [ name = "dioxus-router" version = "0.4.3" dependencies = [ - "axum 0.6.20", + "axum", "console_error_panic_hook", "criterion 0.5.1", "dioxus", @@ -2857,7 +2747,7 @@ dependencies = [ "proc-macro2", "quote", "slab", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -2870,7 +2760,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.48", + "syn 2.0.49", "tracing", ] @@ -2909,8 +2799,8 @@ dependencies = [ "fern", "fs_extra", "generational-box", - "http 0.2.11", - "lru 0.10.1", + "http 1.0.0", + "lru", "rustc-hash", "serde", "serde_json", @@ -2983,7 +2873,7 @@ dependencies = [ "proc-macro2", "quote", "server_fn_macro", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -3075,9 +2965,9 @@ checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" [[package]] name = "either" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" dependencies = [ "serde", ] @@ -3106,14 +2996,14 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] name = "enumflags2" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5998b4f30320c9d93aed72f63af821bfdac50465b75428fce77b48ec482c3939" +checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d" dependencies = [ "enumflags2_derive", "serde", @@ -3121,13 +3011,13 @@ dependencies = [ [[package]] name = "enumflags2_derive" -version = "0.7.8" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f95e2801cd355d4a1a3e3953ce6ee5ae9603a5c833455343a8bfe3f44d418246" +checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -3148,7 +3038,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -3180,16 +3070,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "etag" -version = "4.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b3d0661a2ccddc26cba0b834e9b717959ed6fdd76c7129ee159c170a875bf44" -dependencies = [ - "str-buf", - "xxhash-rust", -] - [[package]] name = "etcetera" version = "0.8.0" @@ -3298,7 +3178,7 @@ checksum = "ce8cd46a041ad005ab9c71263f9a0ff5b529eac0fe4cc9b4a20f4f0765d8cf4b" dependencies = [ "execute-command-tokens", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -3388,20 +3268,6 @@ dependencies = [ "rustc_version", ] -[[package]] -name = "figment" -version = "0.10.14" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b6e5bc7bd59d60d0d45a6ccab6cf0f4ce28698fb4e81e750ddf229c9b824026" -dependencies = [ - "atomic 0.6.0", - "pear", - "serde", - "toml 0.8.10", - "uncased", - "version_check", -] - [[package]] name = "filetime" version = "0.2.23" @@ -3480,7 +3346,7 @@ checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -3504,6 +3370,16 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "forwarded-header-value" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835f84f38484cc86f110a805655697908257fb9a7af005234060891557198e9" +dependencies = [ + "nonempty", + "thiserror", +] + [[package]] name = "fs-err" version = "2.11.0" @@ -3653,7 +3529,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -3803,19 +3679,6 @@ dependencies = [ "rand 0.8.5", ] -[[package]] -name = "generator" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cc16584ff22b460a382b7feec54b23d2908d858152e5739a120b949293bd74e" -dependencies = [ - "cc", - "libc", - "log", - "rustversion", - "windows 0.48.0", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -3954,7 +3817,7 @@ dependencies = [ "gix-date", "itoa 1.0.10", "thiserror", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -3975,7 +3838,7 @@ dependencies = [ "smallvec", "thiserror", "unicode-bom", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -4075,7 +3938,7 @@ dependencies = [ "itoa 1.0.10", "smallvec", "thiserror", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -4109,7 +3972,7 @@ dependencies = [ "gix-validate", "memmap2", "thiserror", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -4197,7 +4060,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -4239,8 +4102,8 @@ dependencies = [ "aho-corasick 1.1.2", "bstr 1.9.0", "log", - "regex-automata 0.4.5", - "regex-syntax 0.8.2", + "regex-automata", + "regex-syntax", ] [[package]] @@ -4495,7 +4358,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -4510,7 +4373,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.11", - "indexmap 2.2.2", + "indexmap 2.2.3", "slab", "tokio", "tokio-util", @@ -4529,7 +4392,7 @@ dependencies = [ "futures-sink", "futures-util", "http 1.0.0", - "indexmap 2.2.2", + "indexmap 2.2.3", "slab", "tokio", "tokio-util", @@ -4572,7 +4435,7 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.7", + "ahash 0.7.8", ] [[package]] @@ -4581,7 +4444,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.8", "bumpalo", ] @@ -4591,7 +4454,7 @@ version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.8", "allocator-api2", ] @@ -4610,30 +4473,15 @@ version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ - "base64 0.21.7", + "base64", "bytes", - "headers-core 0.2.0", + "headers-core", "http 0.2.11", "httpdate", "mime", "sha1", ] -[[package]] -name = "headers" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" -dependencies = [ - "base64 0.21.7", - "bytes", - "headers-core 0.3.0", - "http 1.0.0", - "httpdate", - "mime", - "sha1", -] - [[package]] name = "headers-core" version = "0.2.0" @@ -4643,15 +4491,6 @@ dependencies = [ "http 0.2.11", ] -[[package]] -name = "headers-core" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" -dependencies = [ - "http 1.0.0", -] - [[package]] name = "heck" version = "0.3.3" @@ -4681,9 +4520,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.5" +version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" +checksum = "bd5256b483761cd23699d0da46cc6fd2ee3be420bbe6d020ae4a091e70b7e9fd" [[package]] name = "hex" @@ -4845,9 +4684,9 @@ checksum = "21dec9db110f5f872ed9699c3ecf50cf16f423502706ba5c72462e28d3157573" [[package]] name = "http-range-header" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "add0ab9360ddbd88cfeb3bd9574a1d85cfdfa14db10b3e21d3700dbc4328758f" +checksum = "3ce4ef31cda248bbdb6e6820603b82dfcd9e833db65a43e997a0ccec777d11fe" [[package]] name = "httparse" @@ -4911,21 +4750,6 @@ dependencies = [ "want", ] -[[package]] -name = "hyper-rustls" -version = "0.23.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1788965e61b367cd03a62950836d5cd41560c3577d90e40e0819373194d1661c" -dependencies = [ - "http 0.2.11", - "hyper 0.14.28", - "log", - "rustls 0.20.9", - "rustls-native-certs", - "tokio", - "tokio-rustls 0.23.4", -] - [[package]] name = "hyper-rustls" version = "0.24.2" @@ -4940,6 +4764,25 @@ dependencies = [ "tokio-rustls 0.24.1", ] +[[package]] +name = "hyper-rustls" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0bea761b46ae2b24eb4aef630d8d1c398157b6fc29e6350ecf090a0b70c952c" +dependencies = [ + "futures-util", + "http 1.0.0", + "hyper 1.1.0", + "hyper-util", + "log", + "rustls 0.22.2", + "rustls-native-certs", + "rustls-pki-types", + "tokio", + "tokio-rustls 0.25.0", + "tower-service", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -4960,6 +4803,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ca38ef113da30126bbff9cd1705f9273e15d45498615d138b0c20279ac7a76aa" dependencies = [ "bytes", + "futures-channel", "futures-util", "http 1.0.0", "http-body 1.0.0", @@ -4967,6 +4811,9 @@ dependencies = [ "pin-project-lite", "socket2 0.5.5", "tokio", + "tower", + "tower-service", + "tracing", ] [[package]] @@ -5034,7 +4881,7 @@ dependencies = [ "globset", "log", "memchr", - "regex-automata 0.4.5", + "regex-automata", "same-file", "walkdir", "winapi-util", @@ -5093,9 +4940,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "824b2ae422412366ba479e8111fd301f7b5faece8149317bb81925979a53f520" +checksum = "233cf39063f058ea2caae4091bf4a3ef70a653afbc026f5c4a4135d114e3c177" dependencies = [ "equivalent", "hashbrown 0.14.3", @@ -5104,9 +4951,9 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.17.7" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" dependencies = [ "console", "instant", @@ -5139,12 +4986,6 @@ dependencies = [ "cfb", ] -[[package]] -name = "inlinable_string" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8fae54786f62fb2918dcfae3d568594e50eb9b5c25bf04371af6fe7516452fb" - [[package]] name = "inotify" version = "0.9.6" @@ -5201,7 +5042,7 @@ checksum = "c34819042dc3d3971c46c2190835914dfbe0c3c13f61449b2997f4e9722dfa60" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -5242,7 +5083,7 @@ version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" dependencies = [ - "hermit-abi 0.3.5", + "hermit-abi 0.3.6", "libc", "windows-sys 0.48.0", ] @@ -5276,11 +5117,12 @@ dependencies = [ [[package]] name = "iri-string" -version = "0.4.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f0f7638c1e223529f1bfdc48c8b133b9e0b434094d1d28473161ee48b235f78" +checksum = "21859b667d66a4c1dacd9df0863b3efb65785474255face87f5bca39dd8407c0" dependencies = [ - "nom", + "memchr", + "serde", ] [[package]] @@ -5294,11 +5136,11 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe8f25ce1159c7740ff0b9b2f5cdf4a8428742ba7c112b9f20f22cd5219c7dab" +checksum = "f23ff5ef2b80d608d61efee834934d862cd92461afc0560dedf493e4c033738b" dependencies = [ - "hermit-abi 0.3.5", + "hermit-abi 0.3.6", "libc", "windows-sys 0.52.0", ] @@ -5675,17 +5517,18 @@ dependencies = [ [[package]] name = "lightningcss" -version = "1.0.0-alpha.52" +version = "1.0.0-alpha.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771a62dedf5ec563bbfea9760f6c6a6bc546e67355eba0cd7d00c0dc34b11d90" +checksum = "4ae8ba2b1b450cefc6a7a6ee93868992f56f662869b90404de2a7319da18640f" dependencies = [ - "ahash 0.7.7", + "ahash 0.8.8", "bitflags 2.4.2", "const-str", "cssparser 0.33.0", "cssparser-color", "dashmap", "data-encoding", + "getrandom 0.2.12", "itertools 0.10.5", "lazy_static", "parcel_selectors", @@ -5769,7 +5612,7 @@ checksum = "fc2fb41a9bb4257a3803154bdf7e2df7d45197d1941c9b1a90ad815231630721" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -5812,21 +5655,6 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b3bd0dd2cd90571056fdb71f6275fada10131182f84899f4b2a916e565d81d86" -[[package]] -name = "loom" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff50ecb28bb86013e935fb6683ab1f6d3a20016f123c76fd4c27470076ac30f5" -dependencies = [ - "cfg-if", - "generator", - "scoped-tls", - "serde", - "serde_json", - "tracing", - "tracing-subscriber", -] - [[package]] name = "loop9" version = "0.1.5" @@ -5836,15 +5664,6 @@ dependencies = [ "imgref", ] -[[package]] -name = "lru" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "718e8fae447df0c7e1ba7f5189829e63fd536945c8988d61444c19039f16b670" -dependencies = [ - "hashbrown 0.13.2", -] - [[package]] name = "lru" version = "0.12.2" @@ -5947,7 +5766,7 @@ version = "0.1.0" source = "git+https://github.com/DioxusLabs/collect-assets?rev=f982698#f982698027fc27d22acfb4121fba389ec125d538" dependencies = [ "anyhow", - "base64 0.21.7", + "base64", "home", "infer 0.11.0", "reqwest", @@ -5961,12 +5780,12 @@ name = "manganis-macro" version = "0.0.1" source = "git+https://github.com/DioxusLabs/collect-assets?rev=f982698#f982698027fc27d22acfb4121fba389ec125d538" dependencies = [ - "base64 0.21.7", + "base64", "manganis-cli-support", "manganis-common", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -5989,27 +5808,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbee8634e0d45d258acb448e7eaab3fce7a0a467395d4d9f228e3c1f01fb2e4" -[[package]] -name = "matchers" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558" -dependencies = [ - "regex-automata 0.1.10", -] - [[package]] name = "matches" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2532096657941c2fea9c289d370a250971c689d4f143798ff67113ec042024a5" -[[package]] -name = "matchit" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73cbba799671b762df5a175adf59ce145165747bb891505c43d09aefbbf38beb" - [[package]] name = "matchit" version = "0.7.3" @@ -6090,16 +5894,6 @@ version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" -[[package]] -name = "mime-infer" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91caed19dd472bc88bcd063571df18153529d49301a1918f4cf37f42332bee2e" -dependencies = [ - "mime", - "unicase", -] - [[package]] name = "mime_guess" version = "2.0.4" @@ -6225,53 +6019,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "multer" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01acbdc23469fd8fe07ab135923371d5f5a422fbf9c522158677c8eb15bc51c2" -dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http 0.2.11", - "httparse", - "log", - "memchr", - "mime", - "spin 0.9.8", - "tokio", - "tokio-util", - "version_check", -] - -[[package]] -name = "multer" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a15d522be0a9c3e46fd2632e272d178f56387bdb5c9fbb3a36c649062e9b5219" -dependencies = [ - "bytes", - "encoding_rs", - "futures-util", - "http 1.0.0", - "httparse", - "log", - "memchr", - "mime", - "spin 0.9.8", - "version_check", -] - -[[package]] -name = "multimap" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1a5d38b9b352dbd913288736af36af41c48d61b1a8cd34bcecd727561b7d511" -dependencies = [ - "serde", -] - [[package]] name = "names" version = "0.14.0" @@ -6395,6 +6142,12 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nonempty" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9e591e719385e6ebaeb5ce5d3887f7d5676fceca6411d1925ccc95745f3d6f7" + [[package]] name = "noop_proc_macro" version = "0.3.0" @@ -6492,7 +6245,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -6543,7 +6296,7 @@ version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.3.5", + "hermit-abi 0.3.6", "libc", ] @@ -6570,9 +6323,9 @@ dependencies = [ [[package]] name = "num_threads" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +checksum = "5c7398b9c8b70908f6371f47ed36737907c87c52af34c268fed0bf0ceb92ead9" dependencies = [ "libc", ] @@ -6683,7 +6436,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -6694,9 +6447,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] name = "openssl-src" -version = "300.2.2+3.2.1" +version = "300.2.3+3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8bbfad0063610ac26ee79f7484739e2b07555a75c42453b89263830b5c8103bc" +checksum = "5cff92b6f71555b61bb9315f7c64da3ca43d87531622120fea0195fc761b4843" dependencies = [ "cc", ] @@ -6902,12 +6655,6 @@ dependencies = [ "once_cell", ] -[[package]] -name = "path-slash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e91099d4268b0e11973f036e885d652fb0b21fedcf69738c627f94db6a44f42" - [[package]] name = "pathdiff" version = "0.2.1" @@ -6926,29 +6673,6 @@ dependencies = [ "sha2", ] -[[package]] -name = "pear" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ccca0f6c17acc81df8e242ed473ec144cbf5c98037e69aa6d144780aad103c8" -dependencies = [ - "inlinable_string", - "pear_codegen", - "yansi 1.0.0-rc.1", -] - -[[package]] -name = "pear_codegen" -version = "0.2.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e22670e8eb757cff11d6c199ca7b987f352f0346e0be4dd23869ec72cb53c77" -dependencies = [ - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "syn 2.0.48", -] - [[package]] name = "pem-rfc7468" version = "0.7.0" @@ -6995,7 +6719,7 @@ dependencies = [ "pest_meta", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -7016,7 +6740,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.2.2", + "indexmap 2.2.3", ] [[package]] @@ -7123,7 +6847,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -7170,7 +6894,7 @@ checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -7219,9 +6943,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plasmo" @@ -7251,8 +6975,8 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e5699cc8a63d1aa2b1ee8e12b9ad70ac790d65788cd36101fa37f87ea46c4cef" dependencies = [ - "base64 0.21.7", - "indexmap 2.2.2", + "base64", + "indexmap 2.2.3", "line-wrap", "quick-xml", "serde", @@ -7373,7 +7097,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "22020dfcf177fcc7bf5deaf7440af371400c67c0de14c399938d8ed4fb4645d3" dependencies = [ "proc-macro2", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -7383,7 +7107,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66" dependencies = [ "diff", - "yansi 0.5.1", + "yansi", ] [[package]] @@ -7403,7 +7127,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a41cf62165e97c7f814d2221421dbb9afcbcdb0a88068e5ea206e19951c2cbb5" dependencies = [ "proc-macro2", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -7473,19 +7197,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "proc-macro2-diagnostics" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af066a9c399a26e020ada66a034357a868728e72cd426f3adcd35f80d88d88c8" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", - "version_check", - "yansi 1.0.0-rc.1", -] - [[package]] name = "prodash" version = "26.2.2" @@ -7508,7 +7219,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ce97fecd27bc49296e5e20518b5a1bb54a14f7d5fe6228bc9686ee2a74915cc8" dependencies = [ "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -7684,7 +7395,7 @@ dependencies = [ "crossterm 0.27.0", "indoc", "itertools 0.11.0", - "lru 0.12.2", + "lru", "paste", "strum", "unicode-segmentation", @@ -7833,26 +7544,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "ref-cast" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4846d4c50d1721b1a3bef8af76924eef20d5e723647333798c1b519b3a9473f" -dependencies = [ - "ref-cast-impl", -] - -[[package]] -name = "ref-cast-impl" -version = "1.0.22" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fddb4f8d99b0a2ebafc65a87a69a7b9875e4b1ae1f00db265d300ef7f28bccc" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - [[package]] name = "regex" version = "1.10.3" @@ -7861,17 +7552,8 @@ checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" dependencies = [ "aho-corasick 1.1.2", "memchr", - "regex-automata 0.4.5", - "regex-syntax 0.8.2", -] - -[[package]] -name = "regex-automata" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" -dependencies = [ - "regex-syntax 0.6.29", + "regex-automata", + "regex-syntax", ] [[package]] @@ -7882,15 +7564,9 @@ checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" dependencies = [ "aho-corasick 1.1.2", "memchr", - "regex-syntax 0.8.2", + "regex-syntax", ] -[[package]] -name = "regex-syntax" -version = "0.6.29" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" - [[package]] name = "regex-syntax" version = "0.8.2" @@ -7928,7 +7604,7 @@ version = "0.11.24" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" dependencies = [ - "base64 0.21.7", + "base64", "bytes", "encoding_rs", "futures-core", @@ -7948,7 +7624,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls 0.21.10", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "serde", "serde_json", "serde_urlencoded", @@ -8017,7 +7693,7 @@ version = "1.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3625f343d89990133d013e39c46e350915178cf94f1bec9f49b0cbef98a3e3c" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.8", "bitflags 2.4.2", "instant", "num-traits", @@ -8035,22 +7711,7 @@ checksum = "853977598f084a492323fe2f7896b4100a86284ee8473612de60021ea341310f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", -] - -[[package]] -name = "ring" -version = "0.16.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" -dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", + "syn 2.0.49", ] [[package]] @@ -8063,7 +7724,7 @@ dependencies = [ "getrandom 0.2.12", "libc", "spin 0.9.8", - "untrusted 0.9.0", + "untrusted", "windows-sys 0.48.0", ] @@ -8102,106 +7763,15 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3582f63211428f83597b51b2ddb88e2a91a9d52d12831f9d08f5e624e8977422" -[[package]] -name = "rocket" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e7bb57ccb26670d73b6a47396c83139447b9e7878cab627fdfe9ea8da489150" -dependencies = [ - "async-stream", - "async-trait", - "atomic 0.5.3", - "binascii", - "bytes", - "either", - "figment", - "futures", - "indexmap 2.2.2", - "log", - "memchr", - "multer 2.1.0", - "num_cpus", - "parking_lot", - "pin-project-lite", - "rand 0.8.5", - "ref-cast", - "rocket_codegen", - "rocket_http", - "serde", - "state", - "tempfile", - "time", - "tokio", - "tokio-stream", - "tokio-util", - "ubyte", - "version_check", - "yansi 1.0.0-rc.1", -] - -[[package]] -name = "rocket_codegen" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2238066abf75f21be6cd7dc1a09d5414a671f4246e384e49fe3f8a4936bd04c" -dependencies = [ - "devise", - "glob", - "indexmap 2.2.2", - "proc-macro2", - "quote", - "rocket_http", - "syn 2.0.48", - "unicode-xid", - "version_check", -] - -[[package]] -name = "rocket_http" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37a1663694d059fe5f943ea5481363e48050acedd241d46deb2e27f71110389e" -dependencies = [ - "cookie 0.18.0", - "either", - "futures", - "http 0.2.11", - "hyper 0.14.28", - "indexmap 2.2.2", - "log", - "memchr", - "pear", - "percent-encoding", - "pin-project-lite", - "ref-cast", - "serde", - "smallvec", - "stable-pattern", - "state", - "time", - "tokio", - "uncased", -] - -[[package]] -name = "rocket_ws" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6677b3fe72e2d73dd632c412546ed8153e8685c830ee8d20e4488575cb905d9" -dependencies = [ - "rocket", - "tokio-tungstenite 0.20.1", -] - [[package]] name = "ron" version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94" dependencies = [ - "base64 0.21.7", + "base64", "bitflags 2.4.2", - "indexmap 2.2.2", + "indexmap 2.2.3", "serde", "serde_derive", ] @@ -8238,48 +7808,14 @@ dependencies = [ "pretty_assertions", "proc-macro2", "quote", - "syn 2.0.48", -] - -[[package]] -name = "rust-embed" -version = "8.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a82c0bbc10308ed323529fd3c1dce8badda635aa319a5ff0e6466f33b8101e3f" -dependencies = [ - "rust-embed-impl", - "rust-embed-utils", - "walkdir", -] - -[[package]] -name = "rust-embed-impl" -version = "8.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6227c01b1783cdfee1bcf844eb44594cd16ec71c35305bf1c9fb5aade2735e16" -dependencies = [ - "proc-macro2", - "quote", - "rust-embed-utils", - "syn 2.0.48", - "walkdir", -] - -[[package]] -name = "rust-embed-utils" -version = "8.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cb0a25bfbb2d4b4402179c2cf030387d9990857ce08a32592c6238db9fa8665" -dependencies = [ - "sha2", - "walkdir", + "syn 2.0.49", ] [[package]] name = "rust_decimal" -version = "1.34.2" +version = "1.34.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "755392e1a2f77afd95580d3f0d0e94ac83eeeb7167552c9b5bca549e61a94d83" +checksum = "b39449a79f45e8da28c57c341891b69a183044b29518bb8f86dbac9df60bb7df" dependencies = [ "arrayvec", "borsh", @@ -8361,18 +7897,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "rustls" -version = "0.20.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b80e3dec595989ea8510028f30c408a4630db12c9cbb8de34203b89d6577e99" -dependencies = [ - "log", - "ring 0.16.20", - "sct", - "webpki", -] - [[package]] name = "rustls" version = "0.21.10" @@ -8380,7 +7904,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ "log", - "ring 0.17.7", + "ring", "rustls-webpki 0.101.7", "sct", ] @@ -8392,7 +7916,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e87c9956bd9807afa1f77e0f7594af32566e830e088a5576d27c5b6f30f49d41" dependencies = [ "log", - "ring 0.17.7", + "ring", "rustls-pki-types", "rustls-webpki 0.102.2", "subtle", @@ -8401,12 +7925,13 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.6.3" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +checksum = "8f1fb85efa936c42c6d5fc28d2629bb51e4b2f4b8a5211e297d599cc5a093792" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pemfile 2.1.0", + "rustls-pki-types", "schannel", "security-framework", ] @@ -8417,14 +7942,24 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.21.7", + "base64", +] + +[[package]] +name = "rustls-pemfile" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c333bb734fcdedcea57de1602543590f545f127dc8b533324318fd492c5c70b" +dependencies = [ + "base64", + "rustls-pki-types", ] [[package]] name = "rustls-pki-types" -version = "1.2.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a716eb65e3158e90e17cd93d855216e27bde02745ab842f2cab4a39dba1bacf" +checksum = "048a63e5b3ac996d78d402940b5fa47973d2d080c6c6fffa1d0f19c4445310b7" [[package]] name = "rustls-webpki" @@ -8432,8 +7967,8 @@ version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.7", - "untrusted 0.9.0", + "ring", + "untrusted", ] [[package]] @@ -8442,9 +7977,9 @@ version = "0.102.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "faaa0a62740bedb9b2ef5afa303da42764c012f743917351dc9a237ea1663610" dependencies = [ - "ring 0.17.7", + "ring", "rustls-pki-types", - "untrusted 0.9.0", + "untrusted", ] [[package]] @@ -8465,151 +8000,6 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef703b7cb59335eae2eb93ceb664c0eb7ea6bf567079d843e09420219668e072" -[[package]] -name = "salvo" -version = "0.63.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc1aaf77a4c306270cb7b1a6e08a5b12ee14935ac5a5c6b0ce1958d66a72ad9" -dependencies = [ - "salvo-compression", - "salvo-serve-static", - "salvo_core", - "salvo_extra", -] - -[[package]] -name = "salvo-compression" -version = "0.63.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c487a736613df6e2ae455bdd3775d86ad9a2a2dcf0cd4067adc9ce08dc9f0d97" -dependencies = [ - "brotli", - "bytes", - "flate2", - "futures-util", - "indexmap 2.2.2", - "salvo_core", - "tokio", - "tokio-util", - "tracing", - "zstd 0.13.0", -] - -[[package]] -name = "salvo-hello-world" -version = "0.1.0" -dependencies = [ - "dioxus", - "dioxus-fullstack", - "dioxus-web", - "execute", - "reqwest", - "salvo", - "serde", - "simple_logger", - "tracing", - "tracing-subscriber", - "tracing-wasm", -] - -[[package]] -name = "salvo-serve-static" -version = "0.63.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef927fe76c5444b3ef6386180ec0f39998e26414dee66e6ce48b91da6f2ef8e" -dependencies = [ - "hex", - "mime", - "mime-infer", - "path-slash", - "percent-encoding", - "rust-embed", - "salvo_core", - "serde", - "serde_json", - "time", - "tokio", - "tracing", -] - -[[package]] -name = "salvo_core" -version = "0.63.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c36a49a4227992bb0e27f3c9589e24b2bd8c68a29e2ed42e03f6de6da39faa0f" -dependencies = [ - "async-trait", - "base64 0.21.7", - "bytes", - "cookie 0.18.0", - "cruet", - "enumflags2", - "form_urlencoded", - "futures-channel", - "futures-util", - "headers 0.4.0", - "http 1.0.0", - "http-body-util", - "hyper 1.1.0", - "hyper-util", - "indexmap 2.2.2", - "mime", - "mime-infer", - "multer 3.0.0", - "multimap", - "nix 0.27.1", - "once_cell", - "parking_lot", - "percent-encoding", - "pin-project", - "rand 0.8.5", - "regex", - "salvo_macros", - "serde", - "serde-xml-rs", - "serde_json", - "sync_wrapper", - "tempfile", - "thiserror", - "tokio", - "tokio-util", - "tracing", -] - -[[package]] -name = "salvo_extra" -version = "0.63.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcfdffe788f7ae4c79bdeea16db85cd27e473a8d4bef44ba10b9323461f78087" -dependencies = [ - "base64 0.21.7", - "etag", - "futures-util", - "hyper 1.1.0", - "pin-project", - "salvo_core", - "serde", - "serde_json", - "tokio", - "tokio-tungstenite 0.21.0", - "tracing", - "ulid", -] - -[[package]] -name = "salvo_macros" -version = "0.63.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fa50756ef995d410bb1968b403a1eca169b54c3c0eb4be4bcb1da8c7591cb7d" -dependencies = [ - "cruet", - "proc-macro-crate 2.0.0", - "proc-macro2", - "quote", - "regex", - "syn 2.0.48", -] - [[package]] name = "same-file" version = "1.0.6" @@ -8656,8 +8046,8 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.7", - "untrusted 0.9.0", + "ring", + "untrusted", ] [[package]] @@ -8754,18 +8144,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "serde-xml-rs" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb3aa78ecda1ebc9ec9847d5d3aba7d618823446a049ba2491940506da6e2782" -dependencies = [ - "log", - "serde", - "thiserror", - "xml-rs", -] - [[package]] name = "serde_cbor" version = "0.11.2" @@ -8784,7 +8162,7 @@ checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -8837,7 +8215,7 @@ checksum = "0b2e6b945e9d3df726b65d6ee24060aff8e3533d431f677a9695db04eff9dfdb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -8867,11 +8245,11 @@ version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15d167997bd841ec232f5b2b8e0e26606df2e7caa4c31b95ea9ca52b200bd270" dependencies = [ - "base64 0.21.7", + "base64", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.2.2", + "indexmap 2.2.3", "serde", "serde_derive", "serde_json", @@ -8888,7 +8266,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -8911,7 +8289,7 @@ dependencies = [ "serde_json", "serde_qs", "server_fn_macro_default", - "syn 2.0.48", + "syn 2.0.49", "thiserror", "xxhash-rust", ] @@ -8927,7 +8305,7 @@ dependencies = [ "proc-macro2", "quote", "serde", - "syn 2.0.48", + "syn 2.0.49", "xxhash-rust", ] @@ -8938,7 +8316,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a3353f22e2bcc451074d4feaa37317d9d17dff11d4311928384734ea17ab9ca" dependencies = [ "server_fn_macro", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -8951,17 +8329,6 @@ dependencies = [ "stable_deref_trait", ] -[[package]] -name = "sha-1" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest", -] - [[package]] name = "sha1" version = "0.10.6" @@ -9132,7 +8499,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9298e863f0143b89972299110a7fa3e2fc08c412341d588c497bae38409f9e68" dependencies = [ "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -9141,7 +8508,7 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f20798defa0e9d4eff9ca451c7f84774c7378a9c3b5a40112cfa2b3eadb97ae2" dependencies = [ - "lru 0.12.2", + "lru", "once_cell", "rustc-hash", ] @@ -9282,7 +8649,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d84b0a3c3739e220d94b3239fd69fb1f74bc36e16643423bd99de3b43c21bfbd" dependencies = [ - "ahash 0.8.7", + "ahash 0.8.8", "atoi", "bigdecimal", "bit-vec", @@ -9301,7 +8668,7 @@ dependencies = [ "futures-util", "hashlink", "hex", - "indexmap 2.2.2", + "indexmap 2.2.3", "ipnetwork", "log", "mac_address", @@ -9311,7 +8678,7 @@ dependencies = [ "percent-encoding", "rust_decimal", "rustls 0.21.10", - "rustls-pemfile", + "rustls-pemfile 1.0.4", "serde", "serde_json", "sha2", @@ -9374,7 +8741,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e37195395df71fd068f6e2082247891bc11e3289624bbc776a0cdfa1ca7f1ea4" dependencies = [ "atoi", - "base64 0.21.7", + "base64", "bigdecimal", "bitflags 2.4.2", "byteorder", @@ -9421,7 +8788,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6ac0ac3b7ccd10cc96c7ab29791a7dd236bd94021f31eec7ba3d46a74aa1c24" dependencies = [ "atoi", - "base64 0.21.7", + "base64", "bigdecimal", "bit-vec", "bitflags 2.4.2", @@ -9488,30 +8855,12 @@ dependencies = [ "uuid", ] -[[package]] -name = "stable-pattern" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4564168c00635f88eaed410d5efa8131afa8d8699a612c80c455a0ba05c21045" -dependencies = [ - "memchr", -] - [[package]] name = "stable_deref_trait" version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" -[[package]] -name = "state" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b8c4a4445d81357df8b1a650d0d0d6fbbbfe99d064aa5e02f3e4022061476d8" -dependencies = [ - "loom", -] - [[package]] name = "static-hydrated" version = "0.1.0" @@ -9530,12 +8879,6 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" -[[package]] -name = "str-buf" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ceb97b7225c713c2fd4db0153cb6b3cab244eb37900c3f634ed4d43310d8c34" - [[package]] name = "string_cache" version = "0.8.7" @@ -9598,7 +8941,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -9640,9 +8983,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.49" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "915aea9e586f80826ee59f8453c1101f9d1c4b3964cd2460185ee8e299ada496" dependencies = [ "proc-macro2", "quote", @@ -9658,7 +9001,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -9748,7 +9091,7 @@ dependencies = [ "tao-macros", "unicode-segmentation", "url", - "windows 0.52.0", + "windows", "windows-implement", "windows-version", "x11-dl", @@ -9928,22 +9271,22 @@ checksum = "8eaa81235c7058867fa8c0e7314f33dcce9c215f535d1913822a2b3f5e289f3c" [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -10067,7 +9410,7 @@ checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -10080,17 +9423,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "tokio-rustls" -version = "0.23.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" -dependencies = [ - "rustls 0.20.9", - "tokio", - "webpki", -] - [[package]] name = "tokio-rustls" version = "0.24.1" @@ -10101,6 +9433,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "775e0c0f0adb3a2f22a00c4745d728b479985fc15ee7ca6a2608388c5569860f" +dependencies = [ + "rustls 0.22.2", + "rustls-pki-types", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.14" @@ -10113,30 +9456,6 @@ dependencies = [ "tokio-util", ] -[[package]] -name = "tokio-tungstenite" -version = "0.17.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite 0.17.3", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" -dependencies = [ - "futures-util", - "log", - "tokio", - "tungstenite 0.20.1", -] - [[package]] name = "tokio-tungstenite" version = "0.21.0" @@ -10146,7 +9465,7 @@ dependencies = [ "futures-util", "log", "tokio", - "tungstenite 0.21.0", + "tungstenite", ] [[package]] @@ -10192,11 +9511,11 @@ version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290" dependencies = [ - "indexmap 2.2.2", + "indexmap 2.2.3", "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.4", + "toml_edit 0.22.6", ] [[package]] @@ -10214,11 +9533,11 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.2.2", + "indexmap 2.2.3", "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -10227,9 +9546,9 @@ version = "0.20.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81" dependencies = [ - "indexmap 2.2.2", + "indexmap 2.2.3", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] @@ -10238,22 +9557,22 @@ version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" dependencies = [ - "indexmap 2.2.2", + "indexmap 2.2.3", "toml_datetime", - "winnow", + "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.22.4" +version = "0.22.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c9ffdf896f8daaabf9b66ba8e77ea1ed5ed0f72821b398aba62352e95062951" +checksum = "2c1b5fd4128cc8d3e0cb74d4ed9a9cc7c7284becd4df68f5f940e1ad123606f6" dependencies = [ - "indexmap 2.2.2", + "indexmap 2.2.3", "serde", "serde_spanned", "toml_datetime", - "winnow", + "winnow 0.6.1", ] [[package]] @@ -10274,18 +9593,19 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.2.5" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aba3f3efabf7fb41fae8534fc20a817013dd1c12cb45441efb6c82e6556b4cd8" +checksum = "0da193277a4e2c33e59e09b5861580c33dd0a637c3883d0fa74ba40c0374af2e" dependencies = [ - "async-compression 0.3.15", - "base64 0.13.1", - "bitflags 1.3.2", + "async-compression", + "base64", + "bitflags 2.4.2", "bytes", "futures-core", "futures-util", - "http 0.2.11", - "http-body 0.4.6", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", "http-range-header", "httpdate", "iri-string", @@ -10299,52 +9619,7 @@ dependencies = [ "tower-layer", "tower-service", "tracing", -] - -[[package]] -name = "tower-http" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f873044bf02dd1e8239e9c1293ea39dad76dc594ec16185d0a1bf31d8dc8d858" -dependencies = [ - "bitflags 1.3.2", - "bytes", - "futures-core", - "futures-util", - "http 0.2.11", - "http-body 0.4.6", - "http-range-header", - "pin-project-lite", - "tower", - "tower-layer", - "tower-service", -] - -[[package]] -name = "tower-http" -version = "0.4.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61c5bb1d698276a2443e5ecfabc1008bf15a36c12e6a7176e7bf089ea9131140" -dependencies = [ - "async-compression 0.4.6", - "base64 0.21.7", - "bitflags 2.4.2", - "bytes", - "futures-core", - "futures-util", - "http 0.2.11", - "http-body 0.4.6", - "http-range-header", - "httpdate", - "mime", - "mime_guess", - "percent-encoding", - "pin-project-lite", - "tokio", - "tokio-util", - "tower-layer", - "tower-service", - "tracing", + "uuid", ] [[package]] @@ -10379,7 +9654,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -10419,14 +9694,10 @@ version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ - "matchers", "nu-ansi-term", - "once_cell", - "regex", "sharded-slab", "smallvec", "thread_local", - "tracing", "tracing-core", "tracing-log", ] @@ -10521,33 +9792,14 @@ dependencies = [ [[package]] name = "tungstenite" -version = "0.17.3" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" -dependencies = [ - "base64 0.13.1", - "byteorder", - "bytes", - "http 0.2.11", - "httparse", - "log", - "rand 0.8.5", - "sha-1", - "thiserror", - "url", - "utf-8", -] - -[[package]] -name = "tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" dependencies = [ "byteorder", "bytes", "data-encoding", - "http 0.2.11", + "http 1.0.0", "httparse", "log", "rand 0.8.5", @@ -10557,35 +9809,12 @@ dependencies = [ "utf-8", ] -[[package]] -name = "tungstenite" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ef1a641ea34f399a848dea702823bbecfb4c486f911735368f1f137cb8257e1" -dependencies = [ - "byteorder", - "bytes", - "log", - "rand 0.8.5", - "thiserror", - "utf-8", -] - [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" -[[package]] -name = "ubyte" -version = "0.10.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f720def6ce1ee2fc44d40ac9ed6d3a59c361c80a75a7aa8e75bb9baed31cf2ea" -dependencies = [ - "serde", -] - [[package]] name = "ucd-trie" version = "0.1.6" @@ -10603,27 +9832,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "ulid" -version = "1.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34778c17965aa2a08913b57e1f34db9b4a63f5de31768b55bf20d2795f921259" -dependencies = [ - "getrandom 0.2.12", - "rand 0.8.5", - "web-time", -] - -[[package]] -name = "uncased" -version = "0.9.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1b88fcfe09e89d3866a5c11019378088af2d24c3fbd4f0543f96b479ec90697" -dependencies = [ - "serde", - "version_check", -] - [[package]] name = "unicase" version = "2.7.0" @@ -10694,12 +9902,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "untrusted" -version = "0.7.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" - [[package]] name = "untrusted" version = "0.9.0" @@ -10712,7 +9914,7 @@ version = "2.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b52731d03d6bb2fd18289d4028aee361d6c28d44977846793b994b13cdcc64d" dependencies = [ - "base64 0.21.7", + "base64", "hootbin", "log", "native-tls", @@ -10867,50 +10069,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "warp" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1e92e22e03ff1230c03a1a8ee37d2f89cd489e2e541b7550d6afad96faed169" -dependencies = [ - "async-compression 0.3.15", - "bytes", - "futures-channel", - "futures-util", - "headers 0.3.9", - "http 0.2.11", - "hyper 0.14.28", - "log", - "mime", - "mime_guess", - "multer 2.1.0", - "percent-encoding", - "pin-project", - "rustls-pemfile", - "scoped-tls", - "serde", - "serde_json", - "serde_urlencoded", - "tokio", - "tokio-stream", - "tokio-tungstenite 0.20.1", - "tokio-util", - "tower-service", - "tracing", -] - -[[package]] -name = "warp-hello-world" -version = "0.1.0" -dependencies = [ - "dioxus", - "reqwest", - "serde", - "tracing", - "tracing-subscriber", - "tracing-wasm", -] - [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -10944,7 +10102,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", "wasm-bindgen-shared", ] @@ -10955,7 +10113,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "806a045c4ec4ef7c3ad86dc27bcb641b84d9eeb3846200f56d7ab0885241d654" dependencies = [ "anyhow", - "base64 0.21.7", + "base64", "log", "rustc-demangle", "serde_json", @@ -11010,7 +10168,7 @@ checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -11053,7 +10211,7 @@ checksum = "a5211b7550606857312bba1d978a8ec75692eae187becc5e680444fffc5e6f89" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -11138,16 +10296,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "web-time" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ee269d72cc29bf77a2c4bc689cc750fb39f5cbd493d2205bbb3f5c7779cf7b0" -dependencies = [ - "js-sys", - "wasm-bindgen", -] - [[package]] name = "webbrowser" version = "0.8.12" @@ -11218,16 +10366,6 @@ dependencies = [ "libwebp-sys", ] -[[package]] -name = "webpki" -version = "0.22.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed63aea5ce73d0ff405984102c42de94fc55a6b75765d621c65262469b3c9b53" -dependencies = [ - "ring 0.17.7", - "untrusted 0.9.0", -] - [[package]] name = "webpki-roots" version = "0.25.4" @@ -11251,7 +10389,7 @@ checksum = "e0ae9c7e420783826cf769d2c06ac9ba462f450eca5893bb8c6c6529a4e5dd33" dependencies = [ "webview2-com-macros", "webview2-com-sys", - "windows 0.52.0", + "windows", "windows-core", "windows-implement", "windows-interface", @@ -11265,7 +10403,7 @@ checksum = "ac1345798ecd8122468840bcdf1b95e5dc6d2206c5e4b0eafa078d061f59c9bc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -11275,7 +10413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6ad85fceee6c42fa3d61239eba5a11401bf38407a849ed5ea1b407df08cca72" dependencies = [ "thiserror", - "windows 0.52.0", + "windows", "windows-core", ] @@ -11340,15 +10478,6 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" -[[package]] -name = "windows" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" -dependencies = [ - "windows-targets 0.48.5", -] - [[package]] name = "windows" version = "0.52.0" @@ -11378,7 +10507,7 @@ checksum = "12168c33176773b86799be25e2a2ba07c7aab9968b37541f1094dbd7a60c8946" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -11389,7 +10518,7 @@ checksum = "9d8dc32e0095a7eeccebd0e3f09e9509365ecb3fc6ac4d6f5f14a3f6392942d1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] @@ -11601,9 +10730,18 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" [[package]] name = "winnow" -version = "0.5.39" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5389a154b01683d28c77f8f68f49dea75f0a4da32557a58f68ee51ebba472d29" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d90f4e0f530c4c69f62b80d839e9ef3855edc9cba471a160c4d692deed62b401" dependencies = [ "memchr", ] @@ -11624,7 +10762,7 @@ version = "0.35.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3016c47c9b6f7029a9da7cd48af8352327226bba0e955f3c92e2966651365a9" dependencies = [ - "base64 0.21.7", + "base64", "block", "cfg_aliases", "cocoa", @@ -11657,7 +10795,7 @@ dependencies = [ "webkit2gtk", "webkit2gtk-sys", "webview2-com", - "windows 0.52.0", + "windows", "windows-implement", "windows-version", "x11-dl", @@ -11714,12 +10852,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "xml-rs" -version = "0.8.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fcb9cbac069e033553e8bb871be2fbdffcab578eb25bd0f7c508cedc6dcd75a" - [[package]] name = "xxhash-rust" version = "0.8.8" @@ -11732,15 +10864,6 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" -[[package]] -name = "yansi" -version = "1.0.0-rc.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1367295b8f788d371ce2dbc842c7b709c73ee1364d30351dd300ec2203b12377" -dependencies = [ - "is-terminal", -] - [[package]] name = "zbus" version = "3.15.0" @@ -11824,7 +10947,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.49", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 748eb89a8..9ac28a43c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,8 +37,6 @@ members = [ "packages/fullstack/examples/axum-router", "packages/fullstack/examples/axum-desktop", "packages/fullstack/examples/axum-auth", - "packages/fullstack/examples/salvo-hello-world", - "packages/fullstack/examples/warp-hello-world", "packages/fullstack/examples/static-hydrated", # Full project examples "examples/tailwind", @@ -88,6 +86,7 @@ dioxus-fullstack = { path = "packages/fullstack", version = "0.4.1" } dioxus_server_macro = { path = "packages/server-macro", version = "0.4.1" } tracing = "0.1.37" tracing-futures = "0.2.5" +toml = "0.8" tokio = "1.28" slab = "0.4.2" futures-channel = "0.3.21" @@ -105,6 +104,17 @@ manganis-cli-support = { git = "https://github.com/DioxusLabs/collect-assets", r ] } manganis = { git = "https://github.com/DioxusLabs/collect-assets", rev = "f982698" } +lru = "0.12.2" +async-trait = "0.1.77" +axum = "0.7.0" +tower = "0.4.13" +http = "1.0.0" +tower-http = "0.5.1" +hyper = "1.0.0" +hyper-rustls = "0.26.0" +serde_json = "1.0.61" +serde = "1.0.61" + # This is a "virtual package" # It is not meant to be published, but is used so "cargo run --example XYZ" works properly [package] @@ -125,7 +135,6 @@ publish = false manganis = { workspace = true, optional = true} reqwest = { version = "0.11.9", features = ["json"], optional = true} http-range = {version = "0.1.5", optional = true } -warp = { version = "0.3.0", optional = true } [dev-dependencies] dioxus = { workspace = true, features = ["router"] } @@ -149,13 +158,11 @@ tokio = { version = "1.16.1", features = ["full"] } liveview = ["dioxus/liveview"] fullstack = ["dioxus/fullstack"] axum = ["dioxus/axum"] -salvo = ["dioxus/salvo"] -rocket = ["dioxus/rocket"] server = ["dioxus/axum"] default = ["dioxus/desktop"] web = ["dioxus/web"] collect-assets = ["manganis"] -http = ["reqwest", "http-range", "warp"] +http = ["reqwest", "http-range"] [[example]] name = "login_form" diff --git a/packages/cli-config/Cargo.toml b/packages/cli-config/Cargo.toml index 2bcbea1f1..0d93c5ebe 100644 --- a/packages/cli-config/Cargo.toml +++ b/packages/cli-config/Cargo.toml @@ -12,7 +12,7 @@ keywords = ["react", "gui", "cli", "dioxus", "wasm"] clap = { version = "4.2", features = ["derive"], optional = true } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" -toml = { version = "0.5.8", optional = true } +toml = { workspace = true, optional = true } cargo_toml = { version = "0.16.0", optional = true } once_cell = "1.18.0" tracing = { workspace = true } diff --git a/packages/cli/Cargo.toml b/packages/cli/Cargo.toml index 657c70e0f..eaa4c7c8f 100644 --- a/packages/cli/Cargo.toml +++ b/packages/cli/Cargo.toml @@ -21,7 +21,7 @@ log = "0.4.14" fern = { version = "0.6.0", features = ["colored"] } serde = { version = "1.0.136", features = ["derive"] } serde_json = "1.0.79" -toml = "0.8.8" +toml = {workspace = true} fs_extra = "1.2.0" cargo_toml = "0.18.0" futures-util = { workspace = true } @@ -32,17 +32,17 @@ tokio = { version = "1.16.1", features = ["fs", "sync", "rt", "macros"] } atty = "0.2.14" chrono = "0.4.19" anyhow = "1" -hyper = "0.14.17" -hyper-rustls = "0.23.2" +hyper = {workspace = true} +hyper-rustls = {workspace = true} indicatif = "0.17.5" subprocess = "0.2.9" rayon = "1.8.0" -axum = { version = "0.5.1", features = ["ws", "headers"] } +axum = { workspace = true, features = ["ws"] } axum-server = { version = "0.5.1", features = ["tls-rustls"] } -tower-http = { version = "0.2.2", features = ["full"] } -headers = "0.3.7" +tower-http = { workspace = true, features = ["full"] } +headers = "0.3.7" walkdir = "2" # tools download @@ -56,7 +56,7 @@ reqwest = { version = "0.11", features = [ flate2 = "1.0.22" tar = "0.4.38" zip = "0.6.2" -tower = "0.4.12" +tower = { workspace = true } lazy_static = "1.4.0" # plugin packages diff --git a/packages/cli/src/main.rs b/packages/cli/src/main.rs index dae2deb2c..d4326a696 100644 --- a/packages/cli/src/main.rs +++ b/packages/cli/src/main.rs @@ -5,9 +5,6 @@ use anyhow::Context; use clap::Parser; use dioxus_cli::*; -#[cfg(feature = "plugin")] -use dioxus_cli::plugin::PluginManager; - use Commands::*; fn get_bin(bin: Option) -> Result { @@ -92,6 +89,9 @@ async fn main() -> anyhow::Result<()> { DioxusConfig::default() }); + #[cfg(feature = "plugin")] + use dioxus_cli::plugin::PluginManager; + #[cfg(feature = "plugin")] PluginManager::init(_dioxus_config.plugin) .context(error_wrapper("Plugin system initialization failed"))?; diff --git a/packages/cli/src/server/web/mod.rs b/packages/cli/src/server/web/mod.rs index 582b81129..6ae873d1f 100644 --- a/packages/cli/src/server/web/mod.rs +++ b/packages/cli/src/server/web/mod.rs @@ -8,8 +8,8 @@ use crate::{ BuildResult, Result, }; use axum::{ - body::{Full, HttpBody}, - extract::{ws::Message, Extension, TypedHeader, WebSocketUpgrade}, + body::{Body, HttpBody}, + extract::{ws::Message, Extension, WebSocketUpgrade}, http::{ self, header::{HeaderName, HeaderValue}, @@ -287,20 +287,18 @@ async fn setup_router( let mut response = if file_service_config.dioxus_config.web.watcher.index_on_404 && response.status() == StatusCode::NOT_FOUND { - let body = Full::from( + let body = Body::from( // TODO: Cache/memoize this. std::fs::read_to_string(file_service_config.out_dir().join("index.html")) .ok() .unwrap(), - ) - .map_err(|err| match err {}) - .boxed(); + ); Response::builder() .status(StatusCode::OK) .body(body) .unwrap() } else { - response.map(|body| body.boxed()) + response.map(|body| body.into()) }; let headers = response.headers_mut(); headers.insert( diff --git a/packages/cli/src/server/web/proxy.rs b/packages/cli/src/server/web/proxy.rs index 4242a55eb..d5e4a4eeb 100644 --- a/packages/cli/src/server/web/proxy.rs +++ b/packages/cli/src/server/web/proxy.rs @@ -5,6 +5,8 @@ use anyhow::Context; use axum::{http::StatusCode, routing::any, Router}; use hyper::{Request, Response, Uri}; +use axum::body::Body as MyBody; + #[derive(Debug, Clone)] struct ProxyClient { inner: hyper::Client>, @@ -24,10 +26,7 @@ impl ProxyClient { } } - async fn send( - &self, - mut req: Request, - ) -> Result> { + async fn send(&self, mut req: Request) -> Result> { let mut uri_parts = req.uri().clone().into_parts(); uri_parts.authority = self.url.authority().cloned(); uri_parts.scheme = self.url.scheme().cloned(); diff --git a/packages/dioxus/Cargo.toml b/packages/dioxus/Cargo.toml index 352a258d5..90fb7ea79 100644 --- a/packages/dioxus/Cargo.toml +++ b/packages/dioxus/Cargo.toml @@ -50,16 +50,10 @@ web = ["dioxus-web", "dioxus-fullstack?/web", "dioxus-config-macro/web", "dioxus ssr = ["dioxus-ssr", "dioxus-router?/ssr", "dioxus-config-macro/ssr"] liveview = ["dioxus-liveview", "dioxus-config-macro/liveview", "dioxus-router?/liveview"] axum = ["dioxus-fullstack?/axum", "ssr", "dioxus-liveview?/axum"] -salvo = ["dioxus-fullstack?/salvo", "ssr", "dioxus-liveview?/salvo"] -warp = ["dioxus-fullstack?/warp", "ssr", "dioxus-liveview?/warp"] -rocket = ["dioxus-liveview?/rocket"] tui = ["dioxus-tui", "dioxus-config-macro/tui"] # This feature just disables the no-renderer-enabled warning third-party-renderer = [] -# This feature enables some nightly flags that make it more clear what structs/methods are available in each feature -nightly-doc = [] - [dev-dependencies] futures-util = { workspace = true } tracing = { workspace = true } diff --git a/packages/dioxus/build.rs b/packages/dioxus/build.rs index e9687a09f..15315eeb9 100644 --- a/packages/dioxus/build.rs +++ b/packages/dioxus/build.rs @@ -5,8 +5,8 @@ fn main() { return; } - let liveview_renderers = ["liveview", "axum", "salvo", "warp", "rocket"]; - let fullstack_renderers = ["axum", "salvo", "warp"]; + let liveview_renderers = ["liveview", "axum"]; + let fullstack_renderers = ["axum"]; let client_renderers = ["desktop", "mobile", "web", "tui"]; let client_renderer_selected = client_renderers .iter() diff --git a/packages/dioxus/src/launch.rs b/packages/dioxus/src/launch.rs index f62377341..e58e3ecb5 100644 --- a/packages/dioxus/src/launch.rs +++ b/packages/dioxus/src/launch.rs @@ -38,7 +38,7 @@ impl LaunchBuilder { /// Launch your web application. #[cfg(feature = "web")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "web")))] + #[cfg_attr(docsrs, doc(cfg(feature = "web")))] pub fn web() -> LaunchBuilder { LaunchBuilder { launch_fn: dioxus_web::launch::launch, @@ -49,7 +49,7 @@ impl LaunchBuilder { /// Launch your desktop application. #[cfg(feature = "desktop")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "desktop")))] + #[cfg_attr(docsrs, doc(cfg(feature = "desktop")))] pub fn desktop() -> LaunchBuilder { LaunchBuilder { launch_fn: dioxus_desktop::launch::launch, @@ -60,7 +60,7 @@ impl LaunchBuilder { /// Launch your fullstack application. #[cfg(feature = "fullstack")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "fullstack")))] + #[cfg_attr(docsrs, doc(cfg(feature = "fullstack")))] pub fn fullstack() -> LaunchBuilder { LaunchBuilder { launch_fn: dioxus_fullstack::launch::launch, @@ -71,7 +71,7 @@ impl LaunchBuilder { /// Launch your fullstack application. #[cfg(feature = "mobile")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "mobile")))] + #[cfg_attr(docsrs, doc(cfg(feature = "mobile")))] pub fn mobile() -> LaunchBuilder { LaunchBuilder { launch_fn: dioxus_mobile::launch::launch, @@ -81,7 +81,7 @@ impl LaunchBuilder { } #[cfg(feature = "tui")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "tui")))] + #[cfg_attr(docsrs, doc(cfg(feature = "tui")))] /// Launch your tui application pub fn tui() -> LaunchBuilder { LaunchBuilder { @@ -232,28 +232,28 @@ pub fn launch(app: fn() -> Element) { } #[cfg(feature = "web")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "web")))] +#[cfg_attr(docsrs, doc(cfg(feature = "web")))] /// Launch your web application without any additional configuration. See [`LaunchBuilder`] for more options. pub fn launch_web(app: fn() -> Element) { LaunchBuilder::web().launch(app) } #[cfg(feature = "desktop")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "desktop")))] +#[cfg_attr(docsrs, doc(cfg(feature = "desktop")))] /// Launch your desktop application without any additional configuration. See [`LaunchBuilder`] for more options. pub fn launch_desktop(app: fn() -> Element) { LaunchBuilder::desktop().launch(app) } #[cfg(feature = "fullstack")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "fullstack")))] +#[cfg_attr(docsrs, doc(cfg(feature = "fullstack")))] /// Launch your fullstack application without any additional configuration. See [`LaunchBuilder`] for more options. pub fn launch_fullstack(app: fn() -> Element) { LaunchBuilder::fullstack().launch(app) } #[cfg(feature = "tui")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "tui")))] +#[cfg_attr(docsrs, doc(cfg(feature = "tui")))] /// Launch your tui application without any additional configuration. See [`LaunchBuilder`] for more options. pub fn launch_tui(app: fn() -> Element) { LaunchBuilder::tui().launch(app) diff --git a/packages/dioxus/src/lib.rs b/packages/dioxus/src/lib.rs index d843cfd56..bd2e8f70b 100644 --- a/packages/dioxus/src/lib.rs +++ b/packages/dioxus/src/lib.rs @@ -1,114 +1,115 @@ #![doc = include_str!("../README.md")] #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")] #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")] -#![cfg_attr(any(docsrs, feature = "nightly-doc"), feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] pub use dioxus_core; #[cfg(feature = "launch")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "launch")))] +#[cfg_attr(docsrs, doc(cfg(feature = "launch")))] mod launch; #[cfg(feature = "hooks")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "hooks")))] +#[cfg_attr(docsrs, doc(cfg(feature = "hooks")))] pub use dioxus_hooks as hooks; #[cfg(feature = "signals")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "signals")))] +#[cfg_attr(docsrs, doc(cfg(feature = "signals")))] pub use dioxus_signals as signals; pub mod events { #[cfg(feature = "html")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "html")))] + #[cfg_attr(docsrs, doc(cfg(feature = "html")))] pub use dioxus_html::prelude::*; } #[cfg(feature = "html")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "html")))] +#[cfg_attr(docsrs, doc(cfg(feature = "html")))] pub use dioxus_html as html; #[cfg(feature = "macro")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "macro")))] +#[cfg_attr(docsrs, doc(cfg(feature = "macro")))] pub use dioxus_core_macro as core_macro; pub mod prelude { #[cfg(feature = "launch")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "launch")))] + #[cfg_attr(docsrs, doc(cfg(feature = "launch")))] pub use crate::launch::*; #[cfg(feature = "hooks")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "hooks")))] + #[cfg_attr(docsrs, doc(cfg(feature = "hooks")))] pub use crate::hooks::*; #[cfg(feature = "signals")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "signals")))] + #[cfg_attr(docsrs, doc(cfg(feature = "signals")))] pub use dioxus_signals::*; pub use dioxus_core::prelude::*; #[cfg(feature = "macro")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "macro")))] + #[cfg_attr(docsrs, doc(cfg(feature = "macro")))] #[allow(deprecated)] pub use dioxus_core_macro::{component, format_args_f, inline_props, render, rsx, Props}; #[cfg(feature = "launch")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "launch")))] + #[cfg_attr(docsrs, doc(cfg(feature = "launch")))] pub use dioxus_config_macro::*; #[cfg(feature = "html")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "html")))] + #[cfg_attr(docsrs, doc(cfg(feature = "html")))] pub use dioxus_html as dioxus_elements; #[cfg(feature = "html")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "html")))] + #[cfg_attr(docsrs, doc(cfg(feature = "html")))] pub use dioxus_elements::{prelude::*, GlobalAttributes, SvgAttributes}; #[cfg(all(not(target_arch = "wasm32"), feature = "hot-reload"))] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "hot-reload")))] + #[cfg_attr(docsrs, doc(cfg(feature = "hot-reload")))] pub use dioxus_hot_reload::{self, hot_reload_init}; pub use dioxus_core; #[cfg(feature = "fullstack")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "fullstack")))] + #[cfg_attr(docsrs, doc(cfg(feature = "fullstack")))] pub use dioxus_fullstack::prelude::*; #[cfg(feature = "router")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "router")))] + #[cfg_attr(docsrs, doc(cfg(feature = "router")))] pub use dioxus_router; + #[cfg(feature = "router")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "router")))] + #[cfg_attr(docsrs, doc(cfg(feature = "router")))] pub use dioxus_router::prelude::*; } #[cfg(feature = "web")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "web")))] +#[cfg_attr(docsrs, doc(cfg(feature = "web")))] pub use dioxus_web as web; #[cfg(feature = "router")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "router")))] +#[cfg_attr(docsrs, doc(cfg(feature = "router")))] pub use dioxus_router as router; #[cfg(feature = "fullstack")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "fullstack")))] +#[cfg_attr(docsrs, doc(cfg(feature = "fullstack")))] pub use dioxus_fullstack as fullstack; #[cfg(feature = "desktop")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "desktop")))] +#[cfg_attr(docsrs, doc(cfg(feature = "desktop")))] pub use dioxus_desktop as desktop; #[cfg(feature = "mobile")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "mobile")))] +#[cfg_attr(docsrs, doc(cfg(feature = "mobile")))] pub use dioxus_desktop as mobile; #[cfg(feature = "liveview")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "liveview")))] +#[cfg_attr(docsrs, doc(cfg(feature = "liveview")))] pub use dioxus_liveview as liveview; #[cfg(feature = "tui")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "tui")))] +#[cfg_attr(docsrs, doc(cfg(feature = "tui")))] pub use dioxus_tui as tui; #[cfg(feature = "ssr")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "ssr")))] +#[cfg_attr(docsrs, doc(cfg(feature = "ssr")))] pub use dioxus_ssr as ssr; diff --git a/packages/fullstack/Cargo.toml b/packages/fullstack/Cargo.toml index 63fde221c..861457351 100644 --- a/packages/fullstack/Cargo.toml +++ b/packages/fullstack/Cargo.toml @@ -15,23 +15,17 @@ resolver = "2" server_fn = { version = "0.5.2", default-features = false } dioxus_server_macro = { workspace = true } -# warp -warp = { version = "0.3.5", features = ["compression-gzip"], optional = true } # axum -axum = { version = "0.6.1", features = ["ws", "macros"], default-features = false, optional = true } -tower-http = { version = "0.4.0", optional = true, features = ["fs", "compression-gzip"] } - -# salvo -salvo = { version = "0.63.0", optional = true, features = ["serve-static", "websocket", "compression"] } -http-body-util = { version = "0.1.0-rc.2", optional = true } +axum = { workspace = true, features = ["ws", "macros"], default-features = false, optional = true } +tower-http = { workspace = true, optional = true, features = ["fs", "compression-gzip"] } dioxus-lib = { workspace = true } # Dioxus + SSR dioxus-ssr = { workspace = true, optional = true } -hyper = { version = "0.14.25", optional = true } -http = { version = "0.2.9", optional = true } +hyper = { workspace = true, optional = true } +http = { workspace = true, optional = true } # Web Integration dioxus-web = { workspace = true, features = ["hydrate"], optional = true } @@ -60,7 +54,7 @@ pin-project = { version = "1.1.2", optional = true } thiserror = { workspace = true, optional = true } async-trait = "0.1.71" bytes = "1.4.0" -tower = { version = "0.4.13", features = ["util"], optional = true } +tower = { workspace = true, features = ["util"], optional = true } tower-layer = { version = "0.3.2", optional = true } web-sys = { version = "0.3.61", optional = true, features = ["Window", "Document", "Element", "HtmlDocument", "Storage", "console"] } @@ -75,11 +69,7 @@ hot-reload = ["serde_json", "futures-util"] web = ["dioxus-web", "web-sys"] desktop = ["dioxus-desktop"] mobile = ["dioxus-mobile"] -warp = ["dep:warp", "server"] axum = ["dep:axum", "tower-http", "server"] -salvo = ["dep:salvo", "server", "http-body-util"] server = ["server_fn/ssr", "dioxus_server_macro/server", "tokio", "tokio-util", "tokio-stream", "dioxus-ssr", "dioxus-ssr/incremental", "tower", "hyper", "http", "tower-layer", "anymap", "tracing-futures", "pin-project", "thiserror", "dioxus-cli-config"] default-tls = ["server_fn/default-tls"] rustls = ["server_fn/rustls"] -# This feature enables some nightly flags that make it more clear what structs/methods are available in each feature -nightly-doc = [] diff --git a/packages/fullstack/README.md b/packages/fullstack/README.md index 55f0fd492..3b1b38d5f 100644 --- a/packages/fullstack/README.md +++ b/packages/fullstack/README.md @@ -37,51 +37,43 @@ Full stack Dioxus in under 50 lines of code use dioxus::prelude::*; use dioxus_fullstack::prelude::*; +// On the web, run our client code +#[cfg(feature = "web")] fn main() { - #[cfg(feature = "web")] dioxus_web::launch_with_props( app, get_root_props_from_document().unwrap_or_default(), dioxus_web::Config::new().hydrate(true), ); - #[cfg(feature = "server")] - { - tokio::runtime::Runtime::new() - .unwrap() - .block_on(async move { - warp::serve( - // Automatically handles server side rendering, hot reloading intigration, and hosting server functions - serve_dioxus_application( - "", - ServerConfig::new(app, ()), - ) - ) - .run(([127, 0, 0, 1], 8080)) - .await; - }); - } +} + +// On the server, run a simple warp server +#[cfg(feature = "server")] +#[tokio::main] +async fn main() { + // Automatically handles server side rendering, hot reloading intigration, and hosting server functions + warp::serve(serve_dioxus_application("", ServerConfig::new(app, ()))) + .run(([127, 0, 0, 1], 8080)) + .await; } fn app() -> Element { let meaning = use_signal(|| None); + rsx! { + h1 { "Meaning of life: {meaning:?}" } button { - onclick: move |_| { - to_owned![meaning]; - async move { - if let Ok(data) = get_meaning("life the universe and everything".into()).await { - meaning.set(data); - } + onclick: move |_| async move { + if let Ok(data) = get_meaning("life the universe and everything".into()).await { + meaning.set(data); } }, "Run a server function" } - "Server said: {meaning:?}" - }) + } } -// This code will only run on the server -#[server(GetMeaning)] +#[server] async fn get_meaning(of: String) -> Result, ServerFnError> { Ok(of.contains("life").then(|| 42)) } diff --git a/packages/fullstack/examples/axum-auth/Cargo.toml b/packages/fullstack/examples/axum-auth/Cargo.toml index 2a3efa267..90148f083 100644 --- a/packages/fullstack/examples/axum-auth/Cargo.toml +++ b/packages/fullstack/examples/axum-auth/Cargo.toml @@ -8,13 +8,11 @@ publish = false [dependencies] dioxus-web = { workspace = true, features = ["hydrate"], optional = true } -dioxus = { workspace = true } +dioxus = { features = ["fullstack"], workspace = true } dioxus-fullstack = { workspace = true } -axum = { version = "0.6.12", optional = true } +axum = { workspace = true, optional = true } tokio = { workspace = true, features = ["full"], optional = true } -serde = "1.0.159" -execute = "0.2.12" -tower-http = { version = "0.4.1", features = ["auth"], optional = true } +tower-http = { workspace = true, features = ["auth"], optional = true } simple_logger = { version = "4.2.0", optional = true } async-trait = { version = "0.1.71", optional = true } sqlx = { version = "0.7.0", features = [ @@ -26,9 +24,12 @@ sqlx = { version = "0.7.0", features = [ "tls-rustls", "runtime-tokio", ], optional = true } +http = { workspace = true, optional = true } +tower = { workspace = true, optional = true } + +serde = "1.0.159" +execute = "0.2.12" anyhow = "1.0.71" -http = { version = "0.2.9", optional = true } -tower = { version = "0.4.13", optional = true } [dependencies.axum_session] version = "0.3.0" @@ -36,7 +37,7 @@ features = ["sqlite-rustls"] optional = true [dependencies.axum_session_auth] -version = "0.3.0" +version = "0.12.0" features = ["sqlite-rustls"] optional = true diff --git a/packages/fullstack/examples/axum-auth/src/main.rs b/packages/fullstack/examples/axum-auth/src/main.rs index 6d9084b7c..b7eb2364a 100644 --- a/packages/fullstack/examples/axum-auth/src/main.rs +++ b/packages/fullstack/examples/axum-auth/src/main.rs @@ -17,7 +17,7 @@ use serde::{Deserialize, Serialize}; fn main() { #[cfg(feature = "web")] // Hydrate the application on the client - dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); + dioxus_web::launch::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); #[cfg(feature = "server")] { @@ -51,7 +51,9 @@ fn main() { // build our application with some routes let app = Router::new() // Server side render the application, serve static assets, and register server functions - .serve_dioxus_application("", ServerConfig::new(app, ())) + .serve_dioxus_application("", ServeConfig::builder().build(), || { + VirtualDom::new(app) + }) .layer( axum_session_auth::AuthSessionLayer::< crate::auth::User, diff --git a/packages/fullstack/examples/axum-desktop/Cargo.toml b/packages/fullstack/examples/axum-desktop/Cargo.toml index fe16f2419..d789b48e5 100644 --- a/packages/fullstack/examples/axum-desktop/Cargo.toml +++ b/packages/fullstack/examples/axum-desktop/Cargo.toml @@ -7,8 +7,8 @@ publish = false [lib] [dependencies] -dioxus = { workspace = true } -axum = { version = "0.6.12", optional = true } +dioxus = { workspace = true, features = ["launch"] } +axum = { workspace = true, optional = true } tokio = { workspace = true, features = ["full"], optional = true } serde = "1.0.159" diff --git a/packages/fullstack/examples/axum-desktop/src/client.rs b/packages/fullstack/examples/axum-desktop/src/client.rs index 247f2e8f2..b9a2e0463 100644 --- a/packages/fullstack/examples/axum-desktop/src/client.rs +++ b/packages/fullstack/examples/axum-desktop/src/client.rs @@ -9,5 +9,7 @@ fn main() { // Set the url of the server where server functions are hosted. #[cfg(not(feature = "server"))] dioxus::fullstack::prelude::server_fn::set_server_url("http://127.0.0.1:8080"); - dioxus::desktop::launch(app) + + #[cfg(feature = "desktop")] + dioxus::prelude::launch_desktop(app) } diff --git a/packages/fullstack/examples/axum-router/Cargo.toml b/packages/fullstack/examples/axum-router/Cargo.toml index 3e020b764..dfac4be56 100644 --- a/packages/fullstack/examples/axum-router/Cargo.toml +++ b/packages/fullstack/examples/axum-router/Cargo.toml @@ -8,7 +8,7 @@ publish = false [dependencies] dioxus = { workspace = true, features = ["router"] } -axum = { version = "0.6.12", optional = true } +axum = { workspace = true, optional = true } tokio = {workspace = true, features = ["full"], optional = true } serde = { version = "1.0.159", features = ["derive"] } diff --git a/packages/fullstack/examples/salvo-hello-world/.gitignore b/packages/fullstack/examples/salvo-hello-world/.gitignore deleted file mode 100644 index 21fff11dd..000000000 --- a/packages/fullstack/examples/salvo-hello-world/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -dist -target -static -.dioxus \ No newline at end of file diff --git a/packages/fullstack/examples/salvo-hello-world/Cargo.toml b/packages/fullstack/examples/salvo-hello-world/Cargo.toml deleted file mode 100644 index 87c82bb4e..000000000 --- a/packages/fullstack/examples/salvo-hello-world/Cargo.toml +++ /dev/null @@ -1,25 +0,0 @@ -[package] -name = "salvo-hello-world" -version = "0.1.0" -edition = "2021" -publish = false - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -dioxus-web = { workspace = true, features=["hydrate"], optional = true } -dioxus = { workspace = true } -dioxus-fullstack = { workspace = true } -serde = "1.0.159" -salvo = { version = "0.63.0", optional = true } -execute = "0.2.12" -reqwest = "0.11.18" -simple_logger = "4.2.0" -tracing-wasm = "0.2.1" -tracing = { workspace = true } -tracing-subscriber = "0.3.17" - -[features] -default = [] -server = ["salvo", "dioxus-fullstack/salvo"] -web = ["dioxus-web"] diff --git a/packages/fullstack/examples/salvo-hello-world/src/main.rs b/packages/fullstack/examples/salvo-hello-world/src/main.rs deleted file mode 100644 index 4870e951a..000000000 --- a/packages/fullstack/examples/salvo-hello-world/src/main.rs +++ /dev/null @@ -1,57 +0,0 @@ -//! Run with: -//! -//! ```sh -//! dx serve --platform fullstack -//! ``` - -#![allow(non_snake_case, unused)] -use dioxus::prelude::*; -use dioxus_fullstack::{launch, prelude::*}; -use serde::{Deserialize, Serialize}; - -fn app() -> Element { - let state = use_server_future(move || async move { get_server_data().await.unwrap() })?; - - let mut count = use_signal(|| 0); - let mut text = use_signal(|| "...".to_string()); - - rsx! { - div { "Server state: {state.value().unwrap()}" } - h1 { "High-Five counter: {count}" } - button { onclick: move |_| count += 1, "Up high!" } - button { onclick: move |_| count -= 1, "Down low!" } - button { - onclick: move |_| async move { - if let Ok(data) = get_server_data().await { - println!("Client received: {}", data); - text.set(data.clone()); - post_server_data(data).await.unwrap(); - } - }, - "Run a server function!" - } - "Server said: {text}" - } -} - -#[server(PostServerData)] -async fn post_server_data(data: String) -> Result<(), ServerFnError> { - println!("Server received: {}", data); - - Ok(()) -} - -#[server(GetServerData)] -async fn get_server_data() -> Result { - Ok(reqwest::get("https://httpbin.org/ip").await?.text().await?) -} - -fn main() { - #[cfg(feature = "web")] - tracing_wasm::set_as_global_default(); - - #[cfg(feature = "server")] - tracing_subscriber::fmt::init(); - - LaunchBuilder::fullstack().launch(app); -} diff --git a/packages/fullstack/examples/warp-hello-world/.gitignore b/packages/fullstack/examples/warp-hello-world/.gitignore deleted file mode 100644 index 21fff11dd..000000000 --- a/packages/fullstack/examples/warp-hello-world/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -dist -target -static -.dioxus \ No newline at end of file diff --git a/packages/fullstack/examples/warp-hello-world/Cargo.toml b/packages/fullstack/examples/warp-hello-world/Cargo.toml deleted file mode 100644 index df7ac9d96..000000000 --- a/packages/fullstack/examples/warp-hello-world/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -name = "warp-hello-world" -version = "0.1.0" -edition = "2021" -publish = false - -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -dioxus = { workspace = true, features = ["fullstack"] } -serde = "1.0.159" -tracing-wasm = "0.2.1" -tracing = { workspace = true } -tracing-subscriber = "0.3.17" -reqwest = "0.11.18" - -[features] -default = [] -server = ["dioxus/warp"] -web = ["dioxus/web"] diff --git a/packages/fullstack/examples/warp-hello-world/src/main.rs b/packages/fullstack/examples/warp-hello-world/src/main.rs deleted file mode 100644 index f424e15c3..000000000 --- a/packages/fullstack/examples/warp-hello-world/src/main.rs +++ /dev/null @@ -1,54 +0,0 @@ -//! Run with: -//! -//! ```sh -//! dx serve --platform fullstack -//! ``` - -#![allow(non_snake_case, unused)] -use dioxus::prelude::*; - -fn app() -> Element { - let mut count = use_signal(|| 0); - let text = use_signal(|| "...".to_string()); - - rsx! { - h1 { "High-Five counter: {count}" } - button { onclick: move |_| count += 1, "Up high!" } - button { onclick: move |_| count -= 1, "Down low!" } - button { - onclick: move |_| { - to_owned![text]; - async move { - if let Ok(data) = get_server_data().await { - println!("Client received: {}", data); - text.set(data.clone()); - post_server_data(data).await.unwrap(); - } - } - }, - "Run a server function!" - } - "Server said: {text}" - } -} - -#[server] -async fn post_server_data(data: String) -> Result<(), ServerFnError> { - println!("Server received: {}", data); - - Ok(()) -} - -#[server] -async fn get_server_data() -> Result { - Ok(reqwest::get("https://httpbin.org/ip").await?.text().await?) -} - -fn main() { - #[cfg(feature = "web")] - tracing_wasm::set_as_global_default(); - #[cfg(feature = "server")] - tracing_subscriber::fmt::init(); - - launch(app); -} diff --git a/packages/fullstack/src/adapters/axum_adapter.rs b/packages/fullstack/src/adapters/axum_adapter.rs index d73edeb88..e12590bed 100644 --- a/packages/fullstack/src/adapters/axum_adapter.rs +++ b/packages/fullstack/src/adapters/axum_adapter.rs @@ -55,7 +55,7 @@ //! ``` use axum::{ - body::{self, Body, BoxBody}, + body::{self, Body}, extract::State, handler::Handler, http::{Request, Response, StatusCode}, @@ -234,7 +234,7 @@ where mut handler: impl FnMut(server_fn::ServerFnTraitObj<()>) -> H, ) -> Self where - H: Handler, + H: Handler, T: 'static, S: Clone + Send + Sync + 'static, { @@ -468,10 +468,10 @@ pub async fn render_handler( .await } -fn report_err(e: E) -> Response { +fn report_err(e: E) -> Response { Response::builder() .status(StatusCode::INTERNAL_SERVER_ERROR) - .body(body::boxed(format!("Error: {}", e))) + .body(body::Body::new(format!("Error: {}", e))) .unwrap() } diff --git a/packages/fullstack/src/adapters/mod.rs b/packages/fullstack/src/adapters/mod.rs index 61f24bf3c..3e8c9321f 100644 --- a/packages/fullstack/src/adapters/mod.rs +++ b/packages/fullstack/src/adapters/mod.rs @@ -12,15 +12,13 @@ #[cfg(feature = "axum")] pub mod axum_adapter; -// #[cfg(feature = "salvo")] -// pub mod salvo_adapter; -#[cfg(feature = "warp")] -pub mod warp_adapter; use http::StatusCode; use server_fn::{Encoding, Payload}; use std::sync::{Arc, RwLock}; +type MyBody = axum::body::Body; + use crate::{ layer::{BoxedService, Service}, prelude::{DioxusServerContext, ProvideServerContext}, @@ -68,11 +66,11 @@ impl ServerFnHandler { impl Service for ServerFnHandler { fn run( &mut self, - req: http::Request, + req: http::Request, ) -> std::pin::Pin< Box< dyn std::future::Future< - Output = Result, server_fn::ServerFnError>, + Output = Result, server_fn::ServerFnError>, > + Send, >, > { @@ -83,7 +81,7 @@ impl Service for ServerFnHandler { Box::pin(async move { let query = req.uri().query().unwrap_or_default().as_bytes().to_vec(); let (parts, body) = req.into_parts(); - let body = hyper::body::to_bytes(body).await?.to_vec(); + let body = axum::body::to_bytes(body, usize::MAX).await?.to_vec(); let headers = &parts.headers; let accept_header = headers.get("Accept").cloned(); let parts = Arc::new(RwLock::new(parts)); diff --git a/packages/fullstack/src/adapters/salvo_adapter.rs b/packages/fullstack/src/adapters/salvo_adapter.rs deleted file mode 100644 index a30097c9a..000000000 --- a/packages/fullstack/src/adapters/salvo_adapter.rs +++ /dev/null @@ -1,581 +0,0 @@ -//! Dioxus utilities for the [Salvo](https://salvo.rs) server framework. -//! -//! # Example -//! ```rust -//! #![allow(non_snake_case)] -//! use dioxus_lib::prelude::*; -//! use dioxus_fullstack::prelude::*; -//! -//! fn main() { -//! #[cfg(feature = "web")] -//! dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); -//! #[cfg(feature = "server")] -//! { -//! use salvo::prelude::*; -//! tokio::runtime::Runtime::new() -//! .unwrap() -//! .block_on(async move { -//! let router = -//! Router::new().serve_dioxus_application("", ServerConfig::new(app, ())); -//! Server::new(TcpListener::bind("127.0.0.1:8080")) -//! .serve(router) -//! .await; -//! }); -//! } -//! } -//! -//! fn app() -> Element { -//! let text = use_signal(|| "...".to_string()); -//! -//! rsx! { -//! button { -//! onclick: move |_| { -//! to_owned![text]; -//! async move { -//! if let Ok(data) = get_server_data().await { -//! text.set(data); -//! } -//! } -//! }, -//! "Run a server function" -//! } -//! "Server said: {text}" -//! }) -//! } -//! -//! #[server(GetServerData)] -//! async fn get_server_data() -> Result { -//! Ok("Hello from the server!".to_string()) -//! } -//! ``` - -use dioxus_lib::prelude::*; -use http_body_util::{BodyExt, Limited}; -use hyper::body::Body as HyperBody; -use hyper::StatusCode; -use salvo::{ - async_trait, handler, - http::{ - cookie::{Cookie, CookieJar}, - ParseError, - }, - serve_static::{StaticDir, StaticFile}, - Depot, Error as SalvoError, FlowCtrl, Handler, Request, Response, Router, -}; -use server_fn::{Encoding, ServerFunctionRegistry}; -use std::error::Error; -use std::sync::Arc; -use std::sync::RwLock; - -use crate::{ - layer::Service, prelude::*, render::SSRState, serve_config::ServeConfig, - server_fn::DioxusServerFnRegistry, server_fn_service, -}; - -type HyperRequest = hyper::Request; -type HyperResponse = hyper::Response; - -/// A extension trait with utilities for integrating Dioxus with your Salvo router. -pub trait DioxusRouterExt { - /// Registers server functions with a custom handler function. This allows you to pass custom context to your server functions by generating a [`DioxusServerContext`] from the request. - /// - /// # Example - /// ```rust - /// use salvo::prelude::*; - /// use std::{net::TcpListener, sync::Arc}; - /// use dioxus_fullstack::prelude::*; - /// - /// struct ServerFunctionHandler { - /// server_fn: server_fn::ServerFnTraitObj<()>, - /// } - /// - /// #[handler] - /// impl ServerFunctionHandler { - /// async fn handle( - /// &self, - /// req: &mut Request, - /// depot: &mut Depot, - /// res: &mut Response, - /// flow: &mut FlowCtrl, - /// ) { - /// // Add the headers to server context - /// ServerFnHandler::new((req.headers().clone(),), self.server_fn.clone()) - /// .handle(req, depot, res, flow) - /// .await - /// } - /// } - /// - /// #[tokio::main] - /// async fn main() { - /// let router = Router::new() - /// .register_server_fns_with_handler("", |func| { - /// ServerFnHandler::new(DioxusServerContext::default(), func) - /// }); - /// Server::new(TcpListener::bind("127.0.0.1:8080")) - /// .serve(router) - /// .await; - /// } - /// ``` - fn register_server_fns_with_handler( - self, - server_fn_route: &'static str, - handler: impl Fn(server_fn::ServerFnTraitObj<()>) -> H, - ) -> Self - where - H: Handler + 'static; - - /// Registers server functions with the default handler. This handler function will pass an empty [`DioxusServerContext`] to your server functions. - /// - /// # Example - /// ```rust - /// use salvo::prelude::*; - /// use std::{net::TcpListener, sync::Arc}; - /// use dioxus_fullstack::prelude::*; - /// - /// #[tokio::main] - /// async fn main() { - /// let router = Router::new() - /// .register_server_fns(""); - /// Server::new(TcpListener::bind("127.0.0.1:8080")) - /// .serve(router) - /// .await; - /// } - /// - /// ``` - fn register_server_fns(self, server_fn_route: &'static str) -> Self; - - /// Register the web RSX hot reloading endpoint. This will enable hot reloading for your application in debug mode when you call [`dioxus_hot_reload::hot_reload_init`]. - /// - /// # Example - /// ```rust - /// use salvo::prelude::*; - /// use std::{net::TcpListener, sync::Arc}; - /// use dioxus_fullstack::prelude::*; - /// - /// #[tokio::main] - /// async fn main() { - /// let router = Router::new() - /// .connect_hot_reload(); - /// Server::new(TcpListener::bind("127.0.0.1:8080")) - /// .serve(router) - /// .await; - /// } - fn connect_hot_reload(self) -> Self; - - /// Serves the static WASM for your Dioxus application (except the generated index.html). - /// - /// # Example - /// ```rust - /// use salvo::prelude::*; - /// use std::{net::TcpListener, sync::Arc}; - /// use dioxus_fullstack::prelude::*; - /// - /// #[tokio::main] - /// async fn main() { - /// let router = Router::new() - /// .server_static_assets("/dist"); - /// Server::new(TcpListener::bind("127.0.0.1:8080")) - /// .serve(router) - /// .await; - /// } - /// ``` - fn serve_static_assets(self, assets_path: impl Into) -> Self; - - /// Serves the Dioxus application. This will serve a complete server side rendered application. - /// This will serve static assets, server render the application, register server functions, and intigrate with hot reloading. - /// - /// # Example - /// ```rust - /// #![allow(non_snake_case)] - /// use dioxus_lib::prelude::*; - /// use dioxus_fullstack::prelude::*; - /// use salvo::prelude::*; - /// use std::{net::TcpListener, sync::Arc}; - /// - /// #[tokio::main] - /// async fn main() { - /// let router = Router::new().serve_dioxus_application("", ServerConfig::new(app, ())); - /// Server::new(TcpListener::bind("127.0.0.1:8080")) - /// .serve(router) - /// .await; - /// } - /// - /// fn app() -> Element {unimplemented!() } - /// ``` - fn serve_dioxus_application( - self, - server_fn_path: &'static str, - cfg: impl Into, - virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static, - ) -> Self; -} - -impl DioxusRouterExt for Router { - fn register_server_fns_with_handler( - self, - server_fn_route: &'static str, - mut handler: impl FnMut(server_fn::ServerFnTraitObj<()>) -> H, - ) -> Self - where - H: Handler + 'static, - { - let mut router = self; - for server_fn_path in DioxusServerFnRegistry::paths_registered() { - let func = DioxusServerFnRegistry::get(server_fn_path).unwrap(); - let full_route = format!("{server_fn_route}/{server_fn_path}"); - match func.encoding() { - Encoding::Url | Encoding::Cbor => { - router = router.push(Router::with_path(&full_route).post(handler(func))); - } - Encoding::GetJSON | Encoding::GetCBOR => { - router = router.push(Router::with_path(&full_route).get(handler(func))); - } - } - } - router - } - - fn register_server_fns(self, server_fn_route: &'static str) -> Self { - self.register_server_fns_with_handler(server_fn_route, |func| ServerFnHandler { - server_context: DioxusServerContext::default(), - function: func, - }) - } - - fn serve_static_assets(mut self, assets_path: impl Into) -> Self { - let assets_path = assets_path.into(); - - // Serve all files in dist folder except index.html - let dir = std::fs::read_dir(&assets_path).unwrap_or_else(|e| { - panic!( - "Couldn't read assets directory at {:?}: {}", - &assets_path, e - ) - }); - - for entry in dir.flatten() { - let path = entry.path(); - if path.ends_with("index.html") { - continue; - } - let route = path - .strip_prefix(&assets_path) - .unwrap() - .iter() - .map(|segment| { - segment.to_str().unwrap_or_else(|| { - panic!("Failed to convert path segment {:?} to string", segment) - }) - }) - .collect::>() - .join("/"); - if path.is_file() { - let route = format!("/{}", route); - let serve_dir = StaticFile::new(path.clone()); - self = self.push(Router::with_path(route).get(serve_dir)) - } else { - let route = format!("/{}/<**path>", route); - let serve_dir = StaticDir::new([path.clone()]); - self = self.push(Router::with_path(route).get(serve_dir)) - } - } - - self - } - - fn serve_dioxus_application( - self, - server_fn_path: &'static str, - cfg: impl Into, - virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static, - ) -> Self { - let cfg = cfg.into(); - - self.serve_static_assets(cfg.assets_path.clone()) - .connect_hot_reload() - .register_server_fns(server_fn_path) - .push(Router::with_path("/<**any_path>").get(SSRHandler { - config: cfg, - virtual_dom: virtual_dom_factory, - })) - } - - fn connect_hot_reload(self) -> Self { - let mut _dioxus_router = Router::with_path("_dioxus"); - _dioxus_router = - _dioxus_router.push(Router::with_path("hot_reload").handle(HotReloadHandler)); - #[cfg(all(debug_assertions, feature = "hot-reload"))] - { - _dioxus_router = _dioxus_router.push(Router::with_path("disconnect").handle(ignore_ws)); - } - self.push(_dioxus_router) - } -} - -/// Extracts the parts of a request that are needed for server functions. This will take parts of the request and replace them with empty values. -pub fn extract_parts(req: &mut Request) -> http::request::Parts { - let mut parts = http::request::Request::new(()).into_parts().0; - parts.method = std::mem::take(req.method_mut()); - parts.uri = std::mem::take(req.uri_mut()); - parts.version = req.version(); - parts.headers = std::mem::take(req.headers_mut()); - parts.extensions = std::mem::take(req.extensions_mut()); - - parts -} - -fn apply_request_parts_to_response( - headers: hyper::header::HeaderMap, - response: &mut salvo::prelude::Response, -) { - let mut_headers = response.headers_mut(); - for (key, value) in headers.iter() { - mut_headers.insert(key, value.clone()); - } -} - -#[inline] -async fn convert_request(req: &mut Request) -> Result { - let forward_url: hyper::Uri = TryFrom::try_from(req.uri()).map_err(SalvoError::other)?; - let mut build = hyper::Request::builder() - .method(req.method()) - .uri(&forward_url); - for (key, value) in req.headers() { - build = build.header(key, value); - } - static SECURE_MAX_SIZE: usize = 64 * 1024; - - let body = Limited::new(req.take_body(), SECURE_MAX_SIZE) - .collect() - .await - .map_err(ParseError::other)? - .to_bytes(); - build.body(body.into()).map_err(SalvoError::other) -} - -#[inline] -async fn convert_response(response: HyperResponse, res: &mut Response) { - let (parts, body) = response.into_parts(); - let http::response::Parts { - version, - headers, - status, - .. - } = parts; - res.status_code = Some(status); - res.version = version; - res.cookies = CookieJar::new(); - for cookie in headers.get_all(http::header::SET_COOKIE).iter() { - if let Some(cookie) = cookie - .to_str() - .ok() - .and_then(|s| Cookie::parse(s.to_string()).ok()) - { - res.cookies.add_original(cookie); - } - } - res.headers = headers; - res.version = version; - if let Ok(bytes) = hyper::body::to_bytes(body).await { - res.body = bytes.into() - } -} - -/// A handler that renders a Dioxus application to HTML using server-side rendering. -pub struct SSRHandler { - config: ServeConfig, - virtual_dom: Box VirtualDom + Send + Sync>, -} - -impl SSRHandler { - /// Creates a new SSR handler with the given configuration. - pub fn new( - config: ServeConfig, - virtual_dom: impl Fn() -> VirtualDom + Send + Sync + 'static, - ) -> Self { - Self { - config, - virtual_dom: Box::new(virtual_dom), - } - } -} - -#[async_trait] -impl Handler for SSRHandler { - async fn handle( - &self, - req: &mut Request, - depot: &mut Depot, - res: &mut Response, - _flow: &mut FlowCtrl, - ) { - // Get the SSR renderer from the depot or create a new one if it doesn't exist - let renderer_pool = if let Some(renderer) = depot.obtain::() { - renderer.clone() - } else { - let renderer = SSRState::new(&self.cfg); - depot.inject(renderer.clone()); - renderer - }; - - let route = req.uri().path().to_string(); - let parts: Arc> = Arc::new(RwLock::new(extract_parts(req))); - let server_context = DioxusServerContext::new(parts); - - match renderer_pool - .render(route, &self.cfg, &server_context) - .await - { - Ok(rendered) => { - let crate::render::RenderResponse { html, freshness } = rendered; - - res.write_body(html).unwrap(); - - let headers = server_context.response_parts().unwrap().headers.clone(); - apply_request_parts_to_response(headers, res); - freshness.write(res.headers_mut()); - } - Err(err) => { - tracing::error!("Error rendering SSR: {}", err); - res.write_body("Error rendering SSR").unwrap(); - } - }; - } -} - -/// A default handler for server functions. It will deserialize the request body, call the server function, and serialize the response. -pub struct ServerFnHandler { - server_context: DioxusServerContext, - function: server_fn::ServerFnTraitObj<()>, -} - -impl ServerFnHandler { - /// Create a new server function handler with the given server context and server function. - pub fn new( - server_context: impl Into, - function: server_fn::ServerFnTraitObj<()>, - ) -> Self { - let server_context = server_context.into(); - Self { - server_context, - function, - } - } -} - -#[handler] -impl ServerFnHandler { - async fn handle(&self, req: &mut Request, _depot: &mut Depot, res: &mut Response) { - match convert_request(req).await { - Ok(hyper_req) => { - let response = - server_fn_service(self.server_context.clone(), self.function.clone()) - .run(hyper_req) - .await - .unwrap(); - convert_response(response, res).await; - } - Err(err) => handle_error(err, res), - } - } -} - -fn handle_error(error: impl Error + Send + Sync, res: &mut Response) { - let mut resp_err = Response::new(); - resp_err.status_code(StatusCode::INTERNAL_SERVER_ERROR); - resp_err.render(format!("Internal Server Error: {}", error)); - *res = resp_err; -} - -/// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change. -#[cfg(not(all(debug_assertions, feature = "hot-reload")))] -#[derive(Default)] -pub struct HotReloadHandler; - -#[cfg(not(all(debug_assertions, feature = "hot-reload")))] -#[handler] -impl HotReloadHandler { - async fn handle( - &self, - _req: &mut Request, - _depot: &mut Depot, - _res: &mut Response, - ) -> Result<(), salvo::http::StatusError> { - Err(salvo::http::StatusError::not_found()) - } -} - -/// A handler for Dioxus web hot reload websocket. This will send the updated static parts of the RSX to the client when they change. -#[cfg(all(debug_assertions, feature = "hot-reload"))] -#[derive(Default)] -pub struct HotReloadHandler; - -#[cfg(all(debug_assertions, feature = "hot-reload"))] -#[handler] -impl HotReloadHandler { - async fn handle( - &self, - req: &mut Request, - _depot: &mut Depot, - res: &mut Response, - ) -> Result<(), salvo::http::StatusError> { - use salvo::websocket::Message; - use salvo::websocket::WebSocketUpgrade; - - let state = crate::hot_reload::spawn_hot_reload().await; - - WebSocketUpgrade::new() - .upgrade(req, res, move |mut websocket| async move { - use futures_util::StreamExt; - - println!("🔥 Hot Reload WebSocket connected"); - { - // update any rsx calls that changed before the websocket connected. - { - println!("🔮 Finding updates since last compile..."); - let templates_read = state.templates.read().await; - - for template in &*templates_read { - if websocket - .send(Message::text(serde_json::to_string(&template).unwrap())) - .await - .is_err() - { - return; - } - } - } - println!("finished"); - } - - let mut rx = tokio_stream::wrappers::WatchStream::from_changes( - state.message_receiver.clone(), - ); - while let Some(change) = rx.next().await { - if let Some(template) = change { - let template = { serde_json::to_string(&template).unwrap() }; - if websocket.send(Message::text(template)).await.is_err() { - break; - }; - } - } - }) - .await - } -} - -#[cfg(all(debug_assertions, feature = "hot-reload"))] -#[handler] -async fn ignore_ws(req: &mut Request, res: &mut Response) -> Result<(), salvo::http::StatusError> { - use salvo::websocket::WebSocketUpgrade; - WebSocketUpgrade::new() - .upgrade(req, res, |mut ws| async move { - let _ = ws.send(salvo::websocket::Message::text("connected")).await; - while let Some(msg) = ws.recv().await { - if msg.is_err() { - return; - }; - } - }) - .await -} diff --git a/packages/fullstack/src/adapters/warp_adapter.rs b/packages/fullstack/src/adapters/warp_adapter.rs deleted file mode 100644 index 711980ec8..000000000 --- a/packages/fullstack/src/adapters/warp_adapter.rs +++ /dev/null @@ -1,417 +0,0 @@ -//! Dioxus utilities for the [Warp](https://docs.rs/warp/latest/warp/index.html) server framework. -//! -//! # Example -//! ```rust -//! #![allow(non_snake_case)] -//! use dioxus_lib::prelude::*; -//! use dioxus_fullstack::prelude::*; -//! -//! fn main() { -//! #[cfg(feature = "web")] -//! dioxus_web::launch_cfg(app, dioxus_web::Config::new().hydrate(true)); -//! #[cfg(feature = "server")] -//! { -//! tokio::runtime::Runtime::new() -//! .unwrap() -//! .block_on(async move { -//! let routes = serve_dioxus_application("", ServerConfig::new(app, ())); -//! warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; -//! }); -//! } -//! } -//! -//! fn app() -> Element { -//! let text = use_signal(|| "...".to_string()); -//! -//! rsx! { -//! button { -//! onclick: move |_| { -//! to_owned![text]; -//! async move { -//! if let Ok(data) = get_server_data().await { -//! text.set(data); -//! } -//! } -//! }, -//! "Run a server function" -//! } -//! "Server said: {text}" -//! }) -//! } -//! -//! #[server(GetServerData)] -//! async fn get_server_data() -> Result { -//! Ok("Hello from the server!".to_string()) -//! } -//! -//! ``` - -use crate::layer::Service; -use crate::{ - prelude::*, render::SSRState, serve_config::ServeConfig, server_fn::DioxusServerFnRegistry, -}; - -use crate::server_fn_service; -use dioxus_lib::prelude::VirtualDom; -use server_fn::{Encoding, Payload, ServerFunctionRegistry}; -use std::error::Error; -use std::sync::Arc; -use std::sync::RwLock; -use tokio::task::spawn_blocking; -use warp::path::FullPath; -use warp::Rejection; -use warp::{ - filters::BoxedFilter, - http::{Response, StatusCode}, - hyper::body::Bytes, - path, Filter, Reply, -}; - -/// Registers server functions with a custom handler function. This allows you to pass custom context to your server functions by generating a [`DioxusServerContext`] from the request. -/// -/// # Example -/// ```rust -/// use warp::{body, header, hyper::HeaderMap, path, post, Filter}; -/// -/// #[tokio::main] -/// async fn main() { -/// let routes = register_server_fns_with_handler(server_fn_route, |full_route, func| { -/// path(full_route) -/// .and(warp::post().or(warp::get()).unify()) -/// .and(request_parts()) -/// .and(warp::body::bytes()) -/// .and_then(move |parts, bytes: bytes::Bytes| { -/// let mut service = server_fn_service(DioxusServerContext::default(), func.clone()); -/// async move { -/// let req = warp::hyper::Request::from_parts(parts, bytes.into()); -/// service.run(req).await.map_err(|err| { -/// tracing::error!("Server function error: {}", err); -/// warp::reject::reject() -/// }) -/// } -/// }) -/// }) -/// warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; -/// } -/// ``` -pub fn register_server_fns_with_handler( - server_fn_route: &'static str, - mut handler: H, -) -> BoxedFilter<(R,)> -where - H: FnMut(String, server_fn::ServerFnTraitObj<()>) -> F, - F: Filter + Send + Sync + 'static, - F::Extract: Send, - R: Reply + 'static, -{ - let mut filter: Option> = None; - for server_fn_path in DioxusServerFnRegistry::paths_registered() { - let func = DioxusServerFnRegistry::get(server_fn_path).unwrap(); - let full_route = format!("{server_fn_route}/{server_fn_path}") - .trim_start_matches('/') - .to_string(); - let route = handler(full_route, func).boxed(); - if let Some(boxed_filter) = filter.take() { - filter = Some(boxed_filter.or(route).unify().boxed()); - } else { - filter = Some(route); - } - } - filter.expect("No server functions found") -} - -/// Registers server functions with the default handler. This handler function will pass an empty [`DioxusServerContext`] to your server functions. -/// -/// # Example -/// ```rust -/// use dioxus_fullstack::prelude::*; -/// -/// #[tokio::main] -/// async fn main() { -/// let routes = register_server_fns(""); -/// warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; -/// } -/// ``` -pub fn register_server_fns(server_fn_route: &'static str) -> BoxedFilter<(impl Reply,)> { - register_server_fns_with_handler(server_fn_route, |full_route, func| { - path(full_route) - .and(warp::post().or(warp::get()).unify()) - .and(request_parts()) - .and(warp::body::bytes()) - .and_then(move |parts, bytes: bytes::Bytes| { - let mut service = server_fn_service(DioxusServerContext::default(), func.clone()); - async move { - let req = warp::hyper::Request::from_parts(parts, bytes.into()); - service.run(req).await.map_err(|err| { - tracing::error!("Server function error: {}", err); - - struct WarpServerFnError(String); - impl std::fmt::Debug for WarpServerFnError { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.0) - } - } - - impl warp::reject::Reject for WarpServerFnError {} - - warp::reject::custom(WarpServerFnError(err.to_string())) - }) - } - }) - }) -} - -/// Serves the Dioxus application. This will serve a complete server side rendered application. -/// This will serve static assets, server render the application, register server functions, and intigrate with hot reloading. -/// -/// # Example -/// ```rust -/// #![allow(non_snake_case)] -/// use dioxus_lib::prelude::*; -/// use dioxus_fullstack::prelude::*; -/// -/// #[tokio::main] -/// async fn main() { -/// let routes = serve_dioxus_application("", ServerConfig::new(app, ())); -/// warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; -/// } -/// -/// fn app() -> Element { -/// None -/// } -/// ``` -pub fn serve_dioxus_application( - server_fn_route: &'static str, - cfg: impl Into, - virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static, -) -> BoxedFilter<(impl Reply,)> { - let cfg = cfg.into(); - // Serve the dist folder and the index.html file - let serve_dir = warp::fs::dir(cfg.assets_path.clone()); - - let virtual_dom_factory = - Arc::new(virtual_dom_factory) as Arc VirtualDom + Send + Sync + 'static>; - - connect_hot_reload() - // First register the server functions - .or(register_server_fns(server_fn_route)) - // Then the index route - .or(path::end().and(render_ssr(cfg.clone(), { - let virtual_dom_factory = virtual_dom_factory.clone(); - move || virtual_dom_factory() - }))) - // Then the static assets - .or(serve_dir) - // Then all other routes - .or(render_ssr(cfg, move || virtual_dom_factory())) - .boxed() -} - -/// Server render the application. -pub fn render_ssr( - cfg: ServeConfig, - virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static, -) -> impl Filter + Clone { - warp::get() - .and(request_parts()) - .and(with_ssr_state(&cfg, virtual_dom_factory)) - .then( - move |parts: http::request::Parts, - (renderer, virtual_dom_factory): ( - SSRState, - Arc VirtualDom + Send + Sync + 'static>, - )| { - let route = parts.uri.path().to_string(); - let parts = Arc::new(RwLock::new(parts)); - let cfg = cfg.clone(); - async move { - let server_context = DioxusServerContext::new(parts); - - match renderer - .render(route, &cfg, move || virtual_dom_factory(), &server_context) - .await - { - Ok(rendered) => { - let crate::render::RenderResponse { html, freshness } = rendered; - - let mut res = Response::builder() - .header("Content-Type", "text/html") - .body(html) - .unwrap(); - - let headers_mut = res.headers_mut(); - let headers = server_context.response_parts().unwrap().headers.clone(); - for (key, value) in headers.iter() { - headers_mut.insert(key, value.clone()); - } - freshness.write(headers_mut); - - res - } - Err(err) => { - tracing::error!("Failed to render ssr: {}", err); - Response::builder() - .status(500) - .body("Failed to render ssr".into()) - .unwrap() - } - } - } - }, - ) -} - -/// An extractor for the request parts (used in [DioxusServerContext]). This will extract the method, uri, query, and headers from the request. -pub fn request_parts( -) -> impl Filter + Clone { - warp::method() - .and(warp::filters::path::full()) - .and( - warp::filters::query::raw() - .or(warp::any().map(String::new)) - .unify(), - ) - .and(warp::header::headers_cloned()) - .and_then(move |method, path: FullPath, query, headers| async move { - http::uri::Builder::new() - .path_and_query(format!("{}?{}", path.as_str(), query)) - .build() - .map_err(|err| { - warp::reject::custom(FailedToReadBody(format!("Failed to build uri: {}", err))) - }) - .map(|uri| { - let mut req = http::Request::builder() - .method(method) - .uri(uri) - .body(()) - .unwrap(); - req.headers_mut().extend(headers); - req.into_parts().0 - }) - }) -} - -fn with_ssr_state( - cfg: &ServeConfig, - virtual_dom_factory: impl Fn() -> VirtualDom + Send + Sync + 'static, -) -> impl Filter< - Extract = (( - SSRState, - Arc VirtualDom + Send + Sync + 'static>, - ),), - Error = std::convert::Infallible, -> + Clone { - let renderer = SSRState::new(cfg); - let virtual_dom_factory = - Arc::new(virtual_dom_factory) as Arc VirtualDom + Send + Sync + 'static>; - warp::any().map(move || (renderer.clone(), virtual_dom_factory.clone())) -} - -#[derive(Debug)] -struct FailedToReadBody(String); - -impl warp::reject::Reject for FailedToReadBody {} - -#[derive(Debug)] -struct RecieveFailed(String); - -impl warp::reject::Reject for RecieveFailed {} - -/// Register the web RSX hot reloading endpoint. This will enable hot reloading for your application in debug mode when you call [`dioxus_hot_reload::hot_reload_init`]. -/// -/// # Example -/// ```rust -/// #![allow(non_snake_case)] -/// use dioxus_fullstack::prelude::*; -/// -/// #[tokio::main] -/// async fn main() { -/// let routes = connect_hot_reload(); -/// warp::serve(routes).run(([127, 0, 0, 1], 8080)).await; -/// } -/// ``` -pub fn connect_hot_reload() -> impl Filter + Clone -{ - #[cfg(not(all(debug_assertions, feature = "hot-reload")))] - { - warp::path!("_dioxus" / "hot_reload") - .map(warp::reply) - .map(|reply| warp::reply::with_status(reply, warp::http::StatusCode::NOT_FOUND)) - } - #[cfg(all(debug_assertions, feature = "hot-reload"))] - { - use crate::hot_reload::HotReloadState; - use futures_util::sink::SinkExt; - use futures_util::StreamExt; - use warp::ws::Message; - - let hot_reload = warp::path!("_dioxus" / "hot_reload") - .and(warp::any().then(crate::hot_reload::spawn_hot_reload)) - .and(warp::ws()) - .map(move |state: &'static HotReloadState, ws: warp::ws::Ws| { - // #[cfg(all(debug_assertions, feature = "hot-reload"))] - ws.on_upgrade(move |mut websocket| { - async move { - println!("🔥 Hot Reload WebSocket connected"); - { - // update any rsx calls that changed before the websocket connected. - { - println!("🔮 Finding updates since last compile..."); - let templates_read = state.templates.read().await; - - for template in &*templates_read { - if websocket - .send(Message::text( - serde_json::to_string(&template).unwrap(), - )) - .await - .is_err() - { - return; - } - } - } - println!("finished"); - } - - let mut rx = tokio_stream::wrappers::WatchStream::from_changes( - state.message_receiver.clone(), - ); - while let Some(change) = rx.next().await { - if let Some(template) = change { - let template = { serde_json::to_string(&template).unwrap() }; - if websocket.send(Message::text(template)).await.is_err() { - break; - }; - } - } - } - }) - }); - let disconnect = - warp::path!("_dioxus" / "disconnect") - .and(warp::ws()) - .map(move |ws: warp::ws::Ws| { - println!("disconnect"); - #[cfg(all(debug_assertions, feature = "hot-reload",))] - ws.on_upgrade(move |mut websocket| async move { - struct DisconnectOnDrop(Option); - impl Drop for DisconnectOnDrop { - fn drop(&mut self) { - std::mem::drop(self.0.take().unwrap().close()); - } - } - - let _ = websocket.send(Message::text("connected")).await; - let mut ws = DisconnectOnDrop(Some(websocket)); - - loop { - if ws.0.as_mut().unwrap().next().await.is_none() { - break; - } - } - }) - }); - disconnect.or(hot_reload) - } -} diff --git a/packages/fullstack/src/config.rs b/packages/fullstack/src/config.rs index f4416b8df..176e7381e 100644 --- a/packages/fullstack/src/config.rs +++ b/packages/fullstack/src/config.rs @@ -53,7 +53,7 @@ impl Config { /// Set the address to serve the app on. #[cfg(feature = "server")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] + #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub fn addr(self, addr: impl Into) -> Self { let addr = addr.into(); Self { addr, ..self } @@ -61,7 +61,7 @@ impl Config { /// Set the route to the server functions. #[cfg(feature = "server")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] + #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub fn server_fn_route(self, server_fn_route: &'static str) -> Self { Self { server_fn_route, @@ -71,7 +71,7 @@ impl Config { /// Set the incremental renderer config. #[cfg(feature = "server")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] + #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub fn incremental(self, cfg: IncrementalRendererConfig) -> Self { Self { server_cfg: self.server_cfg.incremental(cfg), @@ -81,21 +81,21 @@ impl Config { /// Set the server config. #[cfg(feature = "server")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] + #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub fn server_cfg(self, server_cfg: ServeConfigBuilder) -> Self { Self { server_cfg, ..self } } /// Set the web config. #[cfg(feature = "web")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "web")))] + #[cfg_attr(docsrs, doc(cfg(feature = "web")))] pub fn web_cfg(self, web_cfg: dioxus_web::Config) -> Self { Self { web_cfg, ..self } } /// Set the desktop config. #[cfg(feature = "desktop")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "desktop")))] + #[cfg_attr(docsrs, doc(cfg(feature = "desktop")))] pub fn desktop_cfg(self, desktop_cfg: dioxus_desktop::Config) -> Self { Self { desktop_cfg, @@ -105,13 +105,13 @@ impl Config { /// Set the mobile config. #[cfg(feature = "mobile")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "mobile")))] + #[cfg_attr(docsrs, doc(cfg(feature = "mobile")))] pub fn mobile_cfg(self, mobile_cfg: dioxus_mobile::Config) -> Self { Self { mobile_cfg, ..self } } #[cfg(feature = "server")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] + #[cfg_attr(docsrs, doc(cfg(feature = "server")))] /// Launch a server application pub async fn launch_server( self, @@ -121,7 +121,8 @@ impl Config { println!("Listening on {}", addr); let cfg = self.server_cfg.build(); let server_fn_route = self.server_fn_route; - #[cfg(all(feature = "axum", not(feature = "warp"), not(feature = "salvo")))] + + #[cfg(feature = "axum")] { use crate::adapters::axum_adapter::{render_handler, DioxusRouterExt}; use axum::routing::get; @@ -144,52 +145,8 @@ impl Config { .layer(tower_http::compression::CompressionLayer::new().gzip(true)), ) .into_make_service(); - axum::Server::bind(&addr).serve(router).await.unwrap(); - } - #[cfg(all(feature = "warp", not(feature = "axum"), not(feature = "salvo")))] - { - use warp::Filter; - // First register the server functions - let router = register_server_fns(server_fn_route); - #[cfg(not(any(feature = "desktop", feature = "mobile")))] - let router = { - // Serve the dist folder and the index.html file - let serve_dir = warp::fs::dir(cfg.assets_path); - let build_virtual_dom = Arc::new(build_virtual_dom); - - router - .or(connect_hot_reload()) - // Then the index route - .or(warp::path::end().and(render_ssr(cfg.clone(), { - let build_virtual_dom = build_virtual_dom.clone(); - move || build_virtual_dom() - }))) - // Then the static assets - .or(serve_dir) - // Then all other routes - .or(render_ssr(cfg, move || build_virtual_dom())) - }; - warp::serve(router.boxed().with(warp::filters::compression::gzip())) - .run(addr) - .await; - } - #[cfg(all(feature = "salvo", not(feature = "axum"), not(feature = "warp")))] - { - use crate::adapters::salvo_adapter::{DioxusRouterExt, SSRHandler}; - use salvo::conn::Listener; - let router = salvo::Router::new().register_server_fns(server_fn_route); - #[cfg(not(any(feature = "desktop", feature = "mobile")))] - let router = router - .serve_static_assets(cfg.assets_path) - .connect_hot_reload() - .push(salvo::Router::with_path("/<**any_path>").get(SSRHandler::new(cfg))); - let router = router.hoop( - salvo::compression::Compression::new() - .enable_gzip(salvo::prelude::CompressionLevel::Default), - ); - salvo::Server::new(salvo::conn::tcp::TcpListener::new(addr).bind().await) - .serve(router) - .await; + let listener = tokio::net::TcpListener::bind(addr).await.unwrap(); + axum::serve(listener, router).await.unwrap(); } } } diff --git a/packages/fullstack/src/layer.rs b/packages/fullstack/src/layer.rs index 60f76107b..82d0226cb 100644 --- a/packages/fullstack/src/layer.rs +++ b/packages/fullstack/src/layer.rs @@ -19,35 +19,35 @@ where } } +type MyBody = axum::body::Body; + /// A service is a function that takes a request and returns an async response pub trait Service { /// Run the service and produce a future that resolves to a response fn run( &mut self, - req: http::Request, + req: http::Request, ) -> Pin< Box< - dyn std::future::Future< - Output = Result, server_fn::ServerFnError>, - > + Send, + dyn std::future::Future, server_fn::ServerFnError>> + + Send, >, >; } impl Service for S where - S: tower::Service, Response = Response>, + S: tower::Service, Response = Response>, S::Future: Send + 'static, S::Error: Into, { fn run( &mut self, - req: http::Request, + req: http::Request, ) -> Pin< Box< - dyn std::future::Future< - Output = Result, server_fn::ServerFnError>, - > + Send, + dyn std::future::Future, server_fn::ServerFnError>> + + Send, >, > { let fut = self.call(req).instrument(tracing::trace_span!( @@ -62,13 +62,13 @@ where /// A boxed service is a type-erased service that can be used without knowing the underlying type pub struct BoxedService(pub Box); -impl tower::Service> for BoxedService { - type Response = http::Response; +impl tower::Service> for BoxedService { + type Response = http::Response; type Error = server_fn::ServerFnError; type Future = Pin< Box< dyn std::future::Future< - Output = Result, server_fn::ServerFnError>, + Output = Result, server_fn::ServerFnError>, > + Send, >, >; @@ -80,7 +80,7 @@ impl tower::Service> for BoxedService { Ok(()).into() } - fn call(&mut self, req: Request) -> Self::Future { + fn call(&mut self, req: Request) -> Self::Future { self.0.run(req) } } diff --git a/packages/fullstack/src/lib.rs b/packages/fullstack/src/lib.rs index 270cbc801..775683828 100644 --- a/packages/fullstack/src/lib.rs +++ b/packages/fullstack/src/lib.rs @@ -11,21 +11,17 @@ mod html_storage; #[cfg(feature = "server")] mod adapters; // Splitting up the glob export lets us document features required for each adapter -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "axum")))] +#[cfg_attr(docsrs, doc(cfg(feature = "axum")))] #[cfg(feature = "axum")] pub use adapters::axum_adapter; -// TODO: Compilation seems to be broken with the salvo feature enabled. Fix and add more features to checks in CI -// #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "salvo")))] -// #[cfg(feature = "salvo")] -// pub use adapters::salvo_adapter; -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "warp")))] -#[cfg(feature = "warp")] -pub use adapters::warp_adapter; -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] + +#[cfg_attr(docsrs, doc(cfg(feature = "server")))] #[cfg(feature = "server")] pub use adapters::{server_fn_service, ServerFnHandler}; + mod config; mod hooks; + #[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))] mod hot_reload; pub mod launch; @@ -43,15 +39,11 @@ mod server_fn; /// A prelude of commonly used items in dioxus-fullstack. pub mod prelude { #[cfg(feature = "axum")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "axum")))] + #[cfg_attr(docsrs, doc(cfg(feature = "axum")))] pub use crate::adapters::axum_adapter::*; - // #[cfg(feature = "salvo")] - // #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "salvo")))] - // pub use crate::adapters::salvo_adapter::*; - #[cfg(feature = "warp")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "warp")))] - pub use crate::adapters::warp_adapter::*; + use crate::hooks; + #[cfg(not(feature = "server"))] #[cfg_attr( any(docsrs, feature = "nightly-doc"), @@ -59,8 +51,9 @@ pub mod prelude { )] pub use crate::html_storage::deserialize::get_root_props_from_document; #[cfg(feature = "server")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] + #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub use crate::layer::{Layer, Service}; + #[cfg(all(feature = "server", feature = "router"))] #[cfg_attr( any(docsrs, feature = "nightly-doc"), @@ -68,13 +61,15 @@ pub mod prelude { )] pub use crate::render::pre_cache_static_routes_with_props; #[cfg(feature = "server")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] + #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub use crate::render::SSRState; + #[cfg(feature = "router")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "router")))] + #[cfg_attr(docsrs, doc(cfg(feature = "router")))] pub use crate::router::FullstackRouterConfig; + #[cfg(feature = "server")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] + #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub use crate::serve_config::{ServeConfig, ServeConfigBuilder}; #[cfg(all(feature = "server", feature = "axum"))] #[cfg_attr( @@ -83,44 +78,29 @@ pub mod prelude { )] pub use crate::server_context::Axum; #[cfg(feature = "server")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] + #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub use crate::server_context::{ extract, server_context, DioxusServerContext, FromServerContext, ProvideServerContext, }; pub use crate::server_fn::DioxusServerFn; #[cfg(feature = "server")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] + #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub use crate::server_fn::{ServerFnMiddleware, ServerFnTraitObj, ServerFunction}; pub use dioxus_server_macro::*; #[cfg(feature = "server")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] + #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub use dioxus_ssr::incremental::IncrementalRendererConfig; pub use server_fn::{self, ServerFn as _, ServerFnError}; pub use hooks::{server_cached::server_cached, server_future::use_server_future}; } -// Warn users about overlapping features -#[cfg(all( - feature = "server", - feature = "web", - not(doc), - not(feature = "nightly-doc") -))] -compile_error!("The `ssr` feature (enabled by `warp`, `axum`, or `salvo`) and `web` feature are overlapping. Please choose one or the other."); +// // Warn users about overlapping features +// #[cfg(all(feature = "server", feature = "web", not(doc)))] +// compile_error!("The `ssr` feature (enabled by `warp`, `axum`, or `salvo`) and `web` feature are overlapping. Please choose one or the other."); -#[cfg(all( - feature = "server", - feature = "desktop", - not(doc), - not(feature = "nightly-doc") -))] -compile_error!("The `ssr` feature (enabled by `warp`, `axum`, or `salvo`) and `desktop` feature are overlapping. Please choose one or the other."); +// #[cfg(all(feature = "server", feature = "desktop", not(doc)))] +// compile_error!("The `ssr` feature (enabled by `warp`, `axum`, or `salvo`) and `desktop` feature are overlapping. Please choose one or the other."); -#[cfg(all( - feature = "server", - feature = "mobile", - not(doc), - not(feature = "nightly-doc") -))] -compile_error!("The `ssr` feature (enabled by `warp`, `axum`, or `salvo`) and `mobile` feature are overlapping. Please choose one or the other."); +// #[cfg(all(feature = "server", feature = "mobile", not(doc)))] +// compile_error!("The `ssr` feature (enabled by `warp`, `axum`, or `salvo`) and `mobile` feature are overlapping. Please choose one or the other."); diff --git a/packages/fullstack/src/server_context.rs b/packages/fullstack/src/server_context.rs index 8d5966a7c..2fb06b61f 100644 --- a/packages/fullstack/src/server_context.rs +++ b/packages/fullstack/src/server_context.rs @@ -228,7 +228,7 @@ impl FromServerContext for FromContext { } #[cfg(feature = "axum")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "axum")))] +#[cfg_attr(docsrs, doc(cfg(feature = "axum")))] /// An adapter for axum extractors for the server context pub struct Axum; diff --git a/packages/fullstack/src/server_fn.rs b/packages/fullstack/src/server_fn.rs index d51e4beec..cdfff266e 100644 --- a/packages/fullstack/src/server_fn.rs +++ b/packages/fullstack/src/server_fn.rs @@ -1,5 +1,5 @@ #[cfg(feature = "server")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] +#[cfg_attr(docsrs, doc(cfg(feature = "server")))] #[derive(Clone)] /// A trait object for a function that be called on serializable arguments and returns a serializable result. pub struct ServerFnTraitObj(server_fn::ServerFnTraitObj<()>); @@ -41,7 +41,7 @@ impl ServerFnTraitObj { server_fn::inventory::collect!(ServerFnTraitObj); #[cfg(feature = "server")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] +#[cfg_attr(docsrs, doc(cfg(feature = "server")))] /// Middleware for a server function pub struct ServerFnMiddleware { /// The prefix of the server function. @@ -75,7 +75,7 @@ pub(crate) static MIDDLEWARE: once_cell::sync::Lazy< server_fn::inventory::collect!(ServerFnMiddleware); #[cfg(feature = "server")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] +#[cfg_attr(docsrs, doc(cfg(feature = "server")))] /// A server function that can be called on serializable arguments and returns a serializable result. pub type ServerFunction = server_fn::SerializedFnTraitObj<()>; @@ -92,7 +92,7 @@ static REGISTERED_SERVER_FUNCTIONS: once_cell::sync::Lazy< }); #[cfg(feature = "server")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] +#[cfg_attr(docsrs, doc(cfg(feature = "server")))] /// The registry of all Dioxus server functions. pub struct DioxusServerFnRegistry; @@ -160,7 +160,7 @@ impl server_fn::ServerFunctionRegistry<()> for DioxusServerFnRegistry { } #[cfg(feature = "server")] -#[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] +#[cfg_attr(docsrs, doc(cfg(feature = "server")))] /// Errors that can occur when registering a server function. #[derive(thiserror::Error, Debug, Clone, serde::Serialize, serde::Deserialize)] pub enum ServerRegistrationFnError { @@ -184,7 +184,7 @@ pub enum ServerRegistrationFnError { pub trait DioxusServerFn: server_fn::ServerFn<()> { /// Registers the server function, allowing the client to query it by URL. #[cfg(feature = "server")] - #[cfg_attr(any(docsrs, feature = "nightly-doc"), doc(cfg(feature = "server")))] + #[cfg_attr(docsrs, doc(cfg(feature = "server")))] fn register_explicit() -> Result<(), server_fn::ServerFnError> { Self::register_in_explicit::() } diff --git a/packages/liveview/.vscode/settings.json b/packages/liveview/.vscode/settings.json deleted file mode 100644 index 6fff6cc40..000000000 --- a/packages/liveview/.vscode/settings.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "rust-analyzer.cargo.features": [ - "warp" - ] -} diff --git a/packages/liveview/Cargo.toml b/packages/liveview/Cargo.toml index c523d08be..e01e6d3dd 100644 --- a/packages/liveview/Cargo.toml +++ b/packages/liveview/Cargo.toml @@ -31,42 +31,19 @@ dioxus-hot-reload = { workspace = true, optional = true } dioxus-cli-config = { workspace = true } generational-box = { workspace = true } -# warp -warp = { version = "0.3.3", optional = true } - # axum -axum = { version = "0.6.1", optional = true, features = ["ws"] } - -# salvo -salvo = { version = "0.63.0", optional = true, features = ["websocket", "affix"] } -once_cell = "1.17.1" -async-trait = "0.1.71" - -# rocket -rocket = { version = "0.5.0", optional = true } -rocket_ws = { version = "0.1.0", optional = true } - -# actix is ... complicated? -# actix-files = { version = "0.6.2", optional = true } -# actix-web = { version = "4.2.1", optional = true } -# actix-ws = { version = "0.2.5", optional = true } +axum = { workspace = true, optional = true, features = ["ws"] } [dev-dependencies] pretty_env_logger = { version = "0.5.0" } tokio = { workspace = true, features = ["full"] } -warp = "0.3.3" -axum = { version = "0.6.1", features = ["ws"] } -salvo = { version = "0.63.0", features = ["affix", "websocket"] } -rocket = "0.5.0" -rocket_ws = "0.1.0" -tower = "0.4.13" +axum = { workspace = true, features = ["ws"] } +tower = { workspace = true } dioxus = { workspace = true } [features] default = ["hot-reload"] -# actix = ["actix-files", "actix-web", "actix-ws"] hot-reload = ["dioxus-hot-reload"] -rocket = ["dep:rocket", "dep:rocket_ws"] [[example]] name = "axum" @@ -75,15 +52,3 @@ required-features = ["axum"] [[example]] name = "axum_stress" required-features = ["axum"] - -[[example]] -name = "salvo" -required-features = ["salvo"] - -[[example]] -name = "warp" -required-features = ["warp"] - -[[example]] -name = "rocket" -required-features = ["rocket"] diff --git a/packages/liveview/README.md b/packages/liveview/README.md index 13af3c36f..66065ad31 100644 --- a/packages/liveview/README.md +++ b/packages/liveview/README.md @@ -26,9 +26,6 @@ The current backend frameworks supported include: - Axum -- Warp -- Salvo -- Rocket Dioxus-LiveView exports some primitives to wire up an app into an existing backend framework. diff --git a/packages/liveview/examples/rocket.rs b/packages/liveview/examples/rocket.rs deleted file mode 100644 index e5f045698..000000000 --- a/packages/liveview/examples/rocket.rs +++ /dev/null @@ -1,76 +0,0 @@ -#[macro_use] -extern crate rocket; - -use dioxus::prelude::*; -use dioxus_liveview::LiveViewPool; -use rocket::response::content::RawHtml; -use rocket::{Config, Rocket, State}; -use rocket_ws::{Channel, WebSocket}; - -fn app() -> Element { - let mut num = use_signal(|| 0); - - rsx! { - div { - "hello Rocket! {num}" - button { onclick: move |_| num += 1, "Increment" } - } - } -} - -fn index_page_with_glue(glue: &str) -> RawHtml { - RawHtml(format!( - r#" - - - Dioxus LiveView with Rocket -
- {glue} - - "#, - glue = glue - )) -} - -#[get("/")] -async fn index(config: &Config) -> RawHtml { - index_page_with_glue(&dioxus_liveview::interpreter_glue(&format!( - "ws://{addr}:{port}/ws", - addr = config.address, - port = config.port, - ))) -} - -#[get("/as-path")] -async fn as_path() -> RawHtml { - index_page_with_glue(&dioxus_liveview::interpreter_glue("/ws")) -} - -#[get("/ws")] -fn ws(ws: WebSocket, pool: &State) -> Channel<'static> { - let pool = pool.inner().to_owned(); - - ws.channel(move |stream| { - Box::pin(async move { - let _ = pool - .launch(dioxus_liveview::rocket_socket(stream), app) - .await; - Ok(()) - }) - }) -} - -#[tokio::main] -async fn main() { - let view = dioxus_liveview::LiveViewPool::new(); - - Rocket::build() - .manage(view) - .mount("/", routes![index, as_path, ws]) - .ignite() - .await - .expect("Failed to ignite rocket") - .launch() - .await - .expect("Failed to launch rocket"); -} diff --git a/packages/liveview/examples/salvo.rs b/packages/liveview/examples/salvo.rs deleted file mode 100644 index e4c27b091..000000000 --- a/packages/liveview/examples/salvo.rs +++ /dev/null @@ -1,67 +0,0 @@ -use dioxus::prelude::*; -use dioxus_liveview::LiveViewPool; -use salvo::affix; -use salvo::prelude::*; -use std::net::SocketAddr; -use std::sync::Arc; - -fn app() -> Element { - let mut num = use_signal(|| 0); - - rsx! { - div { - "hello salvo! {num}" - button { onclick: move |_| num += 1, "Increment" } - } - } -} - -#[tokio::main] -async fn main() { - pretty_env_logger::init(); - - let addr = "127.0.0.1:3030"; - let acceptor = TcpListener::new(addr).bind().await; - - let view = LiveViewPool::new(); - - let router = Router::new() - .hoop(affix::inject(Arc::new(view))) - .get(index) - .push(Router::with_path("ws").get(connect)); - - println!("Listening on http://{}", addr); - - Server::new(acceptor).serve(router).await; -} - -#[handler] -fn index(res: &mut Response) { - let addr: SocketAddr = ([127, 0, 0, 1], 3030).into(); - res.render(Text::Html(format!( - r#" - - - Dioxus LiveView with Salvo -
- {glue} - - "#, - glue = dioxus_liveview::interpreter_glue(&format!("ws://{addr}/ws")) - ))); -} - -#[handler] -async fn connect( - req: &mut Request, - depot: &mut Depot, - res: &mut Response, -) -> Result<(), StatusError> { - let view = depot.obtain::>().unwrap().clone(); - - WebSocketUpgrade::new() - .upgrade(req, res, |ws| async move { - _ = view.launch(dioxus_liveview::salvo_socket(ws), app).await; - }) - .await -} diff --git a/packages/liveview/examples/warp.rs b/packages/liveview/examples/warp.rs deleted file mode 100644 index 0b97f5abf..000000000 --- a/packages/liveview/examples/warp.rs +++ /dev/null @@ -1,56 +0,0 @@ -use dioxus::prelude::*; -use dioxus_liveview::warp_adapter::warp_socket; -use dioxus_liveview::LiveViewPool; -use std::net::SocketAddr; -use warp::ws::Ws; -use warp::Filter; - -fn app() -> Element { - let mut num = use_signal(|| 0); - - rsx! { - div { - "hello warp! {num}" - button { - onclick: move |_| num += 1, - "Increment" - } - } - } -} - -#[tokio::main] -async fn main() { - pretty_env_logger::init(); - - let addr: SocketAddr = ([127, 0, 0, 1], 3030).into(); - - let index = warp::path::end().map(move || { - warp::reply::html(format!( - r#" - - - Dioxus LiveView with Warp -
- {glue} - - "#, - glue = dioxus_liveview::interpreter_glue(&format!("ws://{addr}/ws/")) - )) - }); - - let pool = LiveViewPool::new(); - - let ws = warp::path("ws") - .and(warp::ws()) - .and(warp::any().map(move || pool.clone())) - .map(move |ws: Ws, pool: LiveViewPool| { - ws.on_upgrade(|ws| async move { - let _ = pool.launch(warp_socket(ws), app).await; - }) - }); - - println!("Listening on http://{}", addr); - - warp::serve(index.or(ws)).run(addr).await; -} diff --git a/packages/liveview/src/adapters/axum_adapter.rs b/packages/liveview/src/adapters/axum_adapter.rs index 6e859078e..7b9eb7904 100644 --- a/packages/liveview/src/adapters/axum_adapter.rs +++ b/packages/liveview/src/adapters/axum_adapter.rs @@ -81,10 +81,8 @@ impl LiveviewRouter for Router { } async fn start(self, address: impl Into) { - if let Err(err) = axum::Server::bind(&address.into()) - .serve(self.into_make_service()) - .await - { + let listener = tokio::net::TcpListener::bind(address.into()).await.unwrap(); + if let Err(err) = axum::serve(listener, self.into_make_service()).await { eprintln!("Failed to start axum server: {}", err); } } diff --git a/packages/liveview/src/adapters/mod.rs b/packages/liveview/src/adapters/mod.rs index 0e9e74d31..2abc6794a 100644 --- a/packages/liveview/src/adapters/mod.rs +++ b/packages/liveview/src/adapters/mod.rs @@ -2,26 +2,11 @@ use std::future::Future; use dioxus_core::{Element, VirtualDom}; -#[cfg(feature = "warp")] -pub mod warp_adapter; -#[cfg(feature = "warp")] -pub use warp_adapter::*; - #[cfg(feature = "axum")] pub mod axum_adapter; #[cfg(feature = "axum")] pub use axum_adapter::*; -#[cfg(feature = "salvo")] -pub mod salvo_adapter; -#[cfg(feature = "salvo")] -pub use salvo_adapter::*; - -#[cfg(feature = "rocket")] -pub mod rocket_adapter; -#[cfg(feature = "rocket")] -pub use rocket_adapter::*; - /// A trait for servers that can be used to host a LiveView app. pub trait LiveviewRouter { /// Create a new router. diff --git a/packages/liveview/src/adapters/rocket_adapter.rs b/packages/liveview/src/adapters/rocket_adapter.rs deleted file mode 100644 index 21f217eca..000000000 --- a/packages/liveview/src/adapters/rocket_adapter.rs +++ /dev/null @@ -1,113 +0,0 @@ -use crate::LiveViewPool; -use crate::LiveviewRouter; -use crate::{LiveViewError, LiveViewSocket}; -use rocket::futures::{SinkExt, StreamExt}; -use rocket::response::content::RawHtml; -use rocket::{get, routes, State}; -use rocket_ws::Channel; -use rocket_ws::WebSocket; -use rocket_ws::{result::Error, stream::DuplexStream, Message}; -use std::sync::Arc; - -/// Convert a Rocket WebSocket into a `LiveViewSocket`. -/// -/// This is required to launch a LiveView app using the Rocket web framework. -pub fn rocket_socket(stream: DuplexStream) -> impl LiveViewSocket { - stream - .map(transform_rx) - .with(transform_tx) - .sink_map_err(|_| LiveViewError::SendingFailed) -} - -fn transform_rx(message: Result) -> Result, LiveViewError> { - message - .map_err(|_| LiveViewError::SendingFailed)? - .into_text() - .map(|s| s.into_bytes()) - .map_err(|_| LiveViewError::SendingFailed) -} - -async fn transform_tx(message: Vec) -> Result { - Ok(Message::Binary(message)) -} - -impl LiveviewRouter for rocket::Rocket { - fn create_default_liveview_router() -> Self { - Self::build() - } - - fn with_virtual_dom( - self, - route: &str, - app: impl Fn() -> dioxus_core::prelude::VirtualDom + Send + Sync + 'static, - ) -> Self { - #[get("/")] - async fn index(request: &rocket::route::Route) -> RawHtml { - let route = request.uri.base(); - - let glue = crate::interpreter_glue(&format!("{route}/ws",)); - - let title = crate::app_title(); - - RawHtml(format!( - r#" - - - {title} -
- {glue} - - "# - )) - } - - #[get("/ws")] - fn ws(ws: WebSocket, app: &State) -> Channel<'static> { - let app = app.inner(); - let pool = app.pool.clone(); - let app = app.app.clone(); - - ws.channel(move |stream| { - Box::pin(async move { - let _ = pool - .launch_virtualdom(crate::rocket_socket(stream), move || app()) - .await; - Ok(()) - }) - }) - } - - struct LiveviewApp { - app: Arc dioxus_core::prelude::VirtualDom + Send + Sync + 'static>, - pool: LiveViewPool, - } - - let app = Arc::new(app); - - let view = crate::LiveViewPool::new(); - - self.manage(LiveviewApp { - app: app, - pool: view, - }) - .mount(route, routes![index, ws]) - } - - async fn start(self, address: impl Into) { - let address = address.into(); - - let figment = self - .figment() - .clone() - .merge((rocket::Config::PORT, address.port())) - .merge((rocket::Config::ADDRESS, address.ip())); - - self.configure(figment) - .ignite() - .await - .expect("Failed to ignite rocket") - .launch() - .await - .expect("Failed to launch rocket"); - } -} diff --git a/packages/liveview/src/adapters/salvo_adapter.rs b/packages/liveview/src/adapters/salvo_adapter.rs deleted file mode 100644 index 0a3f0cd0b..000000000 --- a/packages/liveview/src/adapters/salvo_adapter.rs +++ /dev/null @@ -1,108 +0,0 @@ -use crate::LiveViewPool; -use crate::LiveviewRouter; -use crate::{LiveViewError, LiveViewSocket}; -use futures_util::{SinkExt, StreamExt}; -use salvo::conn::TcpListener; -use salvo::http::StatusError; -use salvo::websocket::WebSocketUpgrade; -use salvo::websocket::{Message, WebSocket}; -use salvo::writing::Text; -use salvo::Listener; -use salvo::Server; -use salvo::{handler, Depot, Request, Response, Router}; -use std::sync::Arc; - -/// Convert a Salvo WebSocket into a `LiveViewSocket`. -/// -/// This is required to launch a LiveView app using the Salvo web framework. -pub fn salvo_socket(ws: WebSocket) -> impl LiveViewSocket { - ws.map(transform_rx) - .with(transform_tx) - .sink_map_err(|_| LiveViewError::SendingFailed) -} - -fn transform_rx(message: Result) -> Result, LiveViewError> { - let as_bytes = message.map_err(|_| LiveViewError::SendingFailed)?; - - Ok(as_bytes.into()) -} - -async fn transform_tx(message: Vec) -> Result { - Ok(Message::binary(message)) -} - -#[derive(Clone)] -struct LiveviewApp { - app: Arc dioxus_core::prelude::VirtualDom + Send + Sync + 'static>, - pool: Arc, -} - -impl LiveviewRouter for Router { - fn create_default_liveview_router() -> Self { - Self::new() - } - - fn with_virtual_dom( - self, - route: &str, - app: impl Fn() -> dioxus_core::prelude::VirtualDom + Send + Sync + 'static, - ) -> Self { - let app = Arc::new(app); - - let view = crate::LiveViewPool::new(); - - self.push( - Router::with_path(route) - .hoop(salvo::affix::inject(LiveviewApp { - app: app, - pool: Arc::new(view), - })) - .get(index) - .push(Router::with_path("ws").get(connect)), - ) - } - - async fn start(self, address: impl Into) { - let address = address.into(); - - let acceptor = TcpListener::new(address).bind().await; - Server::new(acceptor).serve(self).await; - } -} - -#[handler] -fn index(req: &mut Request, res: &mut Response) { - let base = req.uri().path(); - let title = crate::app_title(); - - res.render(Text::Html(format!( - r#" - - - {title} -
- {glue} - - "#, - glue = crate::interpreter_glue(&format!("{base}/ws")) - ))); -} - -#[handler] -async fn connect( - req: &mut Request, - depot: &mut Depot, - res: &mut Response, -) -> Result<(), StatusError> { - let app = depot.obtain::().unwrap().clone(); - let view = app.pool.clone(); - let app = app.app.clone(); - - WebSocketUpgrade::new() - .upgrade(req, res, |ws| async move { - _ = view - .launch_virtualdom(crate::salvo_socket(ws), move || app()) - .await; - }) - .await -} diff --git a/packages/liveview/src/adapters/warp_adapter.rs b/packages/liveview/src/adapters/warp_adapter.rs deleted file mode 100644 index d2861d80e..000000000 --- a/packages/liveview/src/adapters/warp_adapter.rs +++ /dev/null @@ -1,25 +0,0 @@ -use crate::{LiveViewError, LiveViewSocket}; -use futures_util::{SinkExt, StreamExt}; -use warp::ws::{Message, WebSocket}; - -/// Convert a warp WebSocket into a `LiveViewSocket`. -/// -/// This is required to launch a LiveView app using the warp web framework. -pub fn warp_socket(ws: WebSocket) -> impl LiveViewSocket { - ws.map(transform_rx) - .with(transform_tx) - .sink_map_err(|_| LiveViewError::SendingFailed) -} - -fn transform_rx(message: Result) -> Result, LiveViewError> { - // Destructure the `message` into the buffer we got from warp. - let msg = message - .map_err(|_| LiveViewError::SendingFailed)? - .into_bytes(); - - Ok(msg) -} - -async fn transform_tx(message: Vec) -> Result { - Ok(Message::binary(message)) -} diff --git a/packages/liveview/src/launch.rs b/packages/liveview/src/launch.rs index d008e38cd..de8142a4e 100644 --- a/packages/liveview/src/launch.rs +++ b/packages/liveview/src/launch.rs @@ -3,10 +3,6 @@ use std::any::Any; #[cfg(feature = "axum")] pub type Config = crate::Config; -#[cfg(all(feature = "salvo", not(feature = "axum")))] -pub type Config = crate::Config; -#[cfg(all(feature = "rocket", not(any(feature = "axum", feature = "salvo"))))] -pub type Config = crate::Config>; /// Launches the WebView and runs the event loop, with configuration and root props. pub fn launch( diff --git a/packages/liveview/src/lib.rs b/packages/liveview/src/lib.rs index 74ceff98c..075179d87 100644 --- a/packages/liveview/src/lib.rs +++ b/packages/liveview/src/lib.rs @@ -25,7 +25,7 @@ impl WebsocketRx for T where T: StreamExt String { // If the url starts with a `/`, generate glue which reuses current host let get_ws_url = if url_or_path.starts_with('/') { r#" - let loc = window.location; + let loc = window.location; let new_url = ""; if (loc.protocol === "https:") {{ new_url = "wss:"; @@ -135,7 +135,7 @@ pub fn interpreter_glue(url_or_path: &str) -> String { function __dioxusGetWsUrl(path) {{ {get_ws_url} }} - + var WS_ADDR = __dioxusGetWsUrl("{url_or_path}"); {handle_edits} diff --git a/packages/playwright-tests/liveview/Cargo.toml b/packages/playwright-tests/liveview/Cargo.toml index 851bed97d..ac066735c 100644 --- a/packages/playwright-tests/liveview/Cargo.toml +++ b/packages/playwright-tests/liveview/Cargo.toml @@ -10,4 +10,4 @@ publish = false dioxus = { workspace = true } dioxus-liveview = { workspace = true, features = ["axum"] } tokio = { version = "1.19.2", features = ["full"] } -axum = { version = "0.6.1", features = ["ws"] } +axum = { workspace = true, features = ["ws"] } diff --git a/packages/router/Cargo.toml b/packages/router/Cargo.toml index 3343f1886..57065726d 100644 --- a/packages/router/Cargo.toml +++ b/packages/router/Cargo.toml @@ -39,7 +39,7 @@ web = ["gloo", "web-sys", "wasm-bindgen", "gloo-utils", "js-sys"] fullstack = ["dioxus-fullstack"] [dev-dependencies] -axum = { version = "0.6.1", features = ["ws"] } +axum = { workspace = true, features = ["ws"] } dioxus = { workspace = true, features = ["router" ]} # dioxus-liveview = { workspace = true, features = ["axum"] } dioxus-ssr = { path = "../ssr" } diff --git a/packages/router/examples/simple_routes.rs b/packages/router/examples/simple_routes.rs index deefd35e6..49ff66cce 100644 --- a/packages/router/examples/simple_routes.rs +++ b/packages/router/examples/simple_routes.rs @@ -26,9 +26,7 @@ async fn main() { "/ws", get(move |ws: WebSocketUpgrade| async move { ws.on_upgrade(move |socket| async move { - _ = view - .launch(dioxus_liveview::axum_socket(socket), Route::Home {}) - .await; + _ = view.launch(dioxus_liveview::axum_socket(socket), app).await; }) }), ); @@ -43,11 +41,13 @@ async fn main() { #[cfg(not(feature = "liveview"))] fn main() { - launch(|| { - rsx! { - Router:: {} - } - }) + launch(app) +} + +fn app() -> Element { + rsx! { + Router:: {} + } } #[component] diff --git a/packages/router/src/history/liveview.rs b/packages/router/src/history/liveview.rs index ddeb029fe..478785617 100644 --- a/packages/router/src/history/liveview.rs +++ b/packages/router/src/history/liveview.rs @@ -175,10 +175,8 @@ where let eval_provider = consume_context::>(); let create_eval = Rc::new(move |script: &str| { - eval_provider - .new_evaluator(script.to_string()) - .map(UseEval::new) - }) as Rc Result>; + UseEval::new(eval_provider.new_evaluator(script.to_string())) + }) as Rc UseEval>; // Listen to server actions spawn({ @@ -256,7 +254,7 @@ where history.length, ]; "#, - ).expect("failed to load state").await.expect("serializable state"); + ).await.expect("serializable state"); let (route, state, session, depth) = serde_json::from_value::<( String, Option, @@ -276,7 +274,8 @@ where // Call the updater callback (updater.read().unwrap())(); - create_eval(&format!(r#" + create_eval(&format!( + r#" // this does not trigger a PopState event history.replaceState({state}, "", "{route}"); sessionStorage.setItem("liveview", '{session}'); @@ -287,7 +286,8 @@ where event.state, ]); }}); - "#)).expect("failed to initialize popstate") + "# + )) }; loop { diff --git a/packages/router/src/router_cfg.rs b/packages/router/src/router_cfg.rs index 30dcac10f..a53064208 100644 --- a/packages/router/src/router_cfg.rs +++ b/packages/router/src/router_cfg.rs @@ -1,11 +1,9 @@ -use std::sync::Arc; - use crate::contexts::router::RoutingCallback; use crate::history::HistoryProvider; +use crate::prelude::*; use crate::routable::Routable; use dioxus_lib::prelude::*; - -use crate::prelude::*; +use std::sync::Arc; /// Global configuration options for the router. /// @@ -31,43 +29,6 @@ pub struct RouterConfig { pub(crate) initial_route: Option, } -macro_rules! default_history { - ($initial_route:ident) => { - { - // If we are on wasm32 and the web feature is enabled, use the web history. - #[cfg(all(target_arch = "wasm32", feature = "web"))] - return Box::new(AnyHistoryProviderImplWrapper::new(WebHistory::::default())); - // If we are using dioxus fullstack and the ssr feature is enabled, use the memory history with the initial path set to the current path in fullstack - #[cfg(all(feature = "fullstack", feature = "ssr"))] - return Box::new(AnyHistoryProviderImplWrapper::new(MemoryHistory::::with_initial_path( - dioxus_fullstack::prelude::server_context() - .request_parts() - .unwrap() - .uri - .to_string() - .parse() - .unwrap_or_else(|err| { - tracing::error!("Failed to parse uri: {}", err); - "/" - .parse() - .unwrap_or_else(|err| { - panic!("Failed to parse uri: {}", err); - }) - }), - ))); - // If we are not on wasm32 and the liveview feature is enabled, use the liveview history. - #[cfg(all(feature = "liveview"))] - return Box::new(AnyHistoryProviderImplWrapper::new(LiveviewHistory::new_with_initial_path($initial_route))); - // Otherwise use the memory history. - #[cfg(all( - not(all(target_arch = "wasm32", feature = "web")), - not(all(feature = "liveview", not(target_arch = "wasm32"))), - ))] - Box::new(AnyHistoryProviderImplWrapper::new(MemoryHistory::with_initial_path($initial_route))) - } - }; -} - impl Default for RouterConfig where ::Err: std::fmt::Display, @@ -94,7 +55,7 @@ where )); self.history .take() - .unwrap_or_else(|| default_history!(initial_route)) + .unwrap_or_else(|| default_history(initial_route)) } } @@ -154,3 +115,49 @@ where } } } + +/// Get the default history provider for the current platform. +fn default_history(initial_route: R) -> Box +where + ::Err: std::fmt::Display, +{ + // If we're on the web and have wasm, use the web history provider + if cfg!(all(target_arch = "wasm32", feature = "web")) { + return Box::new(AnyHistoryProviderImplWrapper::new( + WebHistory::::default(), + )); + } + + // If we're using fullstack and server side rendering, use the memory history provider + if cfg!(all(feature = "fullstack", feature = "ssr")) { + return Box::new(AnyHistoryProviderImplWrapper::new( + MemoryHistory::::with_initial_path( + dioxus_fullstack::prelude::server_context() + .request_parts() + .unwrap() + .uri + .to_string() + .parse() + .unwrap_or_else(|err| { + tracing::error!("Failed to parse uri: {}", err); + "/".parse().unwrap_or_else(|err| { + panic!("Failed to parse uri: {}", err); + }) + }), + ), + )); + } + + // If liveview is enabled, use the liveview history provider + if cfg!(feature = "liveview") { + return Box::new(AnyHistoryProviderImplWrapper::new( + LiveviewHistory::new_with_initial_path(initial_route), + )); + } + + // If none of the above, use the memory history provider, which is a decent enough fallback + // Eventually we want to integrate with the mobile history provider, and other platform providers + Box::new(AnyHistoryProviderImplWrapper::new( + MemoryHistory::with_initial_path(initial_route), + )) +} diff --git a/packages/ssr/Cargo.toml b/packages/ssr/Cargo.toml index 89cc10edc..350f81b68 100644 --- a/packages/ssr/Cargo.toml +++ b/packages/ssr/Cargo.toml @@ -15,15 +15,17 @@ generational-box = { workspace = true } askama_escape = "0.10.3" thiserror = "1.0.23" rustc-hash = "1.1.0" -lru = "0.10.0" +lru = { workspace = true } tracing = { workspace = true } -http = "0.2.9" +http = { workspace = true } tokio = { version = "1.28", features = ["fs", "io-util"], optional = true } -async-trait = "0.1.58" -serde_json = { version = "1.0" } +async-trait = { workspace = true } +serde_json = { workspace = true } [dev-dependencies] dioxus = { workspace = true } +dioxus-signals = { workspace = true } + tracing = { workspace = true } fern = { version = "0.6.0", features = ["colored"] } anyhow = "1.0" @@ -31,7 +33,6 @@ argh = "0.1.4" serde = "1.0.120" serde_json = "1.0.61" fs_extra = "1.2.0" -dioxus-signals = { workspace = true } [features] default = [] From 64a321eaccb82aa3c48f3fa225cdbed538e204e1 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Thu, 15 Feb 2024 18:59:57 -0800 Subject: [PATCH 03/17] Get more axum stuff upgraded to 0.7 --- Cargo.lock | 137 ++++++++---------- Cargo.toml | 4 + packages/cli/Cargo.toml | 7 +- packages/cli/src/server/web/hot_reload.rs | 6 +- packages/cli/src/server/web/mod.rs | 5 +- packages/cli/src/server/web/proxy.rs | 13 +- packages/dioxus/Cargo.toml | 3 +- packages/fullstack/Cargo.toml | 21 ++- .../fullstack/examples/axum-auth/Cargo.toml | 5 +- .../fullstack/examples/axum-auth/src/main.rs | 6 +- .../examples/axum-desktop/src/server.rs | 20 +-- .../fullstack/examples/axum-router/Cargo.toml | 3 +- .../examples/axum-router/src/main.rs | 24 ++- .../examples/static-hydrated/src/main.rs | 11 +- packages/fullstack/src/lib.rs | 39 ++--- packages/fullstack/src/render.rs | 3 - packages/fullstack/src/serve_config.rs | 6 +- packages/fullstack/src/server_context.rs | 1 - packages/hot-reload/src/file_watcher.rs | 6 +- packages/liveview/examples/axum.rs | 4 +- packages/liveview/examples/axum_stress.rs | 4 +- .../playwright-tests/liveview/src/main.rs | 4 +- packages/router/benches/incremental.rs | 2 + packages/router/examples/simple_routes.rs | 7 +- packages/router/src/router_cfg.rs | 54 ++++--- 25 files changed, 202 insertions(+), 193 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8fda26cd9..e62368d12 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -608,7 +608,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1236b4b292f6c4d6dc34604bb5120d85c3fe1d1aa596bd5cc52ca054d13e7b9e" dependencies = [ "async-trait", - "axum-core 0.4.3", + "axum-core", "axum-macros", "base64", "bytes", @@ -646,7 +646,7 @@ dependencies = [ "anyhow", "async-trait", "axum", - "axum_session 0.3.5", + "axum_session", "axum_session_auth", "dioxus", "dioxus-fullstack", @@ -661,23 +661,6 @@ dependencies = [ "tower-http", ] -[[package]] -name = "axum-core" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "759fa577a247914fd3f7f76d62972792636412fbfd634cd452f6a385a74d2d2c" -dependencies = [ - "async-trait", - "bytes", - "futures-util", - "http 0.2.11", - "http-body 0.4.6", - "mime", - "rustversion", - "tower-layer", - "tower-service", -] - [[package]] name = "axum-core" version = "0.4.3" @@ -709,6 +692,28 @@ dependencies = [ "tokio", ] +[[package]] +name = "axum-extra" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "895ff42f72016617773af68fb90da2a9677d89c62338ec09162d4909d86fdd8f" +dependencies = [ + "axum", + "axum-core", + "bytes", + "futures-util", + "headers 0.4.0", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "mime", + "pin-project-lite", + "serde", + "tower", + "tower-layer", + "tower-service", +] + [[package]] name = "axum-hello-world" version = "0.1.0" @@ -746,53 +751,27 @@ dependencies = [ [[package]] name = "axum-server" -version = "0.5.1" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447f28c85900215cc1bea282f32d4a2f22d55c5a300afdfbc661c8d6a632e063" +checksum = "c1ad46c3ec4e12f4a4b6835e173ba21c25e484c9d02b49770bf006ce5367c036" dependencies = [ "arc-swap", "bytes", "futures-util", - "http 0.2.11", - "http-body 0.4.6", - "hyper 0.14.28", + "http 1.0.0", + "http-body 1.0.0", + "http-body-util", + "hyper 1.1.0", + "hyper-util", "pin-project-lite", "rustls 0.21.10", - "rustls-pemfile 1.0.4", + "rustls-pemfile 2.1.0", "tokio", "tokio-rustls 0.24.1", + "tower", "tower-service", ] -[[package]] -name = "axum_session" -version = "0.3.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b9a35d2907b706dcd52f875c4f9fe55293ebc03fc5b3c2d8883104c821452b8" -dependencies = [ - "aes-gcm", - "async-trait", - "axum-core 0.3.4", - "base64", - "bytes", - "chrono", - "cookie 0.17.0", - "dashmap", - "futures", - "http 0.2.11", - "http-body 0.4.6", - "rand 0.8.5", - "serde", - "serde_json", - "sqlx", - "thiserror", - "tokio", - "tower-layer", - "tower-service", - "tracing", - "uuid", -] - [[package]] name = "axum_session" version = "0.12.4" @@ -805,7 +784,7 @@ dependencies = [ "base64", "bytes", "chrono", - "cookie 0.18.0", + "cookie", "dashmap", "forwarded-header-value", "futures", @@ -834,8 +813,8 @@ dependencies = [ "anyhow", "async-recursion", "async-trait", - "axum-core 0.4.3", - "axum_session 0.12.4", + "axum-core", + "axum_session", "bytes", "chrono", "dashmap", @@ -1699,21 +1678,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "cookie" -version = "0.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7efb37c3e1ccb1ff97164ad95ac1606e8ccd35b3fa0a7d99a304c7f4a428cc24" -dependencies = [ - "aes-gcm", - "base64", - "percent-encoding", - "rand 0.8.5", - "subtle", - "time", - "version_check", -] - [[package]] name = "cookie" version = "0.18.0" @@ -2285,6 +2249,7 @@ dependencies = [ "anyhow", "atty", "axum", + "axum-extra", "axum-server", "cargo-generate", "cargo_metadata 0.18.1", @@ -2305,7 +2270,7 @@ dependencies = [ "flate2", "fs_extra", "futures-util", - "headers", + "headers 0.3.9", "html_parser", "hyper 1.1.0", "hyper-rustls 0.26.0", @@ -4475,13 +4440,28 @@ checksum = "06683b93020a07e3dbcf5f8c0f6d40080d725bea7936fc01ad345c01b97dc270" dependencies = [ "base64", "bytes", - "headers-core", + "headers-core 0.2.0", "http 0.2.11", "httpdate", "mime", "sha1", ] +[[package]] +name = "headers" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "322106e6bd0cba2d5ead589ddb8150a13d7c4217cf80d7c4f682ca994ccc6aa9" +dependencies = [ + "base64", + "bytes", + "headers-core 0.3.0", + "http 1.0.0", + "httpdate", + "mime", + "sha1", +] + [[package]] name = "headers-core" version = "0.2.0" @@ -4491,6 +4471,15 @@ dependencies = [ "http 0.2.11", ] +[[package]] +name = "headers-core" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54b4a22553d4242c49fddb9ba998a99962b5cc6f22cb5a3482bec22522403ce4" +dependencies = [ + "http 1.0.0", +] + [[package]] name = "heck" version = "0.3.3" diff --git a/Cargo.toml b/Cargo.toml index 9ac28a43c..bfbd72d5d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -107,6 +107,7 @@ manganis = { git = "https://github.com/DioxusLabs/collect-assets", rev = "f98269 lru = "0.12.2" async-trait = "0.1.77" axum = "0.7.0" +axum-server = "0.6.0" tower = "0.4.13" http = "1.0.0" tower-http = "0.5.1" @@ -114,6 +115,9 @@ hyper = "1.0.0" hyper-rustls = "0.26.0" serde_json = "1.0.61" serde = "1.0.61" +axum_session = "0.12.1" +axum_session_auth = "0.12.1" +axum-extra = "0.9.2" # This is a "virtual package" # It is not meant to be published, but is used so "cargo run --example XYZ" works properly diff --git a/packages/cli/Cargo.toml b/packages/cli/Cargo.toml index eaa4c7c8f..049bb195f 100644 --- a/packages/cli/Cargo.toml +++ b/packages/cli/Cargo.toml @@ -32,14 +32,15 @@ tokio = { version = "1.16.1", features = ["fs", "sync", "rt", "macros"] } atty = "0.2.14" chrono = "0.4.19" anyhow = "1" -hyper = {workspace = true} -hyper-rustls = {workspace = true} +hyper = { workspace = true } +hyper-rustls = { workspace = true } indicatif = "0.17.5" subprocess = "0.2.9" rayon = "1.8.0" axum = { workspace = true, features = ["ws"] } -axum-server = { version = "0.5.1", features = ["tls-rustls"] } +axum-server = { workspace = true, features = ["tls-rustls"] } +axum-extra = { workspace = true, features = ["typed-header"] } tower-http = { workspace = true, features = ["full"] } headers = "0.3.7" diff --git a/packages/cli/src/server/web/hot_reload.rs b/packages/cli/src/server/web/hot_reload.rs index 7b47dca4c..d55f1333d 100644 --- a/packages/cli/src/server/web/hot_reload.rs +++ b/packages/cli/src/server/web/hot_reload.rs @@ -1,10 +1,10 @@ +use crate::server::HotReloadState; use axum::{ extract::{ws::Message, WebSocketUpgrade}, response::IntoResponse, - Extension, TypedHeader, + Extension, }; - -use crate::server::HotReloadState; +use axum_extra::TypedHeader; pub async fn hot_reload_handler( ws: WebSocketUpgrade, diff --git a/packages/cli/src/server/web/mod.rs b/packages/cli/src/server/web/mod.rs index 6ae873d1f..245259dba 100644 --- a/packages/cli/src/server/web/mod.rs +++ b/packages/cli/src/server/web/mod.rs @@ -19,6 +19,7 @@ use axum::{ routing::{get, get_service}, Router, }; +use axum_extra::TypedHeader; use axum_server::tls_rustls::RustlsConfig; use dioxus_cli_config::CrateConfig; use dioxus_cli_config::WebHttpsConfig; @@ -298,7 +299,9 @@ async fn setup_router( .body(body) .unwrap() } else { - response.map(|body| body.into()) + response.map(|body| body.try_into().unwrap()) + // response.into_body() + // response.map(|body| body.into()) }; let headers = response.headers_mut(); headers.insert( diff --git a/packages/cli/src/server/web/proxy.rs b/packages/cli/src/server/web/proxy.rs index d5e4a4eeb..3158fa286 100644 --- a/packages/cli/src/server/web/proxy.rs +++ b/packages/cli/src/server/web/proxy.rs @@ -17,6 +17,7 @@ impl ProxyClient { fn new(url: Uri) -> Self { let https = hyper_rustls::HttpsConnectorBuilder::new() .with_native_roots() + .unwrap() .https_or_http() .enable_http1() .build(); @@ -138,7 +139,9 @@ mod test { .unwrap(); assert_eq!(resp.status(), StatusCode::OK); assert_eq!( - hyper::body::to_bytes(resp.into_body()).await.unwrap(), + axum::body::to_bytes(resp.into_body(), usize::MAX) + .await + .unwrap(), "backend: /api" ); @@ -148,7 +151,9 @@ mod test { .unwrap(); assert_eq!(resp.status(), StatusCode::OK); assert_eq!( - hyper::body::to_bytes(resp.into_body()).await.unwrap(), + axum::body::to_bytes(resp.into_body(), usize::MAX) + .await + .unwrap(), "backend: /api/" ); @@ -162,7 +167,9 @@ mod test { .unwrap(); assert_eq!(resp.status(), StatusCode::OK); assert_eq!( - hyper::body::to_bytes(resp.into_body()).await.unwrap(), + axum::body::to_bytes(resp.into_body(), usize::MAX) + .await + .unwrap(), "backend: /api/subpath" ); backend_handle.abort(); diff --git a/packages/dioxus/Cargo.toml b/packages/dioxus/Cargo.toml index 90fb7ea79..fbaed9660 100644 --- a/packages/dioxus/Cargo.toml +++ b/packages/dioxus/Cargo.toml @@ -49,8 +49,9 @@ mobile = ["dioxus-mobile", "dioxus-fullstack?/mobile", "dioxus-config-macro/mobi web = ["dioxus-web", "dioxus-fullstack?/web", "dioxus-config-macro/web", "dioxus-router?/web"] ssr = ["dioxus-ssr", "dioxus-router?/ssr", "dioxus-config-macro/ssr"] liveview = ["dioxus-liveview", "dioxus-config-macro/liveview", "dioxus-router?/liveview"] -axum = ["dioxus-fullstack?/axum", "ssr", "dioxus-liveview?/axum"] +axum = ["dioxus-fullstack?/axum", "dioxus-fullstack?/server", "ssr", "dioxus-liveview?/axum"] tui = ["dioxus-tui", "dioxus-config-macro/tui"] + # This feature just disables the no-renderer-enabled warning third-party-renderer = [] diff --git a/packages/fullstack/Cargo.toml b/packages/fullstack/Cargo.toml index 861457351..b20d5feae 100644 --- a/packages/fullstack/Cargo.toml +++ b/packages/fullstack/Cargo.toml @@ -69,7 +69,24 @@ hot-reload = ["serde_json", "futures-util"] web = ["dioxus-web", "web-sys"] desktop = ["dioxus-desktop"] mobile = ["dioxus-mobile"] -axum = ["dep:axum", "tower-http", "server"] -server = ["server_fn/ssr", "dioxus_server_macro/server", "tokio", "tokio-util", "tokio-stream", "dioxus-ssr", "dioxus-ssr/incremental", "tower", "hyper", "http", "tower-layer", "anymap", "tracing-futures", "pin-project", "thiserror", "dioxus-cli-config"] default-tls = ["server_fn/default-tls"] rustls = ["server_fn/rustls"] +axum = ["dep:axum", "tower-http", "server"] +server = [ + "server_fn/ssr", + "dioxus_server_macro/server", + "tokio", + "tokio-util", + "tokio-stream", + "dioxus-ssr", + "dioxus-ssr/incremental", + "tower", + "hyper", + "http", + "tower-layer", + "anymap", + "tracing-futures", + "pin-project", + "thiserror", + "dioxus-cli-config" +] diff --git a/packages/fullstack/examples/axum-auth/Cargo.toml b/packages/fullstack/examples/axum-auth/Cargo.toml index 90148f083..51c0c96ca 100644 --- a/packages/fullstack/examples/axum-auth/Cargo.toml +++ b/packages/fullstack/examples/axum-auth/Cargo.toml @@ -31,13 +31,14 @@ serde = "1.0.159" execute = "0.2.12" anyhow = "1.0.71" + [dependencies.axum_session] -version = "0.3.0" +workspace = true features = ["sqlite-rustls"] optional = true [dependencies.axum_session_auth] -version = "0.12.0" +workspace = true features = ["sqlite-rustls"] optional = true diff --git a/packages/fullstack/examples/axum-auth/src/main.rs b/packages/fullstack/examples/axum-auth/src/main.rs index b7eb2364a..47269f661 100644 --- a/packages/fullstack/examples/axum-auth/src/main.rs +++ b/packages/fullstack/examples/axum-auth/src/main.rs @@ -44,8 +44,6 @@ fn main() { .await .unwrap(); - //Create the Database table for storing our Session Data. - session_store.initiate().await.unwrap(); User::create_user_tables(&pool).await; // build our application with some routes @@ -67,9 +65,9 @@ fn main() { // run it let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 3000)); + let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); - axum::Server::bind(&addr) - .serve(app.into_make_service()) + axum::serve(listener, app.into_make_service()) .await .unwrap(); }); diff --git a/packages/fullstack/examples/axum-desktop/src/server.rs b/packages/fullstack/examples/axum-desktop/src/server.rs index 759d5799b..31eae03e8 100644 --- a/packages/fullstack/examples/axum-desktop/src/server.rs +++ b/packages/fullstack/examples/axum-desktop/src/server.rs @@ -8,17 +8,19 @@ use dioxus::prelude::*; #[tokio::main] async fn main() { - let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); + let listener = tokio::net::TcpListener::bind("127.0.0.01:8080") + .await + .unwrap(); let _ = PostServerData::register_explicit(); let _ = GetServerData::register_explicit(); - axum::Server::bind(&addr) - .serve( - axum::Router::new() - .register_server_fns("") - .into_make_service(), - ) - .await - .unwrap(); + axum::serve( + listener, + axum::Router::new() + .register_server_fns("") + .into_make_service(), + ) + .await + .unwrap(); } diff --git a/packages/fullstack/examples/axum-router/Cargo.toml b/packages/fullstack/examples/axum-router/Cargo.toml index dfac4be56..e1cb35fab 100644 --- a/packages/fullstack/examples/axum-router/Cargo.toml +++ b/packages/fullstack/examples/axum-router/Cargo.toml @@ -7,7 +7,7 @@ publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -dioxus = { workspace = true, features = ["router"] } +dioxus = { workspace = true, features = ["fullstack", "router"] } axum = { workspace = true, optional = true } tokio = {workspace = true, features = ["full"], optional = true } serde = { version = "1.0.159", features = ["derive"] } @@ -16,3 +16,4 @@ serde = { version = "1.0.159", features = ["derive"] } default = [] server = ["axum", "dioxus/axum"] web = ["dioxus/web"] + diff --git a/packages/fullstack/examples/axum-router/src/main.rs b/packages/fullstack/examples/axum-router/src/main.rs index d03b0c04d..6aed7429d 100644 --- a/packages/fullstack/examples/axum-router/src/main.rs +++ b/packages/fullstack/examples/axum-router/src/main.rs @@ -7,21 +7,17 @@ use dioxus::prelude::*; fn main() { - let config = LaunchBuilder::fullstack(); - #[cfg(feature = "server")] - config - .incremental( - IncrementalRendererConfig::default() - .invalidate_after(std::time::Duration::from_secs(120)), - ) - .launch(); + let cfg = server_only!(dioxus::fullstack::Config::new().incremental( + IncrementalRendererConfig::default().invalidate_after(std::time::Duration::from_secs(120)), + )); - #[cfg(not(feature = "server"))] - config.launch(|| { - rsx! { - Router:: {} - } - }); + LaunchBuilder::fullstack().with_cfg(cfg).launch(app); +} + +fn app() -> Element { + rsx! { + Router:: {} + } } #[derive(Clone, Routable, Debug, PartialEq, serde::Serialize, serde::Deserialize)] diff --git a/packages/fullstack/examples/static-hydrated/src/main.rs b/packages/fullstack/examples/static-hydrated/src/main.rs index 69c81b40e..fb0e20618 100644 --- a/packages/fullstack/examples/static-hydrated/src/main.rs +++ b/packages/fullstack/examples/static-hydrated/src/main.rs @@ -15,7 +15,7 @@ use serde::{Deserialize, Serialize}; #[tokio::main] async fn main() { pre_cache_static_routes_with_props( - &ServerConfig::new_with_router( + &ServeConfig::new_with_router( dioxus_fullstack::router::FullstackRouterConfig::::default(), ) .assets_path("docs") @@ -37,13 +37,11 @@ fn main() { ); } -#[cfg(not(any(feature = "web", feature = "server")))] -fn main() {} - #[derive(Clone, Routable, Debug, PartialEq, Serialize, Deserialize)] enum Route { #[route("/")] Home {}, + #[route("/blog")] Blog, } @@ -72,10 +70,7 @@ fn Home() -> Element { let text = use_signal(|| "...".to_string()); rsx! { - Link { - to: Route::Blog {}, - "Go to blog" - } + Link { to: Route::Blog {}, "Go to blog" } div { h1 { "High-Five counter: {count}" } button { onclick: move |_| count += 1, "Up high!" } diff --git a/packages/fullstack/src/lib.rs b/packages/fullstack/src/lib.rs index 775683828..40e821dc0 100644 --- a/packages/fullstack/src/lib.rs +++ b/packages/fullstack/src/lib.rs @@ -2,7 +2,7 @@ #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")] #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")] #![deny(missing_docs)] -#![cfg_attr(any(docsrs, feature = "nightly-doc"), feature(doc_cfg))] +#![cfg_attr(docsrs, feature(doc_cfg))] pub use once_cell; @@ -10,6 +10,7 @@ mod html_storage; #[cfg(feature = "server")] mod adapters; + // Splitting up the glob export lets us document features required for each adapter #[cfg_attr(docsrs, doc(cfg(feature = "axum")))] #[cfg(feature = "axum")] @@ -21,45 +22,46 @@ pub use adapters::{server_fn_service, ServerFnHandler}; mod config; mod hooks; +pub mod launch; +mod server_fn; #[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))] mod hot_reload; -pub mod launch; pub use config::*; + #[cfg(feature = "server")] mod layer; + #[cfg(feature = "server")] mod render; + #[cfg(feature = "server")] mod serve_config; + #[cfg(feature = "server")] mod server_context; -mod server_fn; /// A prelude of commonly used items in dioxus-fullstack. pub mod prelude { + use crate::hooks; + pub use hooks::{server_cached::server_cached, server_future::use_server_future}; + #[cfg(feature = "axum")] #[cfg_attr(docsrs, doc(cfg(feature = "axum")))] pub use crate::adapters::axum_adapter::*; - use crate::hooks; - #[cfg(not(feature = "server"))] - #[cfg_attr( - any(docsrs, feature = "nightly-doc"), - doc(cfg(not(feature = "server"))) - )] + #[cfg_attr(docsrs, doc(cfg(not(feature = "server"))))] pub use crate::html_storage::deserialize::get_root_props_from_document; + #[cfg(feature = "server")] #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub use crate::layer::{Layer, Service}; #[cfg(all(feature = "server", feature = "router"))] - #[cfg_attr( - any(docsrs, feature = "nightly-doc"), - doc(cfg(all(feature = "server", feature = "router"))) - )] + #[cfg_attr(docsrs, doc(cfg(all(feature = "server", feature = "router"))))] pub use crate::render::pre_cache_static_routes_with_props; + #[cfg(feature = "server")] #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub use crate::render::SSRState; @@ -71,28 +73,27 @@ pub mod prelude { #[cfg(feature = "server")] #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub use crate::serve_config::{ServeConfig, ServeConfigBuilder}; + #[cfg(all(feature = "server", feature = "axum"))] - #[cfg_attr( - any(docsrs, feature = "nightly-doc"), - doc(cfg(all(feature = "server", feature = "axum"))) - )] + #[cfg_attr(docsrs, doc(cfg(all(feature = "server", feature = "axum"))))] pub use crate::server_context::Axum; + #[cfg(feature = "server")] #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub use crate::server_context::{ extract, server_context, DioxusServerContext, FromServerContext, ProvideServerContext, }; pub use crate::server_fn::DioxusServerFn; + #[cfg(feature = "server")] #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub use crate::server_fn::{ServerFnMiddleware, ServerFnTraitObj, ServerFunction}; pub use dioxus_server_macro::*; + #[cfg(feature = "server")] #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub use dioxus_ssr::incremental::IncrementalRendererConfig; pub use server_fn::{self, ServerFn as _, ServerFnError}; - - pub use hooks::{server_cached::server_cached, server_future::use_server_future}; } // // Warn users about overlapping features diff --git a/packages/fullstack/src/render.rs b/packages/fullstack/src/render.rs index 84ca1a6e5..5d71dc497 100644 --- a/packages/fullstack/src/render.rs +++ b/packages/fullstack/src/render.rs @@ -6,7 +6,6 @@ use dioxus_ssr::{ incremental::{IncrementalRendererConfig, RenderFreshness, WrapBody}, Renderer, }; -use serde::Serialize; use std::sync::Arc; use std::sync::RwLock; use tokio::task::spawn_blocking; @@ -28,7 +27,6 @@ impl SsrRendererPool { server_context: &DioxusServerContext, ) -> Result<(RenderFreshness, String), dioxus_ssr::incremental::IncrementalRendererError> { let wrapper = FullstackRenderer { - serialized_props: None, cfg: cfg.clone(), server_context: server_context.clone(), }; @@ -210,7 +208,6 @@ impl SSRState { } struct FullstackRenderer { - serialized_props: Option, cfg: ServeConfig, server_context: DioxusServerContext, } diff --git a/packages/fullstack/src/serve_config.rs b/packages/fullstack/src/serve_config.rs index 62f13156d..88e64eb33 100644 --- a/packages/fullstack/src/serve_config.rs +++ b/packages/fullstack/src/serve_config.rs @@ -1,14 +1,10 @@ #![allow(non_snake_case)] -//! Configeration for how to serve a Dioxus application +//! Configuration for how to serve a Dioxus application -#[cfg(feature = "router")] -use crate::router::*; use std::fs::File; use std::io::Read; use std::path::PathBuf; -use dioxus_lib::prelude::*; - /// A ServeConfig is used to configure how to serve a Dioxus application. It contains information about how to serve static assets, and what content to render with [`dioxus-ssr`]. #[derive(Clone)] pub struct ServeConfigBuilder { diff --git a/packages/fullstack/src/server_context.rs b/packages/fullstack/src/server_context.rs index 2fb06b61f..50e657f40 100644 --- a/packages/fullstack/src/server_context.rs +++ b/packages/fullstack/src/server_context.rs @@ -1,5 +1,4 @@ use crate::html_storage::HTMLData; -pub use server_fn_impl::*; use std::sync::Arc; use std::sync::RwLock; diff --git a/packages/hot-reload/src/file_watcher.rs b/packages/hot-reload/src/file_watcher.rs index 867fbd293..5486af4c0 100644 --- a/packages/hot-reload/src/file_watcher.rs +++ b/packages/hot-reload/src/file_watcher.rs @@ -1,19 +1,17 @@ use std::{ - io::{BufRead, BufReader, Write}, + io::Write, path::PathBuf, str::FromStr, sync::{Arc, Mutex}, }; use crate::HotReloadMsg; -use dioxus_core::Template; use dioxus_rsx::{ hot_reload::{FileMap, FileMapBuildResult, UpdateResult}, HotReloadingContext, }; -use interprocess_docfix::local_socket::{LocalSocketListener, LocalSocketStream}; +use interprocess_docfix::local_socket::LocalSocketListener; use notify::{RecommendedWatcher, RecursiveMode, Watcher}; -use serde::{Deserialize, Serialize}; #[cfg(feature = "file_watcher")] use dioxus_html::HtmlCtx; diff --git a/packages/liveview/examples/axum.rs b/packages/liveview/examples/axum.rs index 213629cae..d015259e9 100644 --- a/packages/liveview/examples/axum.rs +++ b/packages/liveview/examples/axum.rs @@ -23,8 +23,8 @@ async fn main() { println!("Listening on http://{addr}"); - axum::Server::bind(&addr.to_string().parse().unwrap()) - .serve(app.into_make_service()) + let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); + axum::serve(listener, app.into_make_service()) .await .unwrap(); } diff --git a/packages/liveview/examples/axum_stress.rs b/packages/liveview/examples/axum_stress.rs index 6994a634f..80e146eed 100644 --- a/packages/liveview/examples/axum_stress.rs +++ b/packages/liveview/examples/axum_stress.rs @@ -55,8 +55,8 @@ async fn main() { println!("Listening on http://{addr}"); - axum::Server::bind(&addr.to_string().parse().unwrap()) - .serve(app.into_make_service()) + let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); + axum::serve(listener, app.into_make_service()) .await .unwrap(); } diff --git a/packages/playwright-tests/liveview/src/main.rs b/packages/playwright-tests/liveview/src/main.rs index dca0bb735..dd5804b05 100644 --- a/packages/playwright-tests/liveview/src/main.rs +++ b/packages/playwright-tests/liveview/src/main.rs @@ -57,8 +57,8 @@ async fn main() { println!("Listening on http://{addr}"); - axum::Server::bind(&addr.to_string().parse().unwrap()) - .serve(app.into_make_service()) + let listener = tokio::net::TcpListener::bind(&addr).await.unwrap(); + axum::serve(listener, app.into_make_service()) .await .unwrap(); } diff --git a/packages/router/benches/incremental.rs b/packages/router/benches/incremental.rs index 80a6bf384..14a7eadfa 100644 --- a/packages/router/benches/incremental.rs +++ b/packages/router/benches/incremental.rs @@ -45,6 +45,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { }) }) }); + c.bench_function("build 1000 routes no memory cache", |b| { b.to_async(tokio::runtime::Runtime::new().unwrap()) .iter(|| async { @@ -67,6 +68,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { .memory_cache_limit(0) .invalidate_after(Duration::from_secs(10)) .build(); + for id in 0..1000 { render_route( &mut renderer, diff --git a/packages/router/examples/simple_routes.rs b/packages/router/examples/simple_routes.rs index 49ff66cce..64ac0c2ff 100644 --- a/packages/router/examples/simple_routes.rs +++ b/packages/router/examples/simple_routes.rs @@ -33,8 +33,11 @@ async fn main() { println!("Listening on http://{listen_address}"); - axum::Server::bind(&listen_address.to_string().parse().unwrap()) - .serve(app.into_make_service()) + let listener = tokio::net::TcpListener::bind(&listen_address) + .await + .unwrap(); + + axum::serve(listener, app.into_make_service()) .await .unwrap(); } diff --git a/packages/router/src/router_cfg.rs b/packages/router/src/router_cfg.rs index a53064208..f71b7cbf3 100644 --- a/packages/router/src/router_cfg.rs +++ b/packages/router/src/router_cfg.rs @@ -122,38 +122,36 @@ where ::Err: std::fmt::Display, { // If we're on the web and have wasm, use the web history provider - if cfg!(all(target_arch = "wasm32", feature = "web")) { - return Box::new(AnyHistoryProviderImplWrapper::new( - WebHistory::::default(), - )); - } + + #[cfg(all(target_arch = "wasm32", feature = "web"))] + return Box::new(AnyHistoryProviderImplWrapper::new( + WebHistory::::default(), + )); // If we're using fullstack and server side rendering, use the memory history provider - if cfg!(all(feature = "fullstack", feature = "ssr")) { - return Box::new(AnyHistoryProviderImplWrapper::new( - MemoryHistory::::with_initial_path( - dioxus_fullstack::prelude::server_context() - .request_parts() - .unwrap() - .uri - .to_string() - .parse() - .unwrap_or_else(|err| { - tracing::error!("Failed to parse uri: {}", err); - "/".parse().unwrap_or_else(|err| { - panic!("Failed to parse uri: {}", err); - }) - }), - ), - )); - } + #[cfg(all(feature = "fullstack", feature = "ssr"))] + return Box::new(AnyHistoryProviderImplWrapper::new( + MemoryHistory::::with_initial_path( + dioxus_fullstack::prelude::server_context() + .request_parts() + .unwrap() + .uri + .to_string() + .parse() + .unwrap_or_else(|err| { + tracing::error!("Failed to parse uri: {}", err); + "/".parse().unwrap_or_else(|err| { + panic!("Failed to parse uri: {}", err); + }) + }), + ), + )); // If liveview is enabled, use the liveview history provider - if cfg!(feature = "liveview") { - return Box::new(AnyHistoryProviderImplWrapper::new( - LiveviewHistory::new_with_initial_path(initial_route), - )); - } + #[cfg(feature = "liveview")] + return Box::new(AnyHistoryProviderImplWrapper::new( + LiveviewHistory::new_with_initial_path(initial_route), + )); // If none of the above, use the memory history provider, which is a decent enough fallback // Eventually we want to integrate with the mobile history provider, and other platform providers From 3ee4fa8099795fe998f8a3b734da320fc8bc0fb9 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Thu, 15 Feb 2024 19:00:07 -0800 Subject: [PATCH 04/17] Add all targets and all features to check --- .github/workflows/main.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index de7efb060..93877a6a1 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -50,7 +50,7 @@ jobs: cache-all-crates: "true" save-if: ${{ github.ref == 'refs/heads/master' }} - uses: ilammy/setup-nasm@v1 - - run: cargo check --all --examples --tests + - run: cargo check --all --examples --tests --all-features --all-targets test: if: github.event.pull_request.draft == false @@ -110,7 +110,7 @@ jobs: with: cache-all-crates: "true" save-if: ${{ github.ref == 'refs/heads/master' }} - - run: cargo clippy --workspace --examples --tests -- -D warnings + - run: cargo clippy --workspace --examples --tests --all-features --all-targets -- -D warnings # We removed most unsafe that we can, and using nightly doubles our cache size # miri: From 2763adb2d39ffac7ffdcb8f16f9c758be0da4065 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Thu, 15 Feb 2024 19:03:46 -0800 Subject: [PATCH 05/17] clean up workflow, fix some more axum stuff --- .github/workflows/main.yml | 39 ------------------------------ packages/cli/src/server/web/mod.rs | 15 ++++++------ 2 files changed, 7 insertions(+), 47 deletions(-) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 93877a6a1..48fdfddcb 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -112,44 +112,6 @@ jobs: save-if: ${{ github.ref == 'refs/heads/master' }} - run: cargo clippy --workspace --examples --tests --all-features --all-targets -- -D warnings - # We removed most unsafe that we can, and using nightly doubles our cache size - # miri: - # if: github.event.pull_request.draft == false - # name: Miri - # runs-on: ubuntu-latest - # env: - # CARGO_UNSTABLE_SPARSE_REGISTRY: 'true' - # RUSTFLAGS: -Dwarnings - # RUST_BACKTRACE: 1 - # MIRIFLAGS: -Zmiri-tag-gc=1 - # # Change to specific Rust release to pin - # rust_stable: stable - # rust_nightly: nightly-2023-11-16 - # rust_clippy: 1.70.0 - - # steps: - # - uses: actions/checkout@v4 - # - uses: ilammy/setup-nasm@v1 - # - name: Install Rust ${{ env.rust_nightly }} - # uses: dtolnay/rust-toolchain@master - # with: - # toolchain: ${{ env.rust_nightly }} - # components: miri - # - uses: Swatinem/rust-cache@v2 - # with: - # cache-all-crates: "true" - # save-if: ${{ github.ref == 'refs/heads/master' }} - # - name: miri - # # Many of tests in tokio/tests and doctests use #[tokio::test] or - # # #[tokio::main] that calls epoll_create1 that Miri does not support. - # # run: cargo miri test --features full --lib --no-fail-fast - # run: | - # cargo miri test --package dioxus-core -- --exact --nocapture - # cargo miri test --package dioxus-native-core --test miri_native -- --exact --nocapture - # env: - # MIRIFLAGS: -Zmiri-disable-isolation -Zmiri-strict-provenance -Zmiri-retag-fields - # PROPTEST_CASES: 10 - playwright: if: github.event.pull_request.draft == false name: Playwright Tests @@ -200,7 +162,6 @@ jobs: path: playwright-report/ retention-days: 30 - matrix_test: runs-on: ${{ matrix.platform.os }} if: github.event.pull_request.draft == false diff --git a/packages/cli/src/server/web/mod.rs b/packages/cli/src/server/web/mod.rs index 245259dba..bef52efd4 100644 --- a/packages/cli/src/server/web/mod.rs +++ b/packages/cli/src/server/web/mod.rs @@ -20,7 +20,7 @@ use axum::{ Router, }; use axum_extra::TypedHeader; -use axum_server::tls_rustls::RustlsConfig; +use axum_server::{service::SendService, tls_rustls::RustlsConfig}; use dioxus_cli_config::CrateConfig; use dioxus_cli_config::WebHttpsConfig; @@ -316,7 +316,7 @@ async fn setup_router( .service(ServeDir::new(config.out_dir())); // Setup websocket - let mut router = Router::new().route("/_dioxus/ws", get(ws_handler)); + let mut router = Router::new().route("/_dioxus/ws", get(ws_handler.into())); // Setup proxy for proxy_config in config.dioxus_config.web.proxy { @@ -324,7 +324,7 @@ async fn setup_router( } // Route file service - router = router.fallback(get_service(file_service).handle_error( + router = router.fallback(get_service(file_service.into_service()).handle_error( |error: std::io::Error| async move { ( StatusCode::INTERNAL_SERVER_ERROR, @@ -336,7 +336,7 @@ async fn setup_router( router = if let Some(base_path) = config.dioxus_config.web.app.base_path.clone() { let base_path = format!("/{}", base_path.trim_matches('/')); Router::new() - .nest(&base_path, axum::routing::any_service(router)) + .nest(&base_path, axum::routing::any_service(router.into())) .fallback(get(move || { let base_path = base_path.clone(); async move { format!("Outside of the base path: {}", base_path) } @@ -347,7 +347,7 @@ async fn setup_router( // Setup routes router = router - .route("/_dioxus/hot_reload", get(hot_reload_handler)) + .route("/_dioxus/hot_reload", get(hot_reload_handler.into())) .layer(cors) .layer(Extension(ws_reload)); @@ -389,9 +389,8 @@ async fn start_server( .await? } None => { - axum::Server::bind(&addr) - .serve(router.into_make_service()) - .await? + let listener = tokio::net::TcpListener::bind(&addr).await?; + axum::serve(listener, router.into_make_service()).await? } } From 0ef29b7d75a855cb44b3160f153f83f218b8f0ad Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 16 Feb 2024 09:03:35 -0600 Subject: [PATCH 06/17] reorganize fullstack --- .../src/{adapters => }/axum_adapter.rs | 2 +- packages/fullstack/src/config.rs | 2 +- packages/fullstack/src/launch.rs | 1 + packages/fullstack/src/lib.rs | 12 +++------ .../{server_fn.rs => server_fn/collection.rs} | 20 -------------- packages/fullstack/src/server_fn/mod.rs | 24 +++++++++++++++++ .../{adapters/mod.rs => server_fn/service.rs} | 26 ++++++------------- 7 files changed, 39 insertions(+), 48 deletions(-) rename packages/fullstack/src/{adapters => }/axum_adapter.rs (99%) rename packages/fullstack/src/{server_fn.rs => server_fn/collection.rs} (86%) create mode 100644 packages/fullstack/src/server_fn/mod.rs rename packages/fullstack/src/{adapters/mod.rs => server_fn/service.rs} (84%) diff --git a/packages/fullstack/src/adapters/axum_adapter.rs b/packages/fullstack/src/axum_adapter.rs similarity index 99% rename from packages/fullstack/src/adapters/axum_adapter.rs rename to packages/fullstack/src/axum_adapter.rs index e12590bed..c56864728 100644 --- a/packages/fullstack/src/adapters/axum_adapter.rs +++ b/packages/fullstack/src/axum_adapter.rs @@ -70,7 +70,7 @@ use std::sync::RwLock; use crate::{ prelude::*, render::SSRState, serve_config::ServeConfig, server_context::DioxusServerContext, - server_fn::DioxusServerFnRegistry, + server_fn::collection::DioxusServerFnRegistry, }; /// A extension trait with utilities for integrating Dioxus with your Axum router. diff --git a/packages/fullstack/src/config.rs b/packages/fullstack/src/config.rs index 176e7381e..d03c90752 100644 --- a/packages/fullstack/src/config.rs +++ b/packages/fullstack/src/config.rs @@ -124,7 +124,7 @@ impl Config { #[cfg(feature = "axum")] { - use crate::adapters::axum_adapter::{render_handler, DioxusRouterExt}; + use crate::axum_adapter::{render_handler, DioxusRouterExt}; use axum::routing::get; use tower::ServiceBuilder; diff --git a/packages/fullstack/src/launch.rs b/packages/fullstack/src/launch.rs index 70deaa981..f32418f67 100644 --- a/packages/fullstack/src/launch.rs +++ b/packages/fullstack/src/launch.rs @@ -7,6 +7,7 @@ use dioxus_lib::prelude::{Element, VirtualDom}; pub use crate::Config; /// Launch a fullstack app with the given root component, contexts, and config. +#[allow(unused)] pub fn launch( root: fn() -> Element, contexts: Vec Box + Send + Sync>>, diff --git a/packages/fullstack/src/lib.rs b/packages/fullstack/src/lib.rs index 40e821dc0..8ba30a5be 100644 --- a/packages/fullstack/src/lib.rs +++ b/packages/fullstack/src/lib.rs @@ -8,17 +8,13 @@ pub use once_cell; mod html_storage; -#[cfg(feature = "server")] -mod adapters; - -// Splitting up the glob export lets us document features required for each adapter #[cfg_attr(docsrs, doc(cfg(feature = "axum")))] #[cfg(feature = "axum")] -pub use adapters::axum_adapter; +mod axum_adapter; #[cfg_attr(docsrs, doc(cfg(feature = "server")))] #[cfg(feature = "server")] -pub use adapters::{server_fn_service, ServerFnHandler}; +pub use server_fn::service::{server_fn_service, ServerFnHandler}; mod config; mod hooks; @@ -48,7 +44,7 @@ pub mod prelude { #[cfg(feature = "axum")] #[cfg_attr(docsrs, doc(cfg(feature = "axum")))] - pub use crate::adapters::axum_adapter::*; + pub use crate::axum_adapter::*; #[cfg(not(feature = "server"))] #[cfg_attr(docsrs, doc(cfg(not(feature = "server"))))] @@ -87,7 +83,7 @@ pub mod prelude { #[cfg(feature = "server")] #[cfg_attr(docsrs, doc(cfg(feature = "server")))] - pub use crate::server_fn::{ServerFnMiddleware, ServerFnTraitObj, ServerFunction}; + pub use crate::server_fn::collection::{ServerFnMiddleware, ServerFnTraitObj, ServerFunction}; pub use dioxus_server_macro::*; #[cfg(feature = "server")] diff --git a/packages/fullstack/src/server_fn.rs b/packages/fullstack/src/server_fn/collection.rs similarity index 86% rename from packages/fullstack/src/server_fn.rs rename to packages/fullstack/src/server_fn/collection.rs index cdfff266e..6ecc1b78f 100644 --- a/packages/fullstack/src/server_fn.rs +++ b/packages/fullstack/src/server_fn/collection.rs @@ -171,23 +171,3 @@ pub enum ServerRegistrationFnError { #[error("The server function registry is poisoned: {0}")] Poisoned(String), } - -/// Defines a "server function." A server function can be called from the server or the client, -/// but the body of its code will only be run on the server, i.e., if a crate feature `ssr` is enabled. -/// -/// Server functions are created using the `server` macro. -/// -/// The set of server functions -/// can be queried on the server for routing purposes by calling [server_fn::ServerFunctionRegistry::get]. -/// -/// Technically, the trait is implemented on a type that describes the server function's arguments, not the function itself. -pub trait DioxusServerFn: server_fn::ServerFn<()> { - /// Registers the server function, allowing the client to query it by URL. - #[cfg(feature = "server")] - #[cfg_attr(docsrs, doc(cfg(feature = "server")))] - fn register_explicit() -> Result<(), server_fn::ServerFnError> { - Self::register_in_explicit::() - } -} - -impl DioxusServerFn for T where T: server_fn::ServerFn<()> {} diff --git a/packages/fullstack/src/server_fn/mod.rs b/packages/fullstack/src/server_fn/mod.rs new file mode 100644 index 000000000..e2637b23b --- /dev/null +++ b/packages/fullstack/src/server_fn/mod.rs @@ -0,0 +1,24 @@ +#[cfg(feature = "server")] +pub(crate)mod collection; +#[cfg(feature = "server")] +pub mod service; + +/// Defines a "server function." A server function can be called from the server or the client, +/// but the body of its code will only be run on the server, i.e., if a crate feature `ssr` is enabled. +/// +/// Server functions are created using the `server` macro. +/// +/// The set of server functions +/// can be queried on the server for routing purposes by calling [server_fn::ServerFunctionRegistry::get]. +/// +/// Technically, the trait is implemented on a type that describes the server function's arguments, not the function itself. +pub trait DioxusServerFn: server_fn::ServerFn<()> { + /// Registers the server function, allowing the client to query it by URL. + #[cfg(feature = "server")] + #[cfg_attr(docsrs, doc(cfg(feature = "server")))] + fn register_explicit() -> Result<(), server_fn::ServerFnError> { + Self::register_in_explicit::() + } +} + +impl DioxusServerFn for T where T: server_fn::ServerFn<()> {} diff --git a/packages/fullstack/src/adapters/mod.rs b/packages/fullstack/src/server_fn/service.rs similarity index 84% rename from packages/fullstack/src/adapters/mod.rs rename to packages/fullstack/src/server_fn/service.rs index 3e8c9321f..22f1a176c 100644 --- a/packages/fullstack/src/adapters/mod.rs +++ b/packages/fullstack/src/server_fn/service.rs @@ -1,29 +1,19 @@ -//! # Adapters -//! Adapters for different web frameworks. -//! -//! Each adapter provides a set of utilities that is ergonomic to use with the framework. -//! -//! Each framework has utilies for some or all of the following: -//! - Server functions -//! - A generic way to register server functions -//! - A way to register server functions with a custom handler that allows users to pass in a custom [`crate::server_context::DioxusServerContext`] based on the state of the server framework. -//! - A way to register static WASM files that is accepts [`crate::serve_config::ServeConfig`] -//! - A hot reloading web socket that intigrates with [`dioxus-hot-reload`](https://crates.io/crates/dioxus-hot-reload) +//! # Server function Service -#[cfg(feature = "axum")] -pub mod axum_adapter; +//! This module defines a service that can be used to handle server functions. use http::StatusCode; use server_fn::{Encoding, Payload}; use std::sync::{Arc, RwLock}; -type MyBody = axum::body::Body; - +use crate::server_fn::collection::MIDDLEWARE; use crate::{ layer::{BoxedService, Service}, prelude::{DioxusServerContext, ProvideServerContext}, }; +type AxumBody = axum::body::Body; + /// Create a server function handler with the given server context and server function. pub fn server_fn_service( context: DioxusServerContext, @@ -31,7 +21,7 @@ pub fn server_fn_service( ) -> crate::layer::BoxedService { let prefix = function.prefix().to_string(); let url = function.url().to_string(); - if let Some(middleware) = crate::server_fn::MIDDLEWARE.get(&(&prefix, &url)) { + if let Some(middleware) = MIDDLEWARE.get(&(&prefix, &url)) { let mut service = BoxedService(Box::new(ServerFnHandler::new(context, function))); for middleware in middleware { service = middleware.layer(service); @@ -66,11 +56,11 @@ impl ServerFnHandler { impl Service for ServerFnHandler { fn run( &mut self, - req: http::Request, + req: http::Request, ) -> std::pin::Pin< Box< dyn std::future::Future< - Output = Result, server_fn::ServerFnError>, + Output = Result, server_fn::ServerFnError>, > + Send, >, > { From 6879507652189ab5573e1312ab0183c570c46c8c Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 16 Feb 2024 09:09:35 -0600 Subject: [PATCH 07/17] fix a few warnings when checking with all features --- packages/router/src/history/mod.rs | 16 ---------------- packages/router/src/routable.rs | 26 -------------------------- packages/router/src/router_cfg.rs | 1 + 3 files changed, 1 insertion(+), 42 deletions(-) diff --git a/packages/router/src/history/mod.rs b/packages/router/src/history/mod.rs index 18ee092e6..8043184fb 100644 --- a/packages/router/src/history/mod.rs +++ b/packages/router/src/history/mod.rs @@ -289,17 +289,9 @@ pub trait HistoryProvider { pub(crate) trait AnyHistoryProvider { fn parse_route(&self, route: &str) -> Result, String>; - #[must_use] - fn accepts_type_id(&self, type_id: &std::any::TypeId) -> bool; - #[must_use] fn current_route(&self) -> Rc; - #[must_use] - fn current_prefix(&self) -> Option { - None - } - #[must_use] fn can_go_back(&self) -> bool { true @@ -359,19 +351,11 @@ where .map(|route| Rc::new(route) as Rc) } - fn accepts_type_id(&self, type_id: &std::any::TypeId) -> bool { - type_id == &std::any::TypeId::of::() - } - fn current_route(&self) -> Rc { let route = self.inner.current_route(); Rc::new(route) } - fn current_prefix(&self) -> Option { - self.inner.current_prefix() - } - fn can_go_back(&self) -> bool { self.inner.can_go_back() } diff --git a/packages/router/src/routable.rs b/packages/router/src/routable.rs index 7037355ca..fc4a86ad1 100644 --- a/packages/router/src/routable.rs +++ b/packages/router/src/routable.rs @@ -311,32 +311,6 @@ pub trait Routable: FromStr + Display + Clone + 'static { } } -trait RoutableFactory { - type Err: Display; - type Routable: Routable + FromStr; -} - -impl RoutableFactory for R -where - ::Err: Display, -{ - type Err = ::Err; - type Routable = R; -} - -trait RouteRenderable: Display + 'static { - fn render(&self, level: usize) -> Element; -} - -impl RouteRenderable for R -where - ::Err: Display, -{ - fn render(&self, level: usize) -> Element { - self.render(level) - } -} - /// A type erased map of the site structure. #[derive(Debug, Clone, PartialEq)] pub struct SiteMapSegment { diff --git a/packages/router/src/router_cfg.rs b/packages/router/src/router_cfg.rs index f71b7cbf3..559c72393 100644 --- a/packages/router/src/router_cfg.rs +++ b/packages/router/src/router_cfg.rs @@ -117,6 +117,7 @@ where } /// Get the default history provider for the current platform. +#[allow(unreachable_code, unused)] fn default_history(initial_route: R) -> Box where ::Err: std::fmt::Display, From e7452121578e7050f18bc4c74959f48901cfcd6b Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 16 Feb 2024 12:17:01 -0600 Subject: [PATCH 08/17] bump server functions --- Cargo.lock | 134 +++++++--- packages/fullstack/Cargo.toml | 7 +- packages/fullstack/src/axum_adapter.rs | 208 ++++++++------- packages/fullstack/src/config.rs | 2 +- packages/fullstack/src/layer.rs | 86 ------- packages/fullstack/src/lib.rs | 19 +- packages/fullstack/src/server_fn/mod.rs | 24 -- packages/fullstack/src/server_fn/service.rs | 154 ----------- packages/liveview/Cargo.toml | 1 + packages/liveview/src/launch.rs | 1 - packages/liveview/src/lib.rs | 1 + packages/server-macro/Cargo.toml | 6 +- packages/server-macro/src/lib.rs | 270 ++++++-------------- 13 files changed, 297 insertions(+), 616 deletions(-) delete mode 100644 packages/fullstack/src/layer.rs delete mode 100644 packages/fullstack/src/server_fn/mod.rs delete mode 100644 packages/fullstack/src/server_fn/service.rs diff --git a/Cargo.lock b/Cargo.lock index e62368d12..a3b1b7b32 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -622,6 +622,7 @@ dependencies = [ "matchit", "memchr", "mime", + "multer", "percent-encoding", "pin-project-lite", "rustversion", @@ -2692,7 +2693,7 @@ dependencies = [ "dioxus-router-macro", "dioxus-ssr", "gloo", - "gloo-utils", + "gloo-utils 0.1.7", "js-sys", "serde", "serde_json", @@ -4086,7 +4087,7 @@ dependencies = [ "gloo-render", "gloo-storage", "gloo-timers", - "gloo-utils", + "gloo-utils 0.1.7", "gloo-worker", ] @@ -4096,7 +4097,7 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "82b7ce3c05debe147233596904981848862b068862e9ec3e34be446077190d3f" dependencies = [ - "gloo-utils", + "gloo-utils 0.1.7", "js-sys", "serde", "wasm-bindgen", @@ -4142,7 +4143,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85725d90bf0ed47063b3930ef28e863658a7905989e9929a8708aab74a1d5e7f" dependencies = [ "gloo-events", - "gloo-utils", + "gloo-utils 0.1.7", "serde", "serde-wasm-bindgen", "serde_urlencoded", @@ -4151,26 +4152,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "gloo-net" -version = "0.2.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9902a044653b26b99f7e3693a42f171312d9be8b26b5697bd1e43ad1f8a35e10" -dependencies = [ - "futures-channel", - "futures-core", - "futures-sink", - "gloo-utils", - "js-sys", - "pin-project", - "serde", - "serde_json", - "thiserror", - "wasm-bindgen", - "wasm-bindgen-futures", - "web-sys", -] - [[package]] name = "gloo-net" version = "0.3.1" @@ -4180,7 +4161,28 @@ dependencies = [ "futures-channel", "futures-core", "futures-sink", - "gloo-utils", + "gloo-utils 0.1.7", + "http 0.2.11", + "js-sys", + "pin-project", + "serde", + "serde_json", + "thiserror", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", +] + +[[package]] +name = "gloo-net" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43aaa242d1239a8822c15c645f02166398da4f8b5c4bae795c1f5b44e9eee173" +dependencies = [ + "futures-channel", + "futures-core", + "futures-sink", + "gloo-utils 0.2.0", "http 0.2.11", "js-sys", "pin-project", @@ -4208,7 +4210,7 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5d6ab60bf5dbfd6f0ed1f7843da31b41010515c745735c970e821945ca91e480" dependencies = [ - "gloo-utils", + "gloo-utils 0.1.7", "js-sys", "serde", "serde_json", @@ -4240,6 +4242,19 @@ dependencies = [ "web-sys", ] +[[package]] +name = "gloo-utils" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa" +dependencies = [ + "js-sys", + "serde", + "serde_json", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "gloo-worker" version = "0.2.1" @@ -4249,7 +4264,7 @@ dependencies = [ "anymap2", "bincode", "gloo-console", - "gloo-utils", + "gloo-utils 0.1.7", "js-sys", "serde", "wasm-bindgen", @@ -6008,6 +6023,24 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "multer" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a15d522be0a9c3e46fd2632e272d178f56387bdb5c9fbb3a36c649062e9b5219" +dependencies = [ + "bytes", + "encoding_rs", + "futures-util", + "http 1.0.0", + "httparse", + "log", + "memchr", + "mime", + "spin 0.9.8", + "version_check", +] + [[package]] name = "names" version = "0.14.0" @@ -7608,6 +7641,7 @@ dependencies = [ "js-sys", "log", "mime", + "mime_guess", "native-tls", "once_cell", "percent-encoding", @@ -8097,6 +8131,15 @@ dependencies = [ "serde", ] +[[package]] +name = "send_wrapper" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0b0ec5f1c1ca621c432a25813d8d60c88abe6d3e08a3eb9cf37d97a0fe3d73" +dependencies = [ + "futures-core", +] + [[package]] name = "separator" version = "0.4.1" @@ -8260,49 +8303,58 @@ dependencies = [ [[package]] name = "server_fn" -version = "0.5.7" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c265de965fe48e09ad8899d0ab1ffebdfa1a9914e4de5ff107b07bd94cf7541" +checksum = "97fab54d9dd2d7e9eba4efccac41d2ec3e7c6e9973d14c0486d662a32662320c" dependencies = [ - "ciborium", + "axum", + "bytes", "const_format", - "gloo-net 0.2.6", + "dashmap", + "futures", + "gloo-net 0.5.0", + "http 1.0.0", + "http-body-util", + "hyper 1.1.0", "inventory", "js-sys", - "lazy_static", "once_cell", - "proc-macro2", - "quote", "reqwest", + "send_wrapper", "serde", "serde_json", "serde_qs", "server_fn_macro_default", - "syn 2.0.49", "thiserror", + "tower", + "tower-layer", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "wasm-streams", + "web-sys", "xxhash-rust", ] [[package]] name = "server_fn_macro" -version = "0.5.7" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f77000541a62ceeec01eef3ee0f86c155c33dac5fae750ad04a40852c6d5469a" +checksum = "3be6011b586a0665546b7ced372b0be690d9e005d3f8524795da2843274d7720" dependencies = [ "const_format", - "proc-macro-error", + "convert_case 0.6.0", "proc-macro2", "quote", - "serde", "syn 2.0.49", "xxhash-rust", ] [[package]] name = "server_fn_macro_default" -version = "0.5.7" +version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a3353f22e2bcc451074d4feaa37317d9d17dff11d4311928384734ea17ab9ca" +checksum = "752ed78ec49132d154b922cf5ab6485680cab039a75740c48ea2db621ad481da" dependencies = [ "server_fn_macro", "syn 2.0.49", diff --git a/packages/fullstack/Cargo.toml b/packages/fullstack/Cargo.toml index b20d5feae..d80f7caf7 100644 --- a/packages/fullstack/Cargo.toml +++ b/packages/fullstack/Cargo.toml @@ -12,9 +12,8 @@ resolver = "2" [dependencies] # server functions -server_fn = { version = "0.5.2", default-features = false } -dioxus_server_macro = { workspace = true } - +server_fn = { version = "0.6.5", features = ["json", "url", "browser"], default-features = false } +dioxus_server_macro = { workspace = true, version = "0.6.5", default-features = false } # axum axum = { workspace = true, features = ["ws", "macros"], default-features = false, optional = true } @@ -71,7 +70,7 @@ desktop = ["dioxus-desktop"] mobile = ["dioxus-mobile"] default-tls = ["server_fn/default-tls"] rustls = ["server_fn/rustls"] -axum = ["dep:axum", "tower-http", "server"] +axum = ["dep:axum", "tower-http", "server", "server_fn/axum", "dioxus_server_macro/axum"] server = [ "server_fn/ssr", "dioxus_server_macro/server", diff --git a/packages/fullstack/src/axum_adapter.rs b/packages/fullstack/src/axum_adapter.rs index c56864728..40df37083 100644 --- a/packages/fullstack/src/axum_adapter.rs +++ b/packages/fullstack/src/axum_adapter.rs @@ -57,61 +57,25 @@ use axum::{ body::{self, Body}, extract::State, - handler::Handler, http::{Request, Response, StatusCode}, response::IntoResponse, routing::{get, post}, Router, }; use dioxus_lib::prelude::VirtualDom; -use server_fn::{Encoding, ServerFunctionRegistry}; +use server_fn::error::NoCustomError; +use server_fn::error::ServerFnErrorSerde; use std::sync::Arc; use std::sync::RwLock; +use axum::routing::*; +use http::header::*; use crate::{ prelude::*, render::SSRState, serve_config::ServeConfig, server_context::DioxusServerContext, - server_fn::collection::DioxusServerFnRegistry, }; /// A extension trait with utilities for integrating Dioxus with your Axum router. pub trait DioxusRouterExt { - /// Registers server functions with a custom handler function. This allows you to pass custom context to your server functions by generating a [`DioxusServerContext`] from the request. - /// - /// # Example - /// ```rust - /// use dioxus_lib::prelude::*; - /// use dioxus_fullstack::prelude::*; - /// - /// #[tokio::main] - /// async fn main() { - /// let addr = std::net::SocketAddr::from(([127, 0, 0, 1], 8080)); - /// axum::Server::bind(&addr) - /// .serve( - /// axum::Router::new() - /// .register_server_fns_with_handler("", |func| { - /// move |req: Request| async move { - /// let (parts, body) = req.into_parts(); - /// let parts: Arc = Arc::new(parts.into()); - /// let server_context = DioxusServerContext::new(parts.clone()); - /// server_fn_handler(server_context, func.clone(), parts, body).await - /// } - /// }) - /// .into_make_service(), - /// ) - /// .await - /// .unwrap(); - /// } - /// ``` - fn register_server_fns_with_handler( - self, - server_fn_route: &'static str, - handler: impl FnMut(server_fn::ServerFnTraitObj<()>) -> H, - ) -> Self - where - H: Handler, - T: 'static, - S: Clone + Send + Sync + 'static; - /// Registers server functions with the default handler. This handler function will pass an empty [`DioxusServerContext`] to your server functions. /// /// # Example @@ -133,7 +97,7 @@ pub trait DioxusRouterExt { /// .unwrap(); /// } /// ``` - fn register_server_fns(self, server_fn_route: &'static str) -> Self; + fn register_server_fns(self) -> Self; /// Register the web RSX hot reloading endpoint. This will enable hot reloading for your application in debug mode when you call [`dioxus_hot_reload::hot_reload_init`]. /// @@ -218,7 +182,6 @@ pub trait DioxusRouterExt { /// ``` fn serve_dioxus_application( self, - server_fn_route: &'static str, cfg: impl Into, build_virtual_dom: impl Fn() -> VirtualDom + Send + Sync + 'static, ) -> Self; @@ -228,51 +191,20 @@ impl DioxusRouterExt for Router where S: Send + Sync + Clone + 'static, { - fn register_server_fns_with_handler( - self, - server_fn_route: &'static str, - mut handler: impl FnMut(server_fn::ServerFnTraitObj<()>) -> H, - ) -> Self - where - H: Handler, - T: 'static, - S: Clone + Send + Sync + 'static, - { - let mut router = self; - for server_fn_path in DioxusServerFnRegistry::paths_registered() { - let func = DioxusServerFnRegistry::get(server_fn_path).unwrap(); - let full_route = format!("{server_fn_route}/{server_fn_path}"); - match func.encoding() { - Encoding::Url | Encoding::Cbor => { - router = router.route(&full_route, post(handler(func))); - } - Encoding::GetJSON | Encoding::GetCBOR => { - router = router.route(&full_route, get(handler(func))); - } - } - } - router - } + fn register_server_fns(mut self) -> Self { + use http::method::Method; - fn register_server_fns(self, server_fn_route: &'static str) -> Self { - self.register_server_fns_with_handler(server_fn_route, |func| { - move |req: Request| { - let mut service = crate::server_fn_service(Default::default(), func); - async move { - let (req, body) = req.into_parts(); - let req = Request::from_parts(req, body); - let res = service.run(req); - match res.await { - Ok(res) => Ok::<_, std::convert::Infallible>(res.map(|b| b.into())), - Err(e) => { - let mut res = Response::new(Body::from(e.to_string())); - *res.status_mut() = StatusCode::INTERNAL_SERVER_ERROR; - Ok(res) - } - } - } - } - }) + for (path, method) in server_fn::axum::server_fn_paths() { + let handler = move |req| handle_server_fns_inner(path, ||{}, req); + self = match method { + Method::GET => self.route(path, get(handler)), + Method::POST => self.route(path, post(handler)), + Method::PUT => self.route(path, put(handler)), + _ => todo!() + }; + } + + self } fn serve_static_assets(mut self, assets_path: impl Into) -> Self { @@ -317,7 +249,6 @@ where fn serve_dioxus_application( self, - server_fn_route: &'static str, cfg: impl Into, build_virtual_dom: impl Fn() -> VirtualDom + Send + Sync + 'static, ) -> Self { @@ -327,7 +258,7 @@ where // Add server functions and render index.html self.serve_static_assets(cfg.assets_path.clone()) .connect_hot_reload() - .register_server_fns(server_fn_route) + .register_server_fns() .fallback(get(render_handler).with_state((cfg, Arc::new(build_virtual_dom), ssr_state))) } @@ -516,3 +447,104 @@ pub async fn hot_reload_handler(ws: axum::extract::WebSocketUpgrade) -> impl Int } }) } + +fn get_local_pool() -> tokio_util::task::LocalPoolHandle { + use once_cell::sync::OnceCell; + static LOCAL_POOL: OnceCell = OnceCell::new(); + LOCAL_POOL + .get_or_init(|| { + tokio_util::task::LocalPoolHandle::new( + std::thread::available_parallelism() + .map(Into::into) + .unwrap_or(1), + ) + }) + .clone() +} + +/// A handler for Dioxus server functions. This will run the server function and return the result. +async fn handle_server_fns_inner( + path: &str, + additional_context: impl Fn() + 'static + Clone + Send, + req: Request, +) -> impl IntoResponse { + use server_fn::middleware::Service; + + let (tx, rx) = tokio::sync::oneshot::channel(); + let path_string = path.to_string(); + + get_local_pool().spawn_pinned(move || async move { + let (parts, body) = req.into_parts(); + let req = Request::from_parts(parts.clone(), body); + + + let res = if let Some(mut service) = + server_fn::axum::get_server_fn_service(&path_string) + { + + let server_context = DioxusServerContext::new(Arc::new(RwLock::new(parts))); + additional_context(); + + // store Accepts and Referrer in case we need them for redirect (below) + let accepts_html = req + .headers() + .get(ACCEPT) + .and_then(|v| v.to_str().ok()) + .map(|v| v.contains("text/html")) + .unwrap_or(false); + let referrer = req.headers().get(REFERER).cloned(); + + // actually run the server fn + let mut res = service.run(req).await; + + + // it it accepts text/html (i.e., is a plain form post) and doesn't already have a + // Location set, then redirect to to Referer + if accepts_html { + if let Some(referrer) = referrer { + let has_location = res.headers().get(LOCATION).is_some(); + if !has_location { + *res.status_mut() = StatusCode::FOUND; + res.headers_mut().insert(LOCATION, referrer); + } + } + } + + // apply the response parts from the server context to the response + let mut res_options = server_context.response_parts_mut().unwrap(); + res.headers_mut().extend(res_options.headers.drain()); + + Ok(res) + } else { + Response::builder().status(StatusCode::BAD_REQUEST).body( + { + #[cfg(target_family = "wasm")] + { + Body::from(format!( + "No server function found for path: {path_string}\nYou may need to explicitly register the server function with `register_explicit`, rebuild your wasm binary to update a server function link or make sure the prefix your server and client use for server functions match.", + )) + } + #[cfg(not(target_family = "wasm"))] + { + Body::from(format!( + "No server function found for path: {path_string}\nYou may need to rebuild your wasm binary to update a server function link or make sure the prefix your server and client use for server functions match.", + )) + } + } + ) + } + .expect("could not build Response"); + + _ = tx.send(res); + }); + + rx.await.unwrap_or_else(|e| { + ( + StatusCode::INTERNAL_SERVER_ERROR, + ServerFnError::::ServerError(e.to_string()) + .ser() + .unwrap_or_default(), + ) + .into_response() + }) +} \ No newline at end of file diff --git a/packages/fullstack/src/config.rs b/packages/fullstack/src/config.rs index d03c90752..a0f7211c6 100644 --- a/packages/fullstack/src/config.rs +++ b/packages/fullstack/src/config.rs @@ -129,7 +129,7 @@ impl Config { use tower::ServiceBuilder; let ssr_state = SSRState::new(&cfg); - let router = axum::Router::new().register_server_fns(server_fn_route); + let router = axum::Router::new().register_server_fns(); #[cfg(not(any(feature = "desktop", feature = "mobile")))] let router = router .serve_static_assets(cfg.assets_path.clone()) diff --git a/packages/fullstack/src/layer.rs b/packages/fullstack/src/layer.rs deleted file mode 100644 index 82d0226cb..000000000 --- a/packages/fullstack/src/layer.rs +++ /dev/null @@ -1,86 +0,0 @@ -use std::pin::Pin; -use tracing_futures::Instrument; - -use http::{Request, Response}; - -/// A layer that wraps a service. This can be used to add additional information to the request, or response on top of some other service -pub trait Layer: Send + Sync + 'static { - /// Wrap a boxed service with this layer - fn layer(&self, inner: BoxedService) -> BoxedService; -} - -impl Layer for L -where - L: tower_layer::Layer + Sync + Send + 'static, - L::Service: Service + Send + 'static, -{ - fn layer(&self, inner: BoxedService) -> BoxedService { - BoxedService(Box::new(self.layer(inner))) - } -} - -type MyBody = axum::body::Body; - -/// A service is a function that takes a request and returns an async response -pub trait Service { - /// Run the service and produce a future that resolves to a response - fn run( - &mut self, - req: http::Request, - ) -> Pin< - Box< - dyn std::future::Future, server_fn::ServerFnError>> - + Send, - >, - >; -} - -impl Service for S -where - S: tower::Service, Response = Response>, - S::Future: Send + 'static, - S::Error: Into, -{ - fn run( - &mut self, - req: http::Request, - ) -> Pin< - Box< - dyn std::future::Future, server_fn::ServerFnError>> - + Send, - >, - > { - let fut = self.call(req).instrument(tracing::trace_span!( - "service", - "{}", - std::any::type_name::() - )); - Box::pin(async move { fut.await.map_err(|err| err.into()) }) - } -} - -/// A boxed service is a type-erased service that can be used without knowing the underlying type -pub struct BoxedService(pub Box); - -impl tower::Service> for BoxedService { - type Response = http::Response; - type Error = server_fn::ServerFnError; - type Future = Pin< - Box< - dyn std::future::Future< - Output = Result, server_fn::ServerFnError>, - > + Send, - >, - >; - - fn poll_ready( - &mut self, - _cx: &mut std::task::Context<'_>, - ) -> std::task::Poll> { - Ok(()).into() - } - - fn call(&mut self, req: Request) -> Self::Future { - self.0.run(req) - } -} diff --git a/packages/fullstack/src/lib.rs b/packages/fullstack/src/lib.rs index 8ba30a5be..d13fcb695 100644 --- a/packages/fullstack/src/lib.rs +++ b/packages/fullstack/src/lib.rs @@ -12,21 +12,14 @@ mod html_storage; #[cfg(feature = "axum")] mod axum_adapter; -#[cfg_attr(docsrs, doc(cfg(feature = "server")))] -#[cfg(feature = "server")] -pub use server_fn::service::{server_fn_service, ServerFnHandler}; - mod config; mod hooks; pub mod launch; -mod server_fn; #[cfg(all(debug_assertions, feature = "hot-reload", feature = "server"))] mod hot_reload; pub use config::*; -#[cfg(feature = "server")] -mod layer; #[cfg(feature = "server")] mod render; @@ -50,10 +43,6 @@ pub mod prelude { #[cfg_attr(docsrs, doc(cfg(not(feature = "server"))))] pub use crate::html_storage::deserialize::get_root_props_from_document; - #[cfg(feature = "server")] - #[cfg_attr(docsrs, doc(cfg(feature = "server")))] - pub use crate::layer::{Layer, Service}; - #[cfg(all(feature = "server", feature = "router"))] #[cfg_attr(docsrs, doc(cfg(all(feature = "server", feature = "router"))))] pub use crate::render::pre_cache_static_routes_with_props; @@ -79,17 +68,13 @@ pub mod prelude { pub use crate::server_context::{ extract, server_context, DioxusServerContext, FromServerContext, ProvideServerContext, }; - pub use crate::server_fn::DioxusServerFn; - - #[cfg(feature = "server")] - #[cfg_attr(docsrs, doc(cfg(feature = "server")))] - pub use crate::server_fn::collection::{ServerFnMiddleware, ServerFnTraitObj, ServerFunction}; - pub use dioxus_server_macro::*; #[cfg(feature = "server")] #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub use dioxus_ssr::incremental::IncrementalRendererConfig; + pub use server_fn::{self, ServerFn as _, ServerFnError}; + pub use dioxus_server_macro::*; } // // Warn users about overlapping features diff --git a/packages/fullstack/src/server_fn/mod.rs b/packages/fullstack/src/server_fn/mod.rs deleted file mode 100644 index e2637b23b..000000000 --- a/packages/fullstack/src/server_fn/mod.rs +++ /dev/null @@ -1,24 +0,0 @@ -#[cfg(feature = "server")] -pub(crate)mod collection; -#[cfg(feature = "server")] -pub mod service; - -/// Defines a "server function." A server function can be called from the server or the client, -/// but the body of its code will only be run on the server, i.e., if a crate feature `ssr` is enabled. -/// -/// Server functions are created using the `server` macro. -/// -/// The set of server functions -/// can be queried on the server for routing purposes by calling [server_fn::ServerFunctionRegistry::get]. -/// -/// Technically, the trait is implemented on a type that describes the server function's arguments, not the function itself. -pub trait DioxusServerFn: server_fn::ServerFn<()> { - /// Registers the server function, allowing the client to query it by URL. - #[cfg(feature = "server")] - #[cfg_attr(docsrs, doc(cfg(feature = "server")))] - fn register_explicit() -> Result<(), server_fn::ServerFnError> { - Self::register_in_explicit::() - } -} - -impl DioxusServerFn for T where T: server_fn::ServerFn<()> {} diff --git a/packages/fullstack/src/server_fn/service.rs b/packages/fullstack/src/server_fn/service.rs deleted file mode 100644 index 22f1a176c..000000000 --- a/packages/fullstack/src/server_fn/service.rs +++ /dev/null @@ -1,154 +0,0 @@ -//! # Server function Service - -//! This module defines a service that can be used to handle server functions. - -use http::StatusCode; -use server_fn::{Encoding, Payload}; -use std::sync::{Arc, RwLock}; - -use crate::server_fn::collection::MIDDLEWARE; -use crate::{ - layer::{BoxedService, Service}, - prelude::{DioxusServerContext, ProvideServerContext}, -}; - -type AxumBody = axum::body::Body; - -/// Create a server function handler with the given server context and server function. -pub fn server_fn_service( - context: DioxusServerContext, - function: server_fn::ServerFnTraitObj<()>, -) -> crate::layer::BoxedService { - let prefix = function.prefix().to_string(); - let url = function.url().to_string(); - if let Some(middleware) = MIDDLEWARE.get(&(&prefix, &url)) { - let mut service = BoxedService(Box::new(ServerFnHandler::new(context, function))); - for middleware in middleware { - service = middleware.layer(service); - } - service - } else { - BoxedService(Box::new(ServerFnHandler::new(context, function))) - } -} - -#[derive(Clone)] -/// A default handler for server functions. It will deserialize the request body, call the server function, and serialize the response. -pub struct ServerFnHandler { - server_context: DioxusServerContext, - function: server_fn::ServerFnTraitObj<()>, -} - -impl ServerFnHandler { - /// Create a new server function handler with the given server context and server function. - pub fn new( - server_context: impl Into, - function: server_fn::ServerFnTraitObj<()>, - ) -> Self { - let server_context = server_context.into(); - Self { - server_context, - function, - } - } -} - -impl Service for ServerFnHandler { - fn run( - &mut self, - req: http::Request, - ) -> std::pin::Pin< - Box< - dyn std::future::Future< - Output = Result, server_fn::ServerFnError>, - > + Send, - >, - > { - let Self { - server_context, - function, - } = self.clone(); - Box::pin(async move { - let query = req.uri().query().unwrap_or_default().as_bytes().to_vec(); - let (parts, body) = req.into_parts(); - let body = axum::body::to_bytes(body, usize::MAX).await?.to_vec(); - let headers = &parts.headers; - let accept_header = headers.get("Accept").cloned(); - let parts = Arc::new(RwLock::new(parts)); - - // Because the future returned by `server_fn_handler` is `Send`, and the future returned by this function must be send, we need to spawn a new runtime - let pool = get_local_pool(); - let result = pool - .spawn_pinned({ - let function = function.clone(); - let mut server_context = server_context.clone(); - server_context.parts = parts; - move || async move { - let data = match function.encoding() { - Encoding::Url | Encoding::Cbor => &body, - Encoding::GetJSON | Encoding::GetCBOR => &query, - }; - let server_function_future = function.call((), data); - let server_function_future = ProvideServerContext::new( - server_function_future, - server_context.clone(), - ); - server_function_future.await - } - }) - .await?; - let mut res = http::Response::builder(); - - // Set the headers from the server context - let parts = server_context.response_parts().unwrap(); - *res.headers_mut().expect("empty headers should be valid") = parts.headers.clone(); - - let serialized = result?; - // if this is Accept: application/json then send a serialized JSON response - let accept_header = accept_header.as_ref().and_then(|value| value.to_str().ok()); - if accept_header == Some("application/json") - || accept_header - == Some( - "application/\ - x-www-form-urlencoded", - ) - || accept_header == Some("application/cbor") - { - res = res.status(StatusCode::OK); - } - - Ok(match serialized { - Payload::Binary(data) => { - res = res.header("Content-Type", "application/cbor"); - res.body(data.into())? - } - Payload::Url(data) => { - res = res.header( - "Content-Type", - "application/\ - x-www-form-urlencoded", - ); - res.body(data.into())? - } - Payload::Json(data) => { - res = res.header("Content-Type", "application/json"); - res.body(data.into())? - } - }) - }) - } -} - -fn get_local_pool() -> tokio_util::task::LocalPoolHandle { - use once_cell::sync::OnceCell; - static LOCAL_POOL: OnceCell = OnceCell::new(); - LOCAL_POOL - .get_or_init(|| { - tokio_util::task::LocalPoolHandle::new( - std::thread::available_parallelism() - .map(Into::into) - .unwrap_or(1), - ) - }) - .clone() -} diff --git a/packages/liveview/Cargo.toml b/packages/liveview/Cargo.toml index e01e6d3dd..6e7173e18 100644 --- a/packages/liveview/Cargo.toml +++ b/packages/liveview/Cargo.toml @@ -43,6 +43,7 @@ dioxus = { workspace = true } [features] default = ["hot-reload"] +axum = ["dep:axum"] hot-reload = ["dioxus-hot-reload"] [[example]] diff --git a/packages/liveview/src/launch.rs b/packages/liveview/src/launch.rs index de8142a4e..994e32769 100644 --- a/packages/liveview/src/launch.rs +++ b/packages/liveview/src/launch.rs @@ -1,7 +1,6 @@ use dioxus_core::*; use std::any::Any; -#[cfg(feature = "axum")] pub type Config = crate::Config; /// Launches the WebView and runs the event loop, with configuration and root props. diff --git a/packages/liveview/src/lib.rs b/packages/liveview/src/lib.rs index 075179d87..9ed7b85e8 100644 --- a/packages/liveview/src/lib.rs +++ b/packages/liveview/src/lib.rs @@ -15,6 +15,7 @@ mod config; mod eval; mod events; pub use config::*; +#[cfg(feature = "axum")] pub mod launch; pub trait WebsocketTx: SinkExt {} diff --git a/packages/server-macro/Cargo.toml b/packages/server-macro/Cargo.toml index 0234a5373..52c6975ff 100644 --- a/packages/server-macro/Cargo.toml +++ b/packages/server-macro/Cargo.toml @@ -17,11 +17,13 @@ proc-macro2 = "^1.0.63" quote = "^1.0.26" syn = { version = "2", features = ["full"] } convert_case = "^0.6.0" -server_fn_macro = "^0.5.2" +server_fn_macro = "^0.6.5" [lib] proc-macro = true [features] -default = [] +actix = ["server_fn_macro/actix"] +axum = ["server_fn_macro/axum"] +nightly = ["server_fn_macro/nightly"] server = ["server_fn_macro/ssr"] diff --git a/packages/server-macro/src/lib.rs b/packages/server-macro/src/lib.rs index 0f1908851..497297950 100644 --- a/packages/server-macro/src/lib.rs +++ b/packages/server-macro/src/lib.rs @@ -2,209 +2,83 @@ #![doc(html_logo_url = "https://avatars.githubusercontent.com/u/79236386")] #![doc(html_favicon_url = "https://avatars.githubusercontent.com/u/79236386")] -use convert_case::{Case, Converter}; -use proc_macro::TokenStream; -use proc_macro2::Literal; -use quote::{ToTokens, __private::TokenStream as TokenStream2}; -use server_fn_macro::*; -use syn::{ - parse::{Parse, ParseStream}, - Ident, ItemFn, Token, -}; +//! This crate contains the dioxus implementation of the #[macro@crate::server] macro without additional context from the server. +//! See the [server_fn_macro] crate for more information. -/// Declares that a function is a [server function](https://dioxuslabs.com/learn/0.4/reference/fullstack/server_functions). This means that -/// its body will only run on the server, i.e., when the `ssr` feature is enabled. +use proc_macro::TokenStream; +use server_fn_macro::server_macro_impl; +use syn::__private::ToTokens; + +/// Declares that a function is a [server function](https://docs.rs/server_fn/). +/// This means that its body will only run on the server, i.e., when the `ssr` +/// feature is enabled on this crate. /// -/// If you call a server function from the client (i.e., when the `csr` or `hydrate` features -/// are enabled), it will instead make a network request to the server. -/// -/// You can specify one, two, or three arguments to the server function: -/// 1. *Optional*: A type name that will be used to identify and register the server function -/// (e.g., `MyServerFn`). -/// 2. *Optional*: A URL prefix at which the function will be mounted when it’s registered -/// (e.g., `"/api"`). Defaults to `"/"`. -/// 3. *Optional*: either `"Cbor"` (specifying that it should use the binary `cbor` format for -/// serialization), `"Url"` (specifying that it should be use a URL-encoded form-data string). -/// Defaults to `"Url"`. If you want to use this server function -/// using Get instead of Post methods, the encoding must be `"GetCbor"` or `"GetJson"`. -/// -/// The server function itself can take any number of arguments, each of which should be serializable -/// and deserializable with `serde`. Optionally, its first argument can be a [DioxusServerContext](https::/docs.rs/dioxus-fullstack/latest/dixous_server/prelude/struct.DioxusServerContext.html), -/// which will be injected *on the server side.* This can be used to inject the raw HTTP request or other -/// server-side context into the server function. -/// -/// ```ignore -/// # use dioxus_fullstack::prelude::*; use serde::{Serialize, Deserialize}; -/// # #[derive(Serialize, Deserialize)] -/// # pub struct Post { } -/// #[server(ReadPosts, "/api")] -/// pub async fn read_posts(how_many: u8, query: String) -> Result, ServerFnError> { -/// // do some work on the server to access the database -/// # unimplemented!() +/// ## Usage +/// ```rust,ignore +/// #[server] +/// pub async fn blog_posts( +/// category: String, +/// ) -> Result, ServerFnError> { +/// let posts = load_posts(&category).await?; +/// // maybe do some other work +/// Ok(posts) /// } /// ``` /// -/// Note the following: -/// - **Server functions must be `async`.** Even if the work being done inside the function body -/// can run synchronously on the server, from the client’s perspective it involves an asynchronous -/// function call. -/// - **Server functions must return `Result`.** Even if the work being done -/// inside the function body can’t fail, the processes of serialization/deserialization and the -/// network call are fallible. -/// - **Return types must implement [`Serialize`](https://docs.rs/serde/latest/serde/trait.Serialize.html).** -/// This should be fairly obvious: we have to serialize arguments to send them to the server, and we -/// need to deserialize the result to return it to the client. -/// - **Arguments must be implement [`Serialize`](https://docs.rs/serde/latest/serde/trait.Serialize.html) -/// and [`DeserializeOwned`](https://docs.rs/serde/latest/serde/de/trait.DeserializeOwned.html).** -/// They are serialized as an `application/x-www-form-urlencoded` -/// form data using [`serde_urlencoded`](https://docs.rs/serde_urlencoded/latest/serde_urlencoded/) or as `application/cbor` -/// using [`cbor`](https://docs.rs/cbor/latest/cbor/). -/// - **The [DioxusServerContext](https::/docs.rs/dioxus-fullstack/latest/dixous_server/prelude/struct.DioxusServerContext.html) comes from the server.** Optionally, the first argument of a server function -/// can be a [DioxusServerContext](https::/docs.rs/dioxus-fullstack/latest/dixous_server/prelude/struct.DioxusServerContext.html). This scope can be used to inject dependencies like the HTTP request -/// or response or other server-only dependencies, but it does *not* have access to reactive state that exists in the client. +/// ## Named Arguments +/// +/// You can any combination of the following named arguments: +/// - `name`: sets the identifier for the server function’s type, which is a struct created +/// to hold the arguments (defaults to the function identifier in PascalCase) +/// - `prefix`: a prefix at which the server function handler will be mounted (defaults to `/api`) +/// - `endpoint`: specifies the exact path at which the server function handler will be mounted, +/// relative to the prefix (defaults to the function name followed by unique hash) +/// - `input`: the encoding for the arguments (defaults to `PostUrl`) +/// - `output`: the encoding for the response (defaults to `Json`) +/// - `client`: a custom `Client` implementation that will be used for this server fn +/// - `encoding`: (legacy, may be deprecated in future) specifies the encoding, which may be one +/// of the following (not case sensitive) +/// - `"Url"`: `POST` request with URL-encoded arguments and JSON response +/// - `"GetUrl"`: `GET` request with URL-encoded arguments and JSON response +/// - `"Cbor"`: `POST` request with CBOR-encoded arguments and response +/// - `"GetCbor"`: `GET` request with URL-encoded arguments and CBOR response +/// - `req` and `res` specify the HTTP request and response types to be used on the server (these +/// should usually only be necessary if you are integrating with a server other than Actix/Axum) +/// ```rust,ignore +/// #[server( +/// name = SomeStructName, +/// prefix = "/my_api", +/// endpoint = "my_fn", +/// input = Cbor, +/// output = Json +/// )] +/// pub async fn my_wacky_server_fn(input: Vec) -> Result { +/// todo!() +/// } +/// +/// // expands to +/// #[derive(Deserialize, Serialize)] +/// struct SomeStructName { +/// input: Vec +/// } +/// +/// impl ServerFn for SomeStructName { +/// const PATH: &'static str = "/my_api/my_fn"; +/// +/// // etc. +/// } +/// ``` #[proc_macro_attribute] pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream { - // before we pass this off to the server function macro, we apply extractors and middleware - let mut function: syn::ItemFn = match syn::parse(s).map_err(|e| e.to_compile_error()) { - Ok(f) => f, - Err(e) => return e.into(), - }; - - // extract all #[middleware] attributes - let mut middlewares: Vec = vec![]; - function.attrs.retain(|attr| { - if attr.meta.path().is_ident("middleware") { - if let Ok(middleware) = attr.parse_args() { - middlewares.push(middleware); - false - } else { - true - } - } else { - true - } - }); - - let ItemFn { - attrs, - vis, - sig, - block, - } = function; - let mapped_body = quote::quote! { - #(#attrs)* - #vis #sig { - #block - } - }; - - let server_fn_path: syn::Path = syn::parse_quote!(::dioxus::fullstack::prelude::server_fn); - let trait_obj_wrapper: syn::Type = - syn::parse_quote!(::dioxus::fullstack::prelude::ServerFnTraitObj); - let mut args: ServerFnArgs = match syn::parse(args) { - Ok(args) => args, - Err(e) => return e.to_compile_error().into(), - }; - if args.struct_name.is_none() { - let upper_cammel_case_name = Converter::new() - .from_case(Case::Snake) - .to_case(Case::UpperCamel) - .convert(sig.ident.to_string()); - args.struct_name = Some(Ident::new(&upper_cammel_case_name, sig.ident.span())); - } - let struct_name = args.struct_name.as_ref().unwrap(); - match server_macro_impl( - quote::quote!(#args), - mapped_body, - trait_obj_wrapper, - None, - Some(server_fn_path.clone()), - ) { - Err(e) => e.to_compile_error().into(), - Ok(tokens) => quote::quote! { - #tokens - #[cfg(feature = "server")] - #server_fn_path::inventory::submit! { - ::dioxus::fullstack::prelude::ServerFnMiddleware { - prefix: #struct_name::PREFIX, - url: #struct_name::URL, - middleware: || vec![ - #( - std::sync::Arc::new(#middlewares), - ),* - ] - } - } - } - .to_token_stream() - .into(), - } -} - -#[derive(Debug)] -struct Middleware { - expr: syn::Expr, -} - -impl ToTokens for Middleware { - fn to_tokens(&self, tokens: &mut TokenStream2) { - let expr = &self.expr; - tokens.extend(quote::quote! { - #expr - }); - } -} - -impl Parse for Middleware { - fn parse(input: syn::parse::ParseStream) -> syn::Result { - let arg: syn::Expr = input.parse()?; - Ok(Middleware { expr: arg }) - } -} - -struct ServerFnArgs { - struct_name: Option, - _comma: Option, - prefix: Option, - _comma2: Option, - encoding: Option, - _comma3: Option, - fn_path: Option, -} - -impl ToTokens for ServerFnArgs { - fn to_tokens(&self, tokens: &mut TokenStream2) { - let struct_name = self.struct_name.as_ref().map(|s| quote::quote! { #s, }); - let prefix = self.prefix.as_ref().map(|p| quote::quote! { #p, }); - let encoding = self.encoding.as_ref().map(|e| quote::quote! { #e, }); - let fn_path = self.fn_path.as_ref().map(|f| quote::quote! { #f, }); - tokens.extend(quote::quote! { - #struct_name - #prefix - #encoding - #fn_path - }) - } -} - -impl Parse for ServerFnArgs { - fn parse(input: ParseStream) -> syn::Result { - let struct_name = input.parse()?; - let _comma = input.parse()?; - let prefix = input.parse()?; - let _comma2 = input.parse()?; - let encoding = input.parse()?; - let _comma3 = input.parse()?; - let fn_path = input.parse()?; - - Ok(Self { - struct_name, - _comma, - prefix, - _comma2, - encoding, - _comma3, - fn_path, - }) - } + match server_macro_impl( + args.into(), + s.into(), + Some(syn::parse_quote!(server_fn)), + "/api", + None, + None, + ) { + Err(e) => e.to_compile_error().into(), + Ok(s) => s.to_token_stream().into(), + } } From 194d90e66f51bf7c8b970d477d3efbac04a0decc Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 16 Feb 2024 12:39:36 -0600 Subject: [PATCH 09/17] fix a few CLI errors --- packages/cli/src/server/web/mod.rs | 2 +- packages/cli/src/server/web/proxy.rs | 18 ++++++++++-------- .../fullstack/examples/axum-auth/src/main.rs | 2 +- .../examples/axum-desktop/src/server.rs | 4 ++-- .../examples/static-hydrated/src/main.rs | 2 +- packages/server-macro/Cargo.toml | 1 - 6 files changed, 15 insertions(+), 14 deletions(-) diff --git a/packages/cli/src/server/web/mod.rs b/packages/cli/src/server/web/mod.rs index bef52efd4..115310916 100644 --- a/packages/cli/src/server/web/mod.rs +++ b/packages/cli/src/server/web/mod.rs @@ -336,7 +336,7 @@ async fn setup_router( router = if let Some(base_path) = config.dioxus_config.web.app.base_path.clone() { let base_path = format!("/{}", base_path.trim_matches('/')); Router::new() - .nest(&base_path, axum::routing::any_service(router.into())) + .route(&base_path, axum::routing::any_service(router.into())) .fallback(get(move || { let base_path = base_path.clone(); async move { format!("Outside of the base path: {}", base_path) } diff --git a/packages/cli/src/server/web/proxy.rs b/packages/cli/src/server/web/proxy.rs index 3158fa286..facb9dce8 100644 --- a/packages/cli/src/server/web/proxy.rs +++ b/packages/cli/src/server/web/proxy.rs @@ -4,12 +4,13 @@ use dioxus_cli_config::WebProxyConfig; use anyhow::Context; use axum::{http::StatusCode, routing::any, Router}; use hyper::{Request, Response, Uri}; +use hyper::client::legacy::Client; use axum::body::Body as MyBody; #[derive(Debug, Clone)] struct ProxyClient { - inner: hyper::Client>, + inner: Client>, url: Uri, } @@ -22,7 +23,7 @@ impl ProxyClient { .enable_http1() .build(); Self { - inner: hyper::Client::builder().build(https), + inner: Client::builder().build(https), url, } } @@ -98,6 +99,7 @@ mod test { use super::*; use axum::{extract::Path, Router}; + use axum_server::Server; fn setup_servers( mut config: WebProxyConfig, @@ -110,13 +112,13 @@ mod test { "/*path", any(|path: Path| async move { format!("backend: {}", path.0) }), ); - let backend_server = axum::Server::bind(&"127.0.0.1:0".parse().unwrap()) + let backend_server = Server::bind(&"127.0.0.1:0".parse().unwrap()) .serve(backend_router.into_make_service()); let backend_addr = backend_server.local_addr(); let backend_handle = tokio::spawn(async move { backend_server.await.unwrap() }); config.backend = format!("http://{}{}", backend_addr, config.backend); let router = super::add_proxy(Router::new(), &config); - let server = axum::Server::bind(&"127.0.0.1:0".parse().unwrap()) + let server = Server::bind("127.0.0.1:0".parse().unwrap()) .serve(router.unwrap().into_make_service()); let server_addr = server.local_addr(); let server_handle = tokio::spawn(async move { server.await.unwrap() }); @@ -132,8 +134,8 @@ mod test { // So in day to day usage, use `http://localhost:8000/api` instead! backend: path, }; - let (backend_handle, server_handle, server_addr) = setup_servers(config); - let resp = hyper::Client::new() + let (backend_handle, server_handle, server_addr) = setup_servers(config).await; + let resp = Client::new() .get(format!("http://{}/api", server_addr).parse().unwrap()) .await .unwrap(); @@ -145,7 +147,7 @@ mod test { "backend: /api" ); - let resp = hyper::Client::new() + let resp = Client::new() .get(format!("http://{}/api/", server_addr).parse().unwrap()) .await .unwrap(); @@ -157,7 +159,7 @@ mod test { "backend: /api/" ); - let resp = hyper::Client::new() + let resp = Client::new() .get( format!("http://{}/api/subpath", server_addr) .parse() diff --git a/packages/fullstack/examples/axum-auth/src/main.rs b/packages/fullstack/examples/axum-auth/src/main.rs index 47269f661..e1638e1b6 100644 --- a/packages/fullstack/examples/axum-auth/src/main.rs +++ b/packages/fullstack/examples/axum-auth/src/main.rs @@ -49,7 +49,7 @@ fn main() { // build our application with some routes let app = Router::new() // Server side render the application, serve static assets, and register server functions - .serve_dioxus_application("", ServeConfig::builder().build(), || { + .serve_dioxus_application(ServeConfig::builder().build(), || { VirtualDom::new(app) }) .layer( diff --git a/packages/fullstack/examples/axum-desktop/src/server.rs b/packages/fullstack/examples/axum-desktop/src/server.rs index 31eae03e8..933f44227 100644 --- a/packages/fullstack/examples/axum-desktop/src/server.rs +++ b/packages/fullstack/examples/axum-desktop/src/server.rs @@ -12,8 +12,8 @@ async fn main() { .await .unwrap(); - let _ = PostServerData::register_explicit(); - let _ = GetServerData::register_explicit(); + let _ = register_explicit::(); + let _ = register_explicit::(); axum::serve( listener, diff --git a/packages/fullstack/examples/static-hydrated/src/main.rs b/packages/fullstack/examples/static-hydrated/src/main.rs index fb0e20618..c3c988e49 100644 --- a/packages/fullstack/examples/static-hydrated/src/main.rs +++ b/packages/fullstack/examples/static-hydrated/src/main.rs @@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "server")] #[tokio::main] async fn main() { - pre_cache_static_routes_with_props( + pre_cache_static_routes( &ServeConfig::new_with_router( dioxus_fullstack::router::FullstackRouterConfig::::default(), ) diff --git a/packages/server-macro/Cargo.toml b/packages/server-macro/Cargo.toml index 52c6975ff..29988789b 100644 --- a/packages/server-macro/Cargo.toml +++ b/packages/server-macro/Cargo.toml @@ -23,7 +23,6 @@ server_fn_macro = "^0.6.5" proc-macro = true [features] -actix = ["server_fn_macro/actix"] axum = ["server_fn_macro/axum"] nightly = ["server_fn_macro/nightly"] server = ["server_fn_macro/ssr"] From 30af55927531ddafea87a7e2e7973a57e7b799a5 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 16 Feb 2024 14:19:36 -0600 Subject: [PATCH 10/17] add tracing to server function registration --- packages/fullstack/src/axum_adapter.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/fullstack/src/axum_adapter.rs b/packages/fullstack/src/axum_adapter.rs index 40df37083..3fc4a138b 100644 --- a/packages/fullstack/src/axum_adapter.rs +++ b/packages/fullstack/src/axum_adapter.rs @@ -195,6 +195,7 @@ where use http::method::Method; for (path, method) in server_fn::axum::server_fn_paths() { + tracing::trace!("Registering server function: {} {}", method, path); let handler = move |req| handle_server_fns_inner(path, ||{}, req); self = match method { Method::GET => self.route(path, get(handler)), From e7d8a25d17a7573c32ca0f356e7bbbd9d4c939dd Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 16 Feb 2024 14:55:44 -0600 Subject: [PATCH 11/17] get the dioxus CLI compiling --- Cargo.lock | 1 + packages/cli/Cargo.toml | 1 + packages/cli/src/server/web/hot_reload.rs | 2 -- packages/cli/src/server/web/mod.rs | 20 ++++++++------------ packages/cli/src/server/web/proxy.rs | 23 +++++++++++++---------- packages/fullstack/src/axum_adapter.rs | 10 +++++----- packages/fullstack/src/lib.rs | 3 +-- packages/server-macro/src/lib.rs | 22 +++++++++++----------- 8 files changed, 40 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index a3b1b7b32..3946586d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2275,6 +2275,7 @@ dependencies = [ "html_parser", "hyper 1.1.0", "hyper-rustls 0.26.0", + "hyper-util", "ignore", "indicatif", "interprocess-docfix", diff --git a/packages/cli/Cargo.toml b/packages/cli/Cargo.toml index 049bb195f..4ea8613fb 100644 --- a/packages/cli/Cargo.toml +++ b/packages/cli/Cargo.toml @@ -33,6 +33,7 @@ atty = "0.2.14" chrono = "0.4.19" anyhow = "1" hyper = { workspace = true } +hyper-util = "0.1.3" hyper-rustls = { workspace = true } indicatif = "0.17.5" subprocess = "0.2.9" diff --git a/packages/cli/src/server/web/hot_reload.rs b/packages/cli/src/server/web/hot_reload.rs index d55f1333d..277150fb1 100644 --- a/packages/cli/src/server/web/hot_reload.rs +++ b/packages/cli/src/server/web/hot_reload.rs @@ -4,11 +4,9 @@ use axum::{ response::IntoResponse, Extension, }; -use axum_extra::TypedHeader; pub async fn hot_reload_handler( ws: WebSocketUpgrade, - _: Option>, Extension(state): Extension, ) -> impl IntoResponse { ws.on_upgrade(|mut socket| async move { diff --git a/packages/cli/src/server/web/mod.rs b/packages/cli/src/server/web/mod.rs index 115310916..6fe190ad7 100644 --- a/packages/cli/src/server/web/mod.rs +++ b/packages/cli/src/server/web/mod.rs @@ -8,7 +8,7 @@ use crate::{ BuildResult, Result, }; use axum::{ - body::{Body, HttpBody}, + body::Body, extract::{ws::Message, Extension, WebSocketUpgrade}, http::{ self, @@ -19,8 +19,7 @@ use axum::{ routing::{get, get_service}, Router, }; -use axum_extra::TypedHeader; -use axum_server::{service::SendService, tls_rustls::RustlsConfig}; +use axum_server::tls_rustls::RustlsConfig; use dioxus_cli_config::CrateConfig; use dioxus_cli_config::WebHttpsConfig; @@ -299,9 +298,7 @@ async fn setup_router( .body(body) .unwrap() } else { - response.map(|body| body.try_into().unwrap()) - // response.into_body() - // response.map(|body| body.into()) + response.into_response() }; let headers = response.headers_mut(); headers.insert( @@ -316,7 +313,7 @@ async fn setup_router( .service(ServeDir::new(config.out_dir())); // Setup websocket - let mut router = Router::new().route("/_dioxus/ws", get(ws_handler.into())); + let mut router = Router::new().route("/_dioxus/ws", get(ws_handler)); // Setup proxy for proxy_config in config.dioxus_config.web.proxy { @@ -324,8 +321,8 @@ async fn setup_router( } // Route file service - router = router.fallback(get_service(file_service.into_service()).handle_error( - |error: std::io::Error| async move { + router = router.fallback(get_service(file_service).handle_error( + |error: std::convert::Infallible| async move { ( StatusCode::INTERNAL_SERVER_ERROR, format!("Unhandled internal error: {}", error), @@ -336,7 +333,7 @@ async fn setup_router( router = if let Some(base_path) = config.dioxus_config.web.app.base_path.clone() { let base_path = format!("/{}", base_path.trim_matches('/')); Router::new() - .route(&base_path, axum::routing::any_service(router.into())) + .route(&base_path, axum::routing::any_service(router)) .fallback(get(move || { let base_path = base_path.clone(); async move { format!("Outside of the base path: {}", base_path) } @@ -347,7 +344,7 @@ async fn setup_router( // Setup routes router = router - .route("/_dioxus/hot_reload", get(hot_reload_handler.into())) + .route("/_dioxus/hot_reload", get(hot_reload_handler)) .layer(cors) .layer(Extension(ws_reload)); @@ -418,7 +415,6 @@ fn get_ip() -> Option { /// Handle websockets async fn ws_handler( ws: WebSocketUpgrade, - _: Option>, Extension(state): Extension>, ) -> impl IntoResponse { ws.on_upgrade(|mut socket| async move { diff --git a/packages/cli/src/server/web/proxy.rs b/packages/cli/src/server/web/proxy.rs index facb9dce8..ee58dabe0 100644 --- a/packages/cli/src/server/web/proxy.rs +++ b/packages/cli/src/server/web/proxy.rs @@ -1,16 +1,19 @@ use crate::Result; use dioxus_cli_config::WebProxyConfig; -use anyhow::Context; +use anyhow::{anyhow, Context}; use axum::{http::StatusCode, routing::any, Router}; use hyper::{Request, Response, Uri}; -use hyper::client::legacy::Client; +use hyper_util::{ + client::legacy::{self, connect::HttpConnector}, + rt::TokioExecutor, +}; use axum::body::Body as MyBody; #[derive(Debug, Clone)] struct ProxyClient { - inner: Client>, + inner: legacy::Client, MyBody>, url: Uri, } @@ -23,12 +26,12 @@ impl ProxyClient { .enable_http1() .build(); Self { - inner: Client::builder().build(https), + inner: legacy::Client::builder(TokioExecutor::new()).build(https), url, } } - async fn send(&self, mut req: Request) -> Result> { + async fn send(&self, mut req: Request) -> Result> { let mut uri_parts = req.uri().clone().into_parts(); uri_parts.authority = self.url.authority().cloned(); uri_parts.scheme = self.url.scheme().cloned(); @@ -36,7 +39,7 @@ impl ProxyClient { self.inner .request(req) .await - .map_err(crate::error::Error::ProxyRequestError) + .map_err(|err| crate::error::Error::Other(anyhow!(err))) } } @@ -112,14 +115,14 @@ mod test { "/*path", any(|path: Path| async move { format!("backend: {}", path.0) }), ); - let backend_server = Server::bind(&"127.0.0.1:0".parse().unwrap()) - .serve(backend_router.into_make_service()); + let backend_server = + Server::bind("127.0.0.1:0".parse().unwrap()).serve(backend_router.into_make_service()); let backend_addr = backend_server.local_addr(); let backend_handle = tokio::spawn(async move { backend_server.await.unwrap() }); config.backend = format!("http://{}{}", backend_addr, config.backend); let router = super::add_proxy(Router::new(), &config); - let server = Server::bind("127.0.0.1:0".parse().unwrap()) - .serve(router.unwrap().into_make_service()); + let server = + Server::bind("127.0.0.1:0".parse().unwrap()).serve(router.unwrap().into_make_service()); let server_addr = server.local_addr(); let server_handle = tokio::spawn(async move { server.await.unwrap() }); (backend_handle, server_handle, server_addr.to_string()) diff --git a/packages/fullstack/src/axum_adapter.rs b/packages/fullstack/src/axum_adapter.rs index 3fc4a138b..3ccef1403 100644 --- a/packages/fullstack/src/axum_adapter.rs +++ b/packages/fullstack/src/axum_adapter.rs @@ -54,6 +54,7 @@ //! } //! ``` +use axum::routing::*; use axum::{ body::{self, Body}, extract::State, @@ -63,12 +64,11 @@ use axum::{ Router, }; use dioxus_lib::prelude::VirtualDom; +use http::header::*; use server_fn::error::NoCustomError; use server_fn::error::ServerFnErrorSerde; use std::sync::Arc; use std::sync::RwLock; -use axum::routing::*; -use http::header::*; use crate::{ prelude::*, render::SSRState, serve_config::ServeConfig, server_context::DioxusServerContext, @@ -196,12 +196,12 @@ where for (path, method) in server_fn::axum::server_fn_paths() { tracing::trace!("Registering server function: {} {}", method, path); - let handler = move |req| handle_server_fns_inner(path, ||{}, req); + let handler = move |req| handle_server_fns_inner(path, || {}, req); self = match method { Method::GET => self.route(path, get(handler)), Method::POST => self.route(path, post(handler)), Method::PUT => self.route(path, put(handler)), - _ => todo!() + _ => todo!(), }; } @@ -548,4 +548,4 @@ async fn handle_server_fns_inner( ) .into_response() }) -} \ No newline at end of file +} diff --git a/packages/fullstack/src/lib.rs b/packages/fullstack/src/lib.rs index d13fcb695..288d32b54 100644 --- a/packages/fullstack/src/lib.rs +++ b/packages/fullstack/src/lib.rs @@ -20,7 +20,6 @@ pub mod launch; mod hot_reload; pub use config::*; - #[cfg(feature = "server")] mod render; @@ -73,8 +72,8 @@ pub mod prelude { #[cfg_attr(docsrs, doc(cfg(feature = "server")))] pub use dioxus_ssr::incremental::IncrementalRendererConfig; - pub use server_fn::{self, ServerFn as _, ServerFnError}; pub use dioxus_server_macro::*; + pub use server_fn::{self, ServerFn as _, ServerFnError}; } // // Warn users about overlapping features diff --git a/packages/server-macro/src/lib.rs b/packages/server-macro/src/lib.rs index 497297950..97f9b0675 100644 --- a/packages/server-macro/src/lib.rs +++ b/packages/server-macro/src/lib.rs @@ -70,15 +70,15 @@ use syn::__private::ToTokens; /// ``` #[proc_macro_attribute] pub fn server(args: proc_macro::TokenStream, s: TokenStream) -> TokenStream { - match server_macro_impl( - args.into(), - s.into(), - Some(syn::parse_quote!(server_fn)), - "/api", - None, - None, - ) { - Err(e) => e.to_compile_error().into(), - Ok(s) => s.to_token_stream().into(), - } + match server_macro_impl( + args.into(), + s.into(), + Some(syn::parse_quote!(server_fn)), + "/api", + None, + None, + ) { + Err(e) => e.to_compile_error().into(), + Ok(s) => s.to_token_stream().into(), + } } From 31a7d2ac04d3cea7913112f2f64ca8a29ee1a25a Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 16 Feb 2024 15:27:48 -0600 Subject: [PATCH 12/17] remove the nightly feature from the server macro crate --- packages/server-macro/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/server-macro/Cargo.toml b/packages/server-macro/Cargo.toml index 29988789b..c2ce13bec 100644 --- a/packages/server-macro/Cargo.toml +++ b/packages/server-macro/Cargo.toml @@ -24,5 +24,4 @@ proc-macro = true [features] axum = ["server_fn_macro/axum"] -nightly = ["server_fn_macro/nightly"] server = ["server_fn_macro/ssr"] From 2952578a2e029a986e3e1211a27c9dfaedd36cb1 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 16 Feb 2024 16:04:12 -0600 Subject: [PATCH 13/17] add a streaming example --- Cargo.lock | 48 ++++++++----------- Cargo.toml | 1 + .../examples/axum-desktop/src/server.rs | 3 +- .../examples/axum-streaming/.gitignore | 4 ++ .../examples/axum-streaming/Cargo.toml | 24 ++++++++++ .../examples/axum-streaming/src/main.rs | 41 ++++++++++++++++ 6 files changed, 92 insertions(+), 29 deletions(-) create mode 100644 packages/fullstack/examples/axum-streaming/.gitignore create mode 100644 packages/fullstack/examples/axum-streaming/Cargo.toml create mode 100644 packages/fullstack/examples/axum-streaming/src/main.rs diff --git a/Cargo.lock b/Cargo.lock index 3946586d3..ed008f445 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -773,6 +773,22 @@ dependencies = [ "tower-service", ] +[[package]] +name = "axum-streaming" +version = "0.1.0" +dependencies = [ + "dioxus", + "futures", + "futures-util", + "once_cell", + "serde", + "simple_logger", + "tokio", + "tracing", + "tracing-subscriber", + "tracing-wasm", +] + [[package]] name = "axum_session" version = "0.12.4" @@ -4562,29 +4578,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "hoot" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df22a4d90f1b0e65fe3e0d6ee6a4608cc4d81f4b2eb3e670f44bb6bde711e452" -dependencies = [ - "httparse", - "log", -] - -[[package]] -name = "hootbin" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "354e60868e49ea1a39c44b9562ad207c4259dc6eabf9863bf3b0f058c55cfdb2" -dependencies = [ - "fastrand 2.0.1", - "hoot", - "serde", - "serde_json", - "thiserror", -] - [[package]] name = "hostname" version = "0.3.1" @@ -7036,9 +7029,9 @@ dependencies = [ [[package]] name = "png" -version = "0.17.11" +version = "0.17.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f6c3c3e617595665b8ea2ff95a86066be38fb121ff920a9c0eb282abcd1da5a" +checksum = "78c2378060fb13acff3ba0325b83442c1d2c44fbb76df481160ddc1687cce160" dependencies = [ "bitflags 1.3.2", "crc32fast", @@ -9952,12 +9945,11 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.9.5" +version = "2.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b52731d03d6bb2fd18289d4028aee361d6c28d44977846793b994b13cdcc64d" +checksum = "11f214ce18d8b2cbe84ed3aa6486ed3f5b285cf8d8fbdbce9f3f767a724adc35" dependencies = [ "base64", - "hootbin", "log", "native-tls", "once_cell", diff --git a/Cargo.toml b/Cargo.toml index bfbd72d5d..89793fb74 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ members = [ "packages/server-macro", "packages/fullstack/examples/axum-hello-world", "packages/fullstack/examples/axum-router", + "packages/fullstack/examples/axum-streaming", "packages/fullstack/examples/axum-desktop", "packages/fullstack/examples/axum-auth", "packages/fullstack/examples/static-hydrated", diff --git a/packages/fullstack/examples/axum-desktop/src/server.rs b/packages/fullstack/examples/axum-desktop/src/server.rs index 933f44227..f14f58abe 100644 --- a/packages/fullstack/examples/axum-desktop/src/server.rs +++ b/packages/fullstack/examples/axum-desktop/src/server.rs @@ -5,6 +5,7 @@ use axum_desktop::*; use dioxus::prelude::*; +use dioxus_fullstack::server_fn::axum::register_explicit; #[tokio::main] async fn main() { @@ -18,7 +19,7 @@ async fn main() { axum::serve( listener, axum::Router::new() - .register_server_fns("") + .register_server_fns() .into_make_service(), ) .await diff --git a/packages/fullstack/examples/axum-streaming/.gitignore b/packages/fullstack/examples/axum-streaming/.gitignore new file mode 100644 index 000000000..21fff11dd --- /dev/null +++ b/packages/fullstack/examples/axum-streaming/.gitignore @@ -0,0 +1,4 @@ +dist +target +static +.dioxus \ No newline at end of file diff --git a/packages/fullstack/examples/axum-streaming/Cargo.toml b/packages/fullstack/examples/axum-streaming/Cargo.toml new file mode 100644 index 000000000..84e5e37e8 --- /dev/null +++ b/packages/fullstack/examples/axum-streaming/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "axum-streaming" +version = "0.1.0" +edition = "2021" +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +dioxus = { workspace = true, features = ["fullstack"] } +serde = "1.0.159" +simple_logger = "4.2.0" +tracing-wasm = "0.2.1" +tracing.workspace = true +tracing-subscriber = "0.3.17" +futures = "0.3.30" +tokio = { workspace = true, optional = true } +futures-util.workspace = true +once_cell = "1.19.0" + +[features] +default = [] +server = ["dioxus/axum", "tokio"] +web = ["dioxus/web"] diff --git a/packages/fullstack/examples/axum-streaming/src/main.rs b/packages/fullstack/examples/axum-streaming/src/main.rs new file mode 100644 index 000000000..fc6e82c02 --- /dev/null +++ b/packages/fullstack/examples/axum-streaming/src/main.rs @@ -0,0 +1,41 @@ +use dioxus::prelude::*; +use futures::StreamExt; +use server_fn::codec::{StreamingText, TextStream}; + +fn app() -> Element { + let mut response = use_signal(String::new); + + rsx! { + button { + onclick: move |_| async move { + response.write().clear(); + if let Ok(stream) = test_stream().await { + response.write().push_str("Stream started\n"); + let mut stream = stream.into_inner(); + while let Some(Ok(text)) = stream.next().await { + response.write().push_str(&text); + } + } + }, + "Start stream" + } + "{response}" + } +} + +#[server(output = StreamingText)] +pub async fn test_stream() -> Result { + let (tx, rx) = futures::channel::mpsc::unbounded(); + tokio::spawn(async move { + loop { + tokio::time::sleep(tokio::time::Duration::from_millis(500)).await; + let _ = tx.unbounded_send(Ok("Hello, world!".to_string())); + } + }); + + Ok(TextStream::new(rx)) +} + +fn main() { + launch(app) +} From 14b4af4bbc1576b8e185521f54912bcdd634b699 Mon Sep 17 00:00:00 2001 From: Evan Almloff Date: Fri, 16 Feb 2024 16:22:13 -0600 Subject: [PATCH 14/17] fix cargo check all features except the router --- .../examples/axum-desktop/Cargo.toml | 2 +- .../examples/axum-desktop/src/server.rs | 2 +- .../examples/static-hydrated/src/main.rs | 29 ++-- packages/fullstack/src/axum_adapter.rs | 5 +- packages/fullstack/src/server_context.rs | 28 ++-- packages/router/benches/incremental.rs | 131 +++++++++--------- packages/router/src/router_cfg.rs | 1 - 7 files changed, 105 insertions(+), 93 deletions(-) diff --git a/packages/fullstack/examples/axum-desktop/Cargo.toml b/packages/fullstack/examples/axum-desktop/Cargo.toml index d789b48e5..bae2a9241 100644 --- a/packages/fullstack/examples/axum-desktop/Cargo.toml +++ b/packages/fullstack/examples/axum-desktop/Cargo.toml @@ -7,7 +7,7 @@ publish = false [lib] [dependencies] -dioxus = { workspace = true, features = ["launch"] } +dioxus = { workspace = true, features = ["launch", "fullstack"] } axum = { workspace = true, optional = true } tokio = { workspace = true, features = ["full"], optional = true } serde = "1.0.159" diff --git a/packages/fullstack/examples/axum-desktop/src/server.rs b/packages/fullstack/examples/axum-desktop/src/server.rs index f14f58abe..68912f452 100644 --- a/packages/fullstack/examples/axum-desktop/src/server.rs +++ b/packages/fullstack/examples/axum-desktop/src/server.rs @@ -5,7 +5,7 @@ use axum_desktop::*; use dioxus::prelude::*; -use dioxus_fullstack::server_fn::axum::register_explicit; +use server_fn::axum::register_explicit; #[tokio::main] async fn main() { diff --git a/packages/fullstack/examples/static-hydrated/src/main.rs b/packages/fullstack/examples/static-hydrated/src/main.rs index c3c988e49..3fb981cee 100644 --- a/packages/fullstack/examples/static-hydrated/src/main.rs +++ b/packages/fullstack/examples/static-hydrated/src/main.rs @@ -14,16 +14,25 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "server")] #[tokio::main] async fn main() { - pre_cache_static_routes( - &ServeConfig::new_with_router( - dioxus_fullstack::router::FullstackRouterConfig::::default(), - ) - .assets_path("docs") - .incremental(IncrementalRendererConfig::default().static_dir("docs")) - .build(), - ) - .await - .unwrap(); + let wrapper = DefaultRenderer { + before_body: r#" + + + + + Dioxus Application + + "# + .to_string(), + after_body: r#" + "# + .to_string(), + }; + let mut renderer = IncrementalRenderer::builder().build(); + pre_cache_static_routes::(&mut renderer, &wrapper) + .await + .unwrap(); } // Hydrate the page diff --git a/packages/fullstack/src/axum_adapter.rs b/packages/fullstack/src/axum_adapter.rs index 3ccef1403..07bd1ff2e 100644 --- a/packages/fullstack/src/axum_adapter.rs +++ b/packages/fullstack/src/axum_adapter.rs @@ -361,7 +361,8 @@ pub async fn render_handler_with_context( ) -> impl IntoResponse { let (parts, _) = request.into_parts(); let url = parts.uri.path_and_query().unwrap().to_string(); - let parts: Arc> = Arc::new(RwLock::new(parts.into())); + let parts: Arc> = + Arc::new(tokio::sync::RwLock::new(parts.into())); let mut server_context = DioxusServerContext::new(parts.clone()); inject_context(&mut server_context); @@ -483,7 +484,7 @@ async fn handle_server_fns_inner( server_fn::axum::get_server_fn_service(&path_string) { - let server_context = DioxusServerContext::new(Arc::new(RwLock::new(parts))); + let server_context = DioxusServerContext::new(Arc::new(tokio::sync::RwLock::new(parts))); additional_context(); // store Accepts and Referrer in case we need them for redirect (below) diff --git a/packages/fullstack/src/server_context.rs b/packages/fullstack/src/server_context.rs index 50e657f40..f70d8548e 100644 --- a/packages/fullstack/src/server_context.rs +++ b/packages/fullstack/src/server_context.rs @@ -12,7 +12,7 @@ pub struct DioxusServerContext { std::sync::RwLock>, >, response_parts: std::sync::Arc>, - pub(crate) parts: Arc>, + pub(crate) parts: Arc>, html_data: Arc>, } @@ -24,7 +24,9 @@ impl Default for DioxusServerContext { response_parts: std::sync::Arc::new(RwLock::new( http::response::Response::new(()).into_parts().0, )), - parts: std::sync::Arc::new(RwLock::new(http::request::Request::new(()).into_parts().0)), + parts: std::sync::Arc::new(tokio::sync::RwLock::new( + http::request::Request::new(()).into_parts().0, + )), html_data: Arc::new(RwLock::new(HTMLData::default())), } } @@ -40,7 +42,7 @@ mod server_fn_impl { impl DioxusServerContext { /// Create a new server context from a request - pub fn new(parts: impl Into>>) -> Self { + pub fn new(parts: impl Into>>) -> Self { Self { parts: parts.into(), shared_context: Arc::new(RwLock::new(SendSyncAnyMap::new())), @@ -82,19 +84,15 @@ mod server_fn_impl { /// Get the request that triggered: /// - The initial SSR render if called from a ScopeState or ServerFn /// - The server function to be called if called from a server function after the initial render - pub fn request_parts( - &self, - ) -> std::sync::LockResult> { - self.parts.read() + pub fn request_parts(&self) -> tokio::sync::RwLockReadGuard<'_, http::request::Parts> { + self.parts.blocking_read() } /// Get the request that triggered: /// - The initial SSR render if called from a ScopeState or ServerFn /// - The server function to be called if called from a server function after the initial render - pub fn request_parts_mut( - &self, - ) -> std::sync::LockResult> { - self.parts.write() + pub fn request_parts_mut(&self) -> tokio::sync::RwLockWriteGuard<'_, http::request::Parts> { + self.parts.blocking_write() } /// Extract some part from the request @@ -185,7 +183,7 @@ impl std::future::Future for ProvideServerContext { } /// A trait for extracting types from the server context -#[async_trait::async_trait(?Send)] +#[async_trait::async_trait] pub trait FromServerContext: Sized { /// The error type returned when extraction fails. This type must implement `std::error::Error`. type Rejection: std::error::Error; @@ -215,7 +213,7 @@ impl std::error::Error for NotFoundInServerContext {} pub struct FromContext(pub(crate) T); -#[async_trait::async_trait(?Send)] +#[async_trait::async_trait] impl FromServerContext for FromContext { type Rejection = NotFoundInServerContext; @@ -232,7 +230,7 @@ impl FromServerContext for FromContext { pub struct Axum; #[cfg(feature = "axum")] -#[async_trait::async_trait(?Send)] +#[async_trait::async_trait] impl< I: axum::extract::FromRequestParts<(), Rejection = R>, R: axum::response::IntoResponse + std::error::Error, @@ -241,6 +239,6 @@ impl< type Rejection = R; async fn from_request(req: &DioxusServerContext) -> Result { - Ok(I::from_request_parts(&mut *req.request_parts_mut().unwrap(), &()).await?) + Ok(I::from_request_parts(&mut *req.request_parts_mut(), &()).await?) } } diff --git a/packages/router/benches/incremental.rs b/packages/router/benches/incremental.rs index 14a7eadfa..b851ee79d 100644 --- a/packages/router/benches/incremental.rs +++ b/packages/router/benches/incremental.rs @@ -11,7 +11,45 @@ use dioxus_ssr::Renderer; pub fn criterion_benchmark(c: &mut Criterion) { c.bench_function("build 1000 routes", |b| { - let mut renderer = IncrementalRenderer::builder(DefaultRenderer { + let mut renderer = IncrementalRenderer::builder() + .static_dir("./static") + .invalidate_after(Duration::from_secs(10)) + .build(); + let wrapper = DefaultRenderer { + before_body: r#" + + + + + Dioxus Application + + "# + .to_string(), + after_body: r#" + "# + .to_string(), + }; + + b.iter(|| { + tokio::runtime::Runtime::new().unwrap().block_on(async { + for id in 0..1000 { + render_route( + &mut renderer, + Route::Post { id }, + &mut tokio::io::sink(), + |_| Box::pin(async move {}), + &wrapper, + ) + .await + .unwrap(); + } + }) + }) + }); + + c.bench_function("build 1000 routes no memory cache", |b| { + let wrapper = DefaultRenderer { before_body: r#" @@ -25,56 +63,22 @@ pub fn criterion_benchmark(c: &mut Criterion) { after_body: r#" "# .to_string(), - }) - .static_dir("./static") - .invalidate_after(Duration::from_secs(10)) - .build(); - - b.iter(|| { - tokio::runtime::Runtime::new().unwrap().block_on(async { - for id in 0..1000 { - render_route( - &mut renderer, - Route::Post { id }, - &mut tokio::io::sink(), - |_| {}, - ) - .await - .unwrap(); - } - }) - }) - }); - - c.bench_function("build 1000 routes no memory cache", |b| { + }; b.to_async(tokio::runtime::Runtime::new().unwrap()) .iter(|| async { - let mut renderer = IncrementalRenderer::builder(DefaultRenderer { - before_body: r#" - - - - - Dioxus Application - - "# - .to_string(), - after_body: r#" - "# - .to_string(), - }) - .static_dir("./static") - .memory_cache_limit(0) - .invalidate_after(Duration::from_secs(10)) - .build(); + let mut renderer = IncrementalRenderer::builder() + .static_dir("./static") + .memory_cache_limit(0) + .invalidate_after(Duration::from_secs(10)) + .build(); for id in 0..1000 { render_route( &mut renderer, Route::Post { id }, &mut tokio::io::sink(), - |_| {}, + |_| Box::pin(async move {}), + &wrapper, ) .await .unwrap(); @@ -91,7 +95,7 @@ pub fn criterion_benchmark(c: &mut Criterion) { RenderPathProps::builder().path(Route::Post { id }).build(), ); - vdom.rebuild(); + vdom.rebuild_in_place(); struct Ignore; @@ -106,27 +110,28 @@ pub fn criterion_benchmark(c: &mut Criterion) { }) }); c.bench_function("cache static", |b| { + let wrapper = DefaultRenderer { + before_body: r#" + + + + + Dioxus Application + + "# + .to_string(), + after_body: r#" + "# + .to_string(), + }; b.to_async(tokio::runtime::Runtime::new().unwrap()) .iter(|| async { - let mut renderer = IncrementalRenderer::builder(DefaultRenderer { - before_body: r#" - - - - - Dioxus Application - - "# - .to_string(), - after_body: r#" - "# - .to_string(), - }) - .static_dir("./static") - .build(); + let mut renderer = IncrementalRenderer::builder() + .static_dir("./static") + .build(); - pre_cache_static_routes::(&mut renderer) + pre_cache_static_routes::(&mut renderer, &wrapper) .await .unwrap(); }) @@ -148,7 +153,7 @@ fn Blog() -> Element { #[component] fn Post(id: usize) -> Element { rsx! { - for _ in 0..*id { + for _ in 0..id { div { "PostId: {id}" } diff --git a/packages/router/src/router_cfg.rs b/packages/router/src/router_cfg.rs index 559c72393..8ec762b14 100644 --- a/packages/router/src/router_cfg.rs +++ b/packages/router/src/router_cfg.rs @@ -135,7 +135,6 @@ where MemoryHistory::::with_initial_path( dioxus_fullstack::prelude::server_context() .request_parts() - .unwrap() .uri .to_string() .parse() From d732269b8f0ec337a5492d97d048e85ab5d1097b Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Sun, 18 Feb 2024 09:45:27 -0800 Subject: [PATCH 15/17] backend proxy tests almost work! --- Cargo.toml | 1 + packages/cli/Cargo.toml | 2 +- packages/cli/src/cli/build.rs | 6 +- packages/cli/src/server/web/proxy.rs | 91 +++++++++++++------------- packages/fullstack/src/axum_adapter.rs | 3 +- 5 files changed, 52 insertions(+), 51 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 89793fb74..c445d8edc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -119,6 +119,7 @@ serde = "1.0.61" axum_session = "0.12.1" axum_session_auth = "0.12.1" axum-extra = "0.9.2" +reqwest = "0.11.24" # This is a "virtual package" # It is not meant to be published, but is used so "cargo run --example XYZ" works properly diff --git a/packages/cli/Cargo.toml b/packages/cli/Cargo.toml index 4ea8613fb..a949b0ed0 100644 --- a/packages/cli/Cargo.toml +++ b/packages/cli/Cargo.toml @@ -49,7 +49,7 @@ walkdir = "2" # tools download dirs = "5.0.1" -reqwest = { version = "0.11", features = [ +reqwest = { workspace = true, features = [ "rustls-tls", "stream", "trust-dns", diff --git a/packages/cli/src/cli/build.rs b/packages/cli/src/cli/build.rs index 8c47fcda7..80962f005 100644 --- a/packages/cli/src/cli/build.rs +++ b/packages/cli/src/cli/build.rs @@ -1,6 +1,4 @@ use crate::assets::AssetConfigDropGuard; -#[cfg(feature = "plugin")] -use crate::plugin::PluginManager; use crate::server::fullstack; use dioxus_cli_config::Platform; @@ -55,7 +53,7 @@ impl Build { crate_config.set_cargo_args(self.build.cargo_args.clone()); // #[cfg(feature = "plugin")] - // let _ = PluginManager::on_build_start(&crate_config, &platform); + // let _ = crate::plugin::PluginManager::on_build_start(&crate_config, &platform); let build_result = match platform { Platform::Web => { @@ -116,7 +114,7 @@ impl Build { file.write_all(temp.as_bytes())?; // #[cfg(feature = "plugin")] - // let _ = PluginManager::on_build_finish(&crate_config, &platform); + // let _ = crate::plugin::PluginManager::on_build_finish(&crate_config, &platform); Ok(()) } diff --git a/packages/cli/src/server/web/proxy.rs b/packages/cli/src/server/web/proxy.rs index ee58dabe0..7f68346d7 100644 --- a/packages/cli/src/server/web/proxy.rs +++ b/packages/cli/src/server/web/proxy.rs @@ -102,30 +102,43 @@ mod test { use super::*; use axum::{extract::Path, Router}; - use axum_server::Server; + use axum_server::{Handle, Server}; - fn setup_servers( - mut config: WebProxyConfig, - ) -> ( - tokio::task::JoinHandle<()>, - tokio::task::JoinHandle<()>, - String, - ) { + async fn setup_servers(mut config: WebProxyConfig) -> String { let backend_router = Router::new().route( "/*path", any(|path: Path| async move { format!("backend: {}", path.0) }), ); - let backend_server = - Server::bind("127.0.0.1:0".parse().unwrap()).serve(backend_router.into_make_service()); - let backend_addr = backend_server.local_addr(); - let backend_handle = tokio::spawn(async move { backend_server.await.unwrap() }); - config.backend = format!("http://{}{}", backend_addr, config.backend); + + // The API backend server + let backend_handle_handle = Handle::new(); + let backend_handle_handle_ = backend_handle_handle.clone(); + tokio::spawn(async move { + Server::bind("127.0.0.1:0".parse().unwrap()) + .handle(backend_handle_handle_) + .serve(backend_router.into_make_service()) + .await + .unwrap(); + }); + + // Set the user's config to this dummy API we just built so we can test it + let backend_addr = backend_handle_handle.listening().await.unwrap(); + config.backend = dbg!(format!("http://{}{}", backend_addr, config.backend)); + + // Now set up our actual filesystem server let router = super::add_proxy(Router::new(), &config); - let server = - Server::bind("127.0.0.1:0".parse().unwrap()).serve(router.unwrap().into_make_service()); - let server_addr = server.local_addr(); - let server_handle = tokio::spawn(async move { server.await.unwrap() }); - (backend_handle, server_handle, server_addr.to_string()) + let server_handle_handle = Handle::new(); + let server_handle_handle_ = server_handle_handle.clone(); + tokio::spawn(async move { + Server::bind("127.0.0.1:0".parse().unwrap()) + .handle(server_handle_handle_) + .serve(router.unwrap().into_make_service()) + .await + .unwrap(); + }); + + // Expose *just* the fileystem web server's address + server_handle_handle.listening().await.unwrap().to_string() } async fn test_proxy_requests(path: String) { @@ -137,48 +150,38 @@ mod test { // So in day to day usage, use `http://localhost:8000/api` instead! backend: path, }; - let (backend_handle, server_handle, server_addr) = setup_servers(config).await; - let resp = Client::new() - .get(format!("http://{}/api", server_addr).parse().unwrap()) - .await - .unwrap(); - assert_eq!(resp.status(), StatusCode::OK); + + let server_addr = setup_servers(config).await; + assert_eq!( - axum::body::to_bytes(resp.into_body(), usize::MAX) + reqwest::get(format!("http://{}/api", server_addr)) + .await + .unwrap() + .text() .await .unwrap(), - "backend: /api" + "backend: api" ); - let resp = Client::new() - .get(format!("http://{}/api/", server_addr).parse().unwrap()) - .await - .unwrap(); - assert_eq!(resp.status(), StatusCode::OK); assert_eq!( - axum::body::to_bytes(resp.into_body(), usize::MAX) + reqwest::get(dbg!(format!("http://{}/api/", server_addr))) + .await + .unwrap() + .text() .await .unwrap(), "backend: /api/" ); - let resp = Client::new() - .get( - format!("http://{}/api/subpath", server_addr) - .parse() - .unwrap(), - ) - .await - .unwrap(); - assert_eq!(resp.status(), StatusCode::OK); assert_eq!( - axum::body::to_bytes(resp.into_body(), usize::MAX) + reqwest::get(format!("http://{}/api/subpath", server_addr)) + .await + .unwrap() + .text() .await .unwrap(), "backend: /api/subpath" ); - backend_handle.abort(); - server_handle.abort(); } #[tokio::test] diff --git a/packages/fullstack/src/axum_adapter.rs b/packages/fullstack/src/axum_adapter.rs index 07bd1ff2e..273abc3ec 100644 --- a/packages/fullstack/src/axum_adapter.rs +++ b/packages/fullstack/src/axum_adapter.rs @@ -68,7 +68,6 @@ use http::header::*; use server_fn::error::NoCustomError; use server_fn::error::ServerFnErrorSerde; use std::sync::Arc; -use std::sync::RwLock; use crate::{ prelude::*, render::SSRState, serve_config::ServeConfig, server_context::DioxusServerContext, @@ -478,7 +477,7 @@ async fn handle_server_fns_inner( get_local_pool().spawn_pinned(move || async move { let (parts, body) = req.into_parts(); let req = Request::from_parts(parts.clone(), body); - + let res = if let Some(mut service) = server_fn::axum::get_server_fn_service(&path_string) From ebdb98bff282d32e8c7e6d4a4399eb67d1d5695e Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Sun, 18 Feb 2024 21:08:48 -0800 Subject: [PATCH 16/17] Make clippy happy, pass tests --- packages/cli/src/plugin/interface/command.rs | 2 +- packages/cli/src/server/web/proxy.rs | 43 +++++++------------ .../examples/axum-desktop/src/server.rs | 4 +- packages/fullstack/src/axum_adapter.rs | 28 ++++++------ packages/fullstack/src/render.rs | 35 +++++++-------- packages/fullstack/src/serve_config.rs | 2 +- packages/fullstack/src/server_context.rs | 6 +-- packages/router/src/history/liveview.rs | 7 ++- 8 files changed, 57 insertions(+), 70 deletions(-) diff --git a/packages/cli/src/plugin/interface/command.rs b/packages/cli/src/plugin/interface/command.rs index 14a2650fe..19a8205a7 100644 --- a/packages/cli/src/plugin/interface/command.rs +++ b/packages/cli/src/plugin/interface/command.rs @@ -45,7 +45,7 @@ impl UserData for PluginCommander { if cmd.is_empty() { return Ok(()); } - let cmd_name = cmd.get(0).unwrap(); + let cmd_name = cmd.first().unwrap(); let mut command = Command::new(cmd_name); let t = cmd .iter() diff --git a/packages/cli/src/server/web/proxy.rs b/packages/cli/src/server/web/proxy.rs index 7f68346d7..4e22fc91f 100644 --- a/packages/cli/src/server/web/proxy.rs +++ b/packages/cli/src/server/web/proxy.rs @@ -53,7 +53,7 @@ impl ProxyClient { pub fn add_proxy(mut router: Router, proxy: &WebProxyConfig) -> Result { let url: Uri = proxy.backend.parse()?; let path = url.path().to_string(); - let trimmed_path = path.trim_end_matches('/'); + let trimmed_path = path.trim_start_matches('/'); if trimmed_path.is_empty() { return Err(crate::Error::ProxySetupError(format!( @@ -65,14 +65,11 @@ pub fn add_proxy(mut router: Router, proxy: &WebProxyConfig) -> Result { let client = ProxyClient::new(url); - // We also match everything after the path using a wildcard matcher. - let wildcard_client = client.clone(); - router = router.route( // Always remove trailing /'s so that the exact route // matches. - trimmed_path, - any(move |req| async move { + &format!("/*{}", trimmed_path.trim_end_matches('/')), + any(move |req: Request| async move { client .send(req) .await @@ -80,19 +77,6 @@ pub fn add_proxy(mut router: Router, proxy: &WebProxyConfig) -> Result { }), ); - // Wildcard match anything else _after_ the backend URL's path. - // Note that we know `path` ends with a trailing `/` in this branch, - // so `wildcard` will look like `http://localhost/api/*proxywildcard`. - let wildcard = format!("{}/*proxywildcard", trimmed_path); - router = router.route( - &wildcard, - any(move |req| async move { - wildcard_client - .send(req) - .await - .map_err(|e| (StatusCode::INTERNAL_SERVER_ERROR, e.to_string())) - }), - ); Ok(router) } @@ -101,14 +85,17 @@ mod test { use super::*; - use axum::{extract::Path, Router}; + use axum::Router; use axum_server::{Handle, Server}; async fn setup_servers(mut config: WebProxyConfig) -> String { - let backend_router = Router::new().route( - "/*path", - any(|path: Path| async move { format!("backend: {}", path.0) }), - ); + let backend_router = + Router::new().route( + "/*path", + any(|request: axum::extract::Request| async move { + format!("backend: {}", request.uri()) + }), + ); // The API backend server let backend_handle_handle = Handle::new(); @@ -123,7 +110,7 @@ mod test { // Set the user's config to this dummy API we just built so we can test it let backend_addr = backend_handle_handle.listening().await.unwrap(); - config.backend = dbg!(format!("http://{}{}", backend_addr, config.backend)); + config.backend = format!("http://{}{}", backend_addr, config.backend); // Now set up our actual filesystem server let router = super::add_proxy(Router::new(), &config); @@ -160,11 +147,11 @@ mod test { .text() .await .unwrap(), - "backend: api" + "backend: /api" ); assert_eq!( - reqwest::get(dbg!(format!("http://{}/api/", server_addr))) + reqwest::get(format!("http://{}/api/", server_addr)) .await .unwrap() .text() @@ -174,7 +161,7 @@ mod test { ); assert_eq!( - reqwest::get(format!("http://{}/api/subpath", server_addr)) + reqwest::get(format!("http://{server_addr}/api/subpath")) .await .unwrap() .text() diff --git a/packages/fullstack/examples/axum-desktop/src/server.rs b/packages/fullstack/examples/axum-desktop/src/server.rs index 68912f452..2d195f392 100644 --- a/packages/fullstack/examples/axum-desktop/src/server.rs +++ b/packages/fullstack/examples/axum-desktop/src/server.rs @@ -13,8 +13,8 @@ async fn main() { .await .unwrap(); - let _ = register_explicit::(); - let _ = register_explicit::(); + register_explicit::(); + register_explicit::(); axum::serve( listener, diff --git a/packages/fullstack/src/axum_adapter.rs b/packages/fullstack/src/axum_adapter.rs index 273abc3ec..dd19c0043 100644 --- a/packages/fullstack/src/axum_adapter.rs +++ b/packages/fullstack/src/axum_adapter.rs @@ -302,6 +302,13 @@ fn apply_request_parts_to_response( } } +type AxumHandler = ( + F, + ServeConfig, + SSRState, + Arc VirtualDom + Send + Sync>, +); + /// SSR renderer handler for Axum with added context injection. /// /// # Example @@ -350,18 +357,13 @@ fn apply_request_parts_to_response( /// } /// ``` pub async fn render_handler_with_context( - State((mut inject_context, cfg, ssr_state, virtual_dom_factory)): State<( - F, - ServeConfig, - SSRState, - Arc VirtualDom + Send + Sync>, - )>, + State((mut inject_context, cfg, ssr_state, virtual_dom_factory)): State>, request: Request, ) -> impl IntoResponse { let (parts, _) = request.into_parts(); let url = parts.uri.path_and_query().unwrap().to_string(); let parts: Arc> = - Arc::new(tokio::sync::RwLock::new(parts.into())); + Arc::new(tokio::sync::RwLock::new(parts)); let mut server_context = DioxusServerContext::new(parts.clone()); inject_context(&mut server_context); @@ -384,13 +386,15 @@ pub async fn render_handler_with_context( } } +type RenderHandlerExtractor = ( + ServeConfig, + Arc VirtualDom + Send + Sync>, + SSRState, +); + /// SSR renderer handler for Axum pub async fn render_handler( - State((cfg, virtual_dom_factory, ssr_state)): State<( - ServeConfig, - Arc VirtualDom + Send + Sync>, - SSRState, - )>, + State((cfg, virtual_dom_factory, ssr_state)): State, request: Request, ) -> impl IntoResponse { render_handler_with_context( diff --git a/packages/fullstack/src/render.rs b/packages/fullstack/src/render.rs index 5d71dc497..42ce4e4d4 100644 --- a/packages/fullstack/src/render.rs +++ b/packages/fullstack/src/render.rs @@ -48,7 +48,7 @@ impl SsrRendererPool { SERVER_CONTEXT.with(|ctx| ctx.replace(server_context)); // poll the future, which may call server_context() tracing::info!("Rebuilding vdom"); - let _ = vdom.rebuild(&mut NoOpMutations); + vdom.rebuild(&mut NoOpMutations); vdom.wait_for_suspense().await; tracing::info!("Suspense resolved"); // after polling the future, we need to restore the context @@ -76,9 +76,11 @@ impl SsrRendererPool { tx.send(Ok((renderer, RenderFreshness::now(None), html))); } Err(err) => { - dioxus_ssr::incremental::IncrementalRendererError::Other( - Box::new(err), - ); + _ = tx.send(Err( + dioxus_ssr::incremental::IncrementalRendererError::Other( + Box::new(err), + ), + )); } } }); @@ -113,7 +115,7 @@ impl SsrRendererPool { .with(|ctx| ctx.replace(Box::new(server_context))); // poll the future, which may call server_context() tracing::info!("Rebuilding vdom"); - let _ = vdom.rebuild(&mut NoOpMutations); + vdom.rebuild(&mut NoOpMutations); vdom.wait_for_suspense().await; tracing::info!("Suspense resolved"); // after polling the future, we need to restore the context @@ -184,26 +186,21 @@ impl SSRState { } /// Render the application to HTML. - pub fn render<'a>( + pub async fn render<'a>( &'a self, route: String, cfg: &'a ServeConfig, virtual_dom_factory: impl FnOnce() -> VirtualDom + Send + Sync + 'static, server_context: &'a DioxusServerContext, - ) -> impl std::future::Future< - Output = Result, - > + Send - + 'a { - async move { - let ServeConfig { .. } = cfg; + ) -> Result { + let ServeConfig { .. } = cfg; - let (freshness, html) = self - .renderers - .render_to(cfg, route, virtual_dom_factory, server_context) - .await?; + let (freshness, html) = self + .renderers + .render_to(cfg, route, virtual_dom_factory, server_context) + .await?; - Ok(RenderResponse { html, freshness }) - } + Ok(RenderResponse { html, freshness }) } } @@ -321,7 +318,7 @@ impl RenderResponse { fn pre_renderer() -> Renderer { let mut renderer = Renderer::default(); renderer.pre_render = true; - renderer.into() + renderer } fn incremental_pre_renderer( diff --git a/packages/fullstack/src/serve_config.rs b/packages/fullstack/src/serve_config.rs index 88e64eb33..aa78ef5c9 100644 --- a/packages/fullstack/src/serve_config.rs +++ b/packages/fullstack/src/serve_config.rs @@ -6,7 +6,7 @@ use std::io::Read; use std::path::PathBuf; /// A ServeConfig is used to configure how to serve a Dioxus application. It contains information about how to serve static assets, and what content to render with [`dioxus-ssr`]. -#[derive(Clone)] +#[derive(Clone, Default)] pub struct ServeConfigBuilder { pub(crate) root_id: Option<&'static str>, pub(crate) index_path: Option, diff --git a/packages/fullstack/src/server_context.rs b/packages/fullstack/src/server_context.rs index f70d8548e..a2cbfeb55 100644 --- a/packages/fullstack/src/server_context.rs +++ b/packages/fullstack/src/server_context.rs @@ -120,7 +120,7 @@ mod server_fn_impl { } std::thread_local! { - pub(crate) static SERVER_CONTEXT: std::cell::RefCell> = std::cell::RefCell::new(Box::new(DioxusServerContext::default() )); + pub(crate) static SERVER_CONTEXT: std::cell::RefCell> = Default::default(); } /// Get information about the current server request. @@ -218,7 +218,7 @@ impl FromServerContext for FromContext { type Rejection = NotFoundInServerContext; async fn from_request(req: &DioxusServerContext) -> Result { - Ok(Self(req.clone().get::().ok_or_else(|| { + Ok(Self(req.clone().get::().ok_or({ NotFoundInServerContext::(std::marker::PhantomData::) })?)) } @@ -239,6 +239,6 @@ impl< type Rejection = R; async fn from_request(req: &DioxusServerContext) -> Result { - Ok(I::from_request_parts(&mut *req.request_parts_mut(), &()).await?) + Ok(I::from_request_parts(&mut req.request_parts_mut(), &()).await?) } } diff --git a/packages/router/src/history/liveview.rs b/packages/router/src/history/liveview.rs index 478785617..036d5d84c 100644 --- a/packages/router/src/history/liveview.rs +++ b/packages/router/src/history/liveview.rs @@ -166,8 +166,8 @@ where /// /// Panics if the function is not called in a dioxus runtime with a Liveview context. pub fn new_with_initial_path(initial_path: R) -> Self { - let (action_tx, action_rx) = tokio::sync::mpsc::unbounded_channel::>(); - let action_rx = Arc::new(Mutex::new(action_rx)); + let (action_tx, mut action_rx) = tokio::sync::mpsc::unbounded_channel::>(); + let timeline = Arc::new(Mutex::new(Timeline::new(initial_path))); let updater_callback: Arc>> = Arc::new(RwLock::new(Arc::new(|| {}))); @@ -181,12 +181,11 @@ where // Listen to server actions spawn({ let timeline = timeline.clone(); - let action_rx = action_rx.clone(); let create_eval = create_eval.clone(); async move { - let mut action_rx = action_rx.lock().expect("unpoisoned mutex"); loop { let eval = action_rx.recv().await.expect("sender to exist"); + let _ = match eval { Action::GoBack => create_eval( r#" From f9eabbe8efb613a367498f9fc55bb949a079f821 Mon Sep 17 00:00:00 2001 From: Jonathan Kelley Date: Sun, 18 Feb 2024 21:29:10 -0800 Subject: [PATCH 17/17] clippy!! --- examples/image_generator_openai.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/image_generator_openai.rs b/examples/image_generator_openai.rs index 8b551889c..8cebbb373 100644 --- a/examples/image_generator_openai.rs +++ b/examples/image_generator_openai.rs @@ -21,7 +21,7 @@ fn app() -> Element { let prompt = prompt.peek().clone(); let number_of_images = n_image.peek().clone(); - if (api_key.is_empty() || prompt.is_empty() || number_of_images.is_empty()) { + if api_key.is_empty() || prompt.is_empty() || number_of_images.is_empty() { return; }