diff --git a/packages/liveview/Cargo.toml b/packages/liveview/Cargo.toml index ee75f71de..99e43da08 100644 --- a/packages/liveview/Cargo.toml +++ b/packages/liveview/Cargo.toml @@ -13,45 +13,51 @@ license = "MIT/Apache-2.0" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tokio = { version = "1", features = ["full"] } -futures-util = { version = "0.3", default-features = false, features = [ +tokio = { version = "1.23.0", features = ["full"] } +futures-util = { version = "0.3.25", default-features = false, features = [ "sink", ] } -futures-channel = { version = "0.3.17", features = ["sink"] } -pretty_env_logger = "0.4" -tokio-stream = { version = "0.1.1", features = ["net"] } +futures-channel = { version = "0.3.25", features = ["sink"] } +pretty_env_logger = "0.4.0" +tokio-stream = { version = "0.1.11", features = ["net"] } -serde = { version = "1.0.136", features = ["derive"] } -serde_json = "1.0.79" -tokio-util = { version = "0.7.0", features = ["full"] } +serde = { version = "1.0.151", features = ["derive"] } +serde_json = "1.0.91" +tokio-util = { version = "0.7.4", features = ["full"] } dioxus-html = { path = "../html", features = ["serialize"], version = "^0.2.1" } dioxus-core = { path = "../core", features = ["serialize"], version = "^0.2.1" } dioxus-interpreter-js = { path = "../interpreter" } # warp -warp = { version = "0.3", optional = true } +warp = { version = "0.3.3", optional = true } # axum -axum = { version = "0.5.1", optional = true, features = ["ws"] } -tower = { version = "0.4.12", optional = true } +axum = { version = "0.6.1", optional = true, features = ["ws"] } +tower = { version = "0.4.13", optional = true } # salvo -salvo = { version = "0.32.0", optional = true, features = ["ws"] } -thiserror = "1.0.37" +salvo = { version = "0.37.7", optional = true, features = ["ws"] } +thiserror = "1.0.38" uuid = { version = "1.2.2", features = ["v4"] } -anyhow = "1.0.66" +anyhow = "1.0.68" + +# 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 } [dev-dependencies] -tokio = { version = "1", features = ["full"] } +tokio = { version = "1.23.0", features = ["full"] } dioxus = { path = "../dioxus" } -warp = "0.3" -axum = { version = "0.5.1", features = ["ws"] } -salvo = { version = "0.32.0", features = ["affix", "ws"] } -tower = "0.4.12" +warp = "0.3.3" +axum = { version = "0.6.1", features = ["ws"] } +salvo = { version = "0.37.7", features = ["affix", "ws"] } +tower = "0.4.13" [features] -default = ["salvo"] +default = [] +# actix = ["actix-files", "actix-web", "actix-ws"] [[example]] name = "axum" diff --git a/packages/liveview/README.md b/packages/liveview/README.md index 6cdd57dcd..46ceabf04 100644 --- a/packages/liveview/README.md +++ b/packages/liveview/README.md @@ -1,49 +1,3 @@ # Dioxus LiveView -Enabling server-rendered and hybrid applications with incredibly low latency (<1ms). - -```rust -#[async_std::main] -async fn main() -> tide::Result<()> { - let liveview_pool = dioxus::liveview::pool::default(); - let mut app = tide::new(); - - // serve the liveview client - app.at("/").get(dioxus::liveview::liveview_frontend); - - // and then connect the client to the backend - app.at("/app").get(|req| dioxus::liveview::launch(App, Props { req })) - - app.listen("127.0.0.1:8080").await?; - - Ok(()) -} -``` - -Dioxus LiveView runs your Dioxus apps on the server - - - -```rust -use soyuz::prelude::*; - -#[tokio::main] -async fn main() { - let mut app = soyuz::new(); - app.at("/app").get(websocket(handler)); - app.listen("127.0.0.1:8080").await.unwrap(); -} - -async fn order_shoes(mut req: WebsocketRequest) -> Response { - let stream = req.upgrade(); - dioxus::liveview::launch(App, stream).await; -} - -fn App(cx: Scope) -> Element { - let mut count = use_state(cx, || 0); - cx.render(rsx!( - button { onclick: move |_| count += 1, "Incr" } - button { onclick: move |_| count -= 1, "Decr" } - )) -} -``` +Server rendered apps with minimal latency diff --git a/packages/liveview/examples/salvo.rs b/packages/liveview/examples/salvo.rs index cfe7a7ffd..8cd2c0ca4 100644 --- a/packages/liveview/examples/salvo.rs +++ b/packages/liveview/examples/salvo.rs @@ -1,7 +1,6 @@ use dioxus::prelude::*; use dioxus_liveview::LiveViewPool; -use salvo::extra::affix; -use salvo::extra::ws::WsHandler; +use salvo::affix; use salvo::prelude::*; use std::net::SocketAddr; use std::sync::Arc; @@ -58,13 +57,10 @@ async fn connect( res: &mut Response, ) -> Result<(), StatusError> { let view = depot.obtain::>().unwrap().clone(); - let fut = WsHandler::new().handle(req, res)?; - tokio::spawn(async move { - if let Some(ws) = fut.await { + WebSocketUpgrade::new() + .upgrade(req, res, |ws| async move { _ = view.launch(dioxus_liveview::salvo_socket(ws), app).await; - } - }); - - Ok(()) + }) + .await } diff --git a/packages/liveview/src/adapters/salvo_adapter.rs b/packages/liveview/src/adapters/salvo_adapter.rs index 19cb528c7..2c8912a57 100644 --- a/packages/liveview/src/adapters/salvo_adapter.rs +++ b/packages/liveview/src/adapters/salvo_adapter.rs @@ -1,5 +1,5 @@ use futures_util::{SinkExt, StreamExt}; -use salvo::extra::ws::{Message, WebSocket}; +use salvo::ws::{Message, WebSocket}; use crate::{LiveViewError, LiveViewSocket}; diff --git a/packages/liveview/src/pool.rs b/packages/liveview/src/pool.rs index c769e1371..a25673d84 100644 --- a/packages/liveview/src/pool.rs +++ b/packages/liveview/src/pool.rs @@ -46,6 +46,32 @@ impl LiveViewPool { } /// A LiveViewSocket is a Sink and Stream of Strings that Dioxus uses to communicate with the client +/// +/// Most websockets from most HTTP frameworks can be converted into a LiveViewSocket using the appropriate adapter. +/// +/// You can also convert your own socket into a LiveViewSocket by implementing this trait. This trait is an auto trait, +/// meaning that as long as your type implements Stream and Sink, you can use it as a LiveViewSocket. +/// +/// For example, the axum implementation is a really small transform: +/// +/// ```rust, ignore +/// pub fn axum_socket(ws: WebSocket) -> impl LiveViewSocket { +/// ws.map(transform_rx) +/// .with(transform_tx) +/// .sink_map_err(|_| LiveViewError::SendingFailed) +/// } +/// +/// fn transform_rx(message: Result) -> Result { +/// message +/// .map_err(|_| LiveViewError::SendingFailed)? +/// .into_text() +/// .map_err(|_| LiveViewError::SendingFailed) +/// } +/// +/// async fn transform_tx(message: String) -> Result { +/// Ok(Message::Text(message)) +/// } +/// ``` pub trait LiveViewSocket: SinkExt + StreamExt>