From 39b77cd66332f6c48d00e02a7e1726f33f14c91a Mon Sep 17 00:00:00 2001 From: Ian Date: Sun, 17 Apr 2022 11:59:43 -0400 Subject: [PATCH 1/4] fixed warp example --- packages/liveview/Cargo.toml | 5 +++++ packages/liveview/examples/warp.rs | 2 -- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/liveview/Cargo.toml b/packages/liveview/Cargo.toml index 176e78d51..40ea894fc 100644 --- a/packages/liveview/Cargo.toml +++ b/packages/liveview/Cargo.toml @@ -30,5 +30,10 @@ dioxus-core = { path = "../core", features = ["serialize"] } # warp warp = { version = "0.3", optional = true } +[dev-dependencies] +dioxus-liveview = { path = "./", features = ["warp"] } +warp = "0.3" + + [features] default = [] diff --git a/packages/liveview/examples/warp.rs b/packages/liveview/examples/warp.rs index a02a5231a..4adc357c4 100644 --- a/packages/liveview/examples/warp.rs +++ b/packages/liveview/examples/warp.rs @@ -1,5 +1,3 @@ -#![cfg(feature = "warp")] - use dioxus_core::{Element, LazyNodes, Scope}; use dioxus_liveview as liveview; use warp::ws::Ws; From 149d484ffb1f2326b781425fc119a888c58ed5c5 Mon Sep 17 00:00:00 2001 From: Ian Date: Mon, 18 Apr 2022 22:24:17 -0400 Subject: [PATCH 2/4] added menu element --- packages/html/src/elements.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/html/src/elements.rs b/packages/html/src/elements.rs index c6b1cb7e0..ad4f66b7b 100644 --- a/packages/html/src/elements.rs +++ b/packages/html/src/elements.rs @@ -428,6 +428,11 @@ builder_constructors! { /// element. mark {}; + /// Build a + /// [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/menu) + /// element. + menu {}; + /// Build a /// [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/q) /// element. From a632d9b12b2d0734f5001627ee85a88a5e72bda5 Mon Sep 17 00:00:00 2001 From: Ian Date: Tue, 19 Apr 2022 22:51:56 -0400 Subject: [PATCH 3/4] implemented liveview axum adapter --- packages/liveview/Cargo.toml | 9 ++- .../liveview/src/adapters/axum_adapter.rs | 68 +++++++++++++++++++ 2 files changed, 75 insertions(+), 2 deletions(-) diff --git a/packages/liveview/Cargo.toml b/packages/liveview/Cargo.toml index 40ea894fc..51b1a89bb 100644 --- a/packages/liveview/Cargo.toml +++ b/packages/liveview/Cargo.toml @@ -30,10 +30,15 @@ dioxus-core = { path = "../core", features = ["serialize"] } # warp warp = { version = "0.3", optional = true } +# axum +axum = { version = "0.5.1", optional = true, features = ["ws"] } +tower = { version = "0.4.12", optional = true } + [dev-dependencies] dioxus-liveview = { path = "./", features = ["warp"] } warp = "0.3" - +axum = { version = "0.5.1", features = ["ws"] } +tower = "0.4.12" [features] -default = [] +default = [] \ No newline at end of file diff --git a/packages/liveview/src/adapters/axum_adapter.rs b/packages/liveview/src/adapters/axum_adapter.rs index 8b1378917..1b779f32f 100644 --- a/packages/liveview/src/adapters/axum_adapter.rs +++ b/packages/liveview/src/adapters/axum_adapter.rs @@ -1 +1,69 @@ +use crate::{events, Liveview}; +use axum::extract::ws::{Message, WebSocket}; +use dioxus_core::prelude::*; +use futures_util::{ + future::{select, Either}, + pin_mut, SinkExt, StreamExt, +}; +use tokio::sync::mpsc; +use tokio_stream::wrappers::UnboundedReceiverStream; +pub async fn connect(socket: WebSocket, liveview: Liveview, app: fn(Scope) -> Element) { + let (mut user_ws_tx, mut user_ws_rx) = socket.split(); + let (event_tx, event_rx) = mpsc::unbounded_channel(); + let (edits_tx, edits_rx) = mpsc::unbounded_channel(); + let mut edits_rx = UnboundedReceiverStream::new(edits_rx); + let mut event_rx = UnboundedReceiverStream::new(event_rx); + let vdom_fut = liveview.pool.clone().spawn_pinned(move || async move { + let mut vdom = VirtualDom::new(app); + let edits = vdom.rebuild(); + let serialized = serde_json::to_string(&edits.edits).unwrap(); + edits_tx.send(serialized).unwrap(); + loop { + let new_event = { + let vdom_fut = vdom.wait_for_work(); + pin_mut!(vdom_fut); + match select(event_rx.next(), vdom_fut).await { + Either::Left((l, _)) => l, + Either::Right((_, _)) => None, + } + }; + if let Some(new_event) = new_event { + vdom.handle_message(dioxus_core::SchedulerMsg::Event(new_event)); + } else { + let mutations = vdom.work_with_deadline(|| false); + for mutation in mutations { + let edits = serde_json::to_string(&mutation.edits).unwrap(); + edits_tx.send(edits).unwrap(); + } + } + } + }); + loop { + match select(user_ws_rx.next(), edits_rx.next()).await { + Either::Left((l, _)) => { + if let Some(Ok(msg)) = l { + if let Ok(Some(msg)) = msg.to_text().map(events::parse_ipc_message) { + let user_event = events::trigger_from_serialized(msg.params); + event_tx.send(user_event).unwrap(); + } else { + break; + } + } else { + break; + } + } + Either::Right((edits, _)) => { + if let Some(edits) = edits { + // send the edits to the client + if user_ws_tx.send(Message::Text(edits)).await.is_err() { + break; + } + } else { + break; + } + } + } + } + vdom_fut.abort(); +} From dfaa6c186bc1f2fc06146a62cc57864857dcf0e9 Mon Sep 17 00:00:00 2001 From: Ian Date: Sat, 23 Apr 2022 22:13:43 -0400 Subject: [PATCH 4/4] Fixed example squiglies. --- packages/liveview/Cargo.toml | 3 +- packages/liveview/examples/axum.rs | 38 +++++++++++++++++++ packages/liveview/examples/warp.rs | 36 +++++++++--------- .../liveview/src/adapters/axum_adapter.rs | 12 +++++- .../liveview/src/adapters/warp_adapter.rs | 1 + 5 files changed, 70 insertions(+), 20 deletions(-) create mode 100644 packages/liveview/examples/axum.rs diff --git a/packages/liveview/Cargo.toml b/packages/liveview/Cargo.toml index 51b1a89bb..313892f45 100644 --- a/packages/liveview/Cargo.toml +++ b/packages/liveview/Cargo.toml @@ -35,7 +35,8 @@ axum = { version = "0.5.1", optional = true, features = ["ws"] } tower = { version = "0.4.12", optional = true } [dev-dependencies] -dioxus-liveview = { path = "./", features = ["warp"] } +tokio = { version = "1", features = ["full"] } +dioxus = { path = "../../" } warp = "0.3" axum = { version = "0.5.1", features = ["ws"] } tower = "0.4.12" diff --git a/packages/liveview/examples/axum.rs b/packages/liveview/examples/axum.rs new file mode 100644 index 000000000..3bcdee8c2 --- /dev/null +++ b/packages/liveview/examples/axum.rs @@ -0,0 +1,38 @@ +use axum::{ + extract::ws::WebSocketUpgrade, response::Html, response::IntoResponse, routing::get, Extension, + Router, +}; +use dioxus_core::{Element, LazyNodes, Scope}; +use dioxus_liveview::Liveview; + +#[tokio::main] +async fn main() { + #[cfg(feature = "axum")] + { + pretty_env_logger::init(); + + let addr: std::net::SocketAddr = ([127, 0, 0, 1], 3030).into(); + + let view = dioxus_liveview::new(addr); + let body = view.body("Dioxus Liveview"); + + let app = Router::new() + .route("/", get(move || async { Html(body) })) + .route( + "/app", + get(move |ws: WebSocketUpgrade| async move { + ws.on_upgrade(move |socket| async move { + view.upgrade(socket, app).await; + }) + }), + ); + axum::Server::bind(&addr.to_string().parse().unwrap()) + .serve(app.into_make_service()) + .await + .unwrap(); + } +} + +fn app(cx: Scope) -> Element { + cx.render(LazyNodes::new(|f| f.text(format_args!("hello world!")))) +} diff --git a/packages/liveview/examples/warp.rs b/packages/liveview/examples/warp.rs index 5540f7b08..2c14d318b 100644 --- a/packages/liveview/examples/warp.rs +++ b/packages/liveview/examples/warp.rs @@ -5,26 +5,28 @@ use warp::Filter; #[tokio::main] async fn main() { - pretty_env_logger::init(); + #[cfg(feature = "warp")] + { + pretty_env_logger::init(); - let addr = ([127, 0, 0, 1], 3030); + let addr = ([127, 0, 0, 1], 3030); - // todo: compactify this routing under one liveview::app method - let view = liveview::new(addr); - let body = view.body("Dioxus LiveView"); + // todo: compactify this routing under one liveview::app method + let view = liveview::new(addr); + let body = view.body("Dioxus LiveView"); - let routes = warp::path::end() - .map(move || warp::reply::html(body.clone())) - .or(warp::path("app") - .and(warp::ws()) - .and(warp::any().map(move || view.clone())) - .map(|ws: Ws, view: liveview::Liveview| { - ws.on_upgrade(|socket| async move { - view.upgrade(socket, app).await; - }) - })); - - warp::serve(routes).run(addr).await; + let routes = warp::path::end() + .map(move || warp::reply::html(body.clone())) + .or(warp::path("app") + .and(warp::ws()) + .and(warp::any().map(move || view.clone())) + .map(|ws: Ws, view: liveview::Liveview| { + ws.on_upgrade(|socket| async move { + view.upgrade(socket, app).await; + }) + })); + warp::serve(routes).run(addr).await; + } } fn app(cx: Scope) -> Element { diff --git a/packages/liveview/src/adapters/axum_adapter.rs b/packages/liveview/src/adapters/axum_adapter.rs index 1b779f32f..d85b6da68 100644 --- a/packages/liveview/src/adapters/axum_adapter.rs +++ b/packages/liveview/src/adapters/axum_adapter.rs @@ -7,14 +7,22 @@ use futures_util::{ }; use tokio::sync::mpsc; use tokio_stream::wrappers::UnboundedReceiverStream; +use tokio_util::task::LocalPoolHandle; -pub async fn connect(socket: WebSocket, liveview: Liveview, app: fn(Scope) -> Element) { +#[cfg(feature = "axum")] +impl crate::Liveview { + pub async fn upgrade(&self, ws: WebSocket, app: fn(Scope) -> Element) { + connect(ws, self.pool.clone(), app).await; + } +} + +pub async fn connect(socket: WebSocket, pool: LocalPoolHandle, app: fn(Scope) -> Element) { let (mut user_ws_tx, mut user_ws_rx) = socket.split(); let (event_tx, event_rx) = mpsc::unbounded_channel(); let (edits_tx, edits_rx) = mpsc::unbounded_channel(); let mut edits_rx = UnboundedReceiverStream::new(edits_rx); let mut event_rx = UnboundedReceiverStream::new(event_rx); - let vdom_fut = liveview.pool.clone().spawn_pinned(move || async move { + let vdom_fut = pool.clone().spawn_pinned(move || async move { let mut vdom = VirtualDom::new(app); let edits = vdom.rebuild(); let serialized = serde_json::to_string(&edits.edits).unwrap(); diff --git a/packages/liveview/src/adapters/warp_adapter.rs b/packages/liveview/src/adapters/warp_adapter.rs index 0c6f3e892..5bdcf671f 100644 --- a/packages/liveview/src/adapters/warp_adapter.rs +++ b/packages/liveview/src/adapters/warp_adapter.rs @@ -6,6 +6,7 @@ use tokio_stream::wrappers::UnboundedReceiverStream; use tokio_util::task::LocalPoolHandle; use warp::ws::{Message, WebSocket}; +#[cfg(feature = "warp")] impl crate::Liveview { pub async fn upgrade(&self, ws: warp::ws::WebSocket, app: fn(Scope) -> Element) { connect(ws, self.pool.clone(), app).await;