ソースを参照

feat(liveview): add rocket adapter (#1761)

Georges KABBOUCHI 1 年間 前
コミット
3733fbf47d

+ 12 - 1
packages/liveview/Cargo.toml

@@ -38,6 +38,10 @@ salvo = { version = "0.44.1", optional = true, features = ["ws"] }
 once_cell = "1.17.1"
 once_cell = "1.17.1"
 async-trait = "0.1.71"
 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 is ... complicated?
 # actix-files = { version = "0.6.2", optional = true }
 # actix-files = { version = "0.6.2", optional = true }
 # actix-web = { version = "4.2.1", optional = true }
 # actix-web = { version = "4.2.1", optional = true }
@@ -49,13 +53,16 @@ tokio = { workspace = true, features = ["full"] }
 dioxus = { workspace = true }
 dioxus = { workspace = true }
 warp = "0.3.3"
 warp = "0.3.3"
 axum = { version = "0.6.1", features = ["ws"] }
 axum = { version = "0.6.1", features = ["ws"] }
-salvo = { version = "0.44.1", features = ["affix", "ws"] }
+# salvo = { version = "0.44.1", features = ["affix", "ws"] }
+rocket = "0.5.0"
+rocket_ws = "0.1.0"
 tower = "0.4.13"
 tower = "0.4.13"
 
 
 [features]
 [features]
 default = ["hot-reload"]
 default = ["hot-reload"]
 # actix = ["actix-files", "actix-web", "actix-ws"]
 # actix = ["actix-files", "actix-web", "actix-ws"]
 hot-reload = ["dioxus-hot-reload"]
 hot-reload = ["dioxus-hot-reload"]
+rocket = ["dep:rocket", "dep:rocket_ws"]
 
 
 [[example]]
 [[example]]
 name = "axum"
 name = "axum"
@@ -68,3 +75,7 @@ required-features = ["salvo"]
 [[example]]
 [[example]]
 name = "warp"
 name = "warp"
 required-features = ["warp"]
 required-features = ["warp"]
+
+[[example]]
+name = "rocket"
+required-features = ["rocket"]

+ 1 - 0
packages/liveview/README.md

@@ -28,6 +28,7 @@ The current backend frameworks supported include:
 - Axum
 - Axum
 - Warp
 - Warp
 - Salvo
 - Salvo
+- Rocket
 
 
 Dioxus-LiveView exports some primitives to wire up an app into an existing backend framework.
 Dioxus-LiveView exports some primitives to wire up an app into an existing backend framework.
 
 

+ 76 - 0
packages/liveview/examples/rocket.rs

@@ -0,0 +1,76 @@
+#[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(cx: Scope) -> Element {
+    let mut num = use_state(cx, || 0);
+
+    cx.render(rsx! {
+        div {
+            "hello Rocket! {num}"
+            button { onclick: move |_| num += 1, "Increment" }
+        }
+    })
+}
+
+fn index_page_with_glue(glue: &str) -> RawHtml<String> {
+    RawHtml(format!(
+        r#"
+        <!DOCTYPE html>
+        <html>
+            <head> <title>Dioxus LiveView with Rocket</title>  </head>
+            <body> <div id="main"></div> </body>
+            {glue}
+        </html>
+        "#,
+        glue = glue
+    ))
+}
+
+#[get("/")]
+async fn index(config: &Config) -> RawHtml<String> {
+    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<String> {
+    index_page_with_glue(&dioxus_liveview::interpreter_glue("/ws"))
+}
+
+#[get("/ws")]
+fn ws(ws: WebSocket, pool: &State<LiveViewPool>) -> 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");
+}

+ 25 - 0
packages/liveview/src/adapters/rocket_adapter.rs

@@ -0,0 +1,25 @@
+use crate::{LiveViewError, LiveViewSocket};
+use rocket::futures::{SinkExt, StreamExt};
+use rocket_ws::{result::Error, stream::DuplexStream, Message};
+
+/// 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<Message, Error>) -> Result<Vec<u8>, LiveViewError> {
+    message
+        .map_err(|_| LiveViewError::SendingFailed)?
+        .into_text()
+        .map(|s| s.into_bytes())
+        .map_err(|_| LiveViewError::SendingFailed)
+}
+
+async fn transform_tx(message: Vec<u8>) -> Result<Message, Error> {
+    Ok(Message::Text(String::from_utf8_lossy(&message).to_string()))
+}

+ 5 - 0
packages/liveview/src/lib.rs

@@ -18,6 +18,11 @@ pub mod adapters {
 
 
     #[cfg(feature = "salvo")]
     #[cfg(feature = "salvo")]
     pub use salvo_adapter::*;
     pub use salvo_adapter::*;
+
+    #[cfg(feature = "rocket")]
+    pub mod rocket_adapter;
+    #[cfg(feature = "rocket")]
+    pub use rocket_adapter::*;
 }
 }
 
 
 pub use adapters::*;
 pub use adapters::*;