diff --git a/Cargo.toml b/Cargo.toml index 760e7ae..9c50ca5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -109,3 +109,7 @@ required-features = ["axum", "tracing"] [[example]] name = "rocket-hello" required-features = ["rocket"] + +[[example]] +name = "rocket-hello-channel" +required-features = ["rocket"] diff --git a/examples/hello-world-channel.html b/examples/hello-world-channel.html new file mode 100644 index 0000000..c744593 --- /dev/null +++ b/examples/hello-world-channel.html @@ -0,0 +1,42 @@ + + + + + + + Datastar SDK Demo + + + + + +
+
+

+ Datastar SDK Demo +

+ Rocket +
+

+ SSE events will be streamed from the backend to the frontend. +

+
+ + +
+ +
+
+
Hello, world!
+
+ + + \ No newline at end of file diff --git a/examples/rocket-hello-channel.rs b/examples/rocket-hello-channel.rs new file mode 100644 index 0000000..b77e037 --- /dev/null +++ b/examples/rocket-hello-channel.rs @@ -0,0 +1,86 @@ +use { + core::time::Duration, + datastar::prelude::PatchElements, + rocket::{ + Shutdown, State, get, launch, + response::{content::RawHtml, stream::Event, stream::EventStream}, + routes, + serde::{Deserialize, json::Json}, + tokio::sync::watch, + }, +}; + +#[launch] +fn rocket() -> _ { + rocket::build() + .mount("/", routes![index, hello_world, set_delay]) + .manage(watch::channel(Signals { delay: 400 })) +} + +#[get("/")] +fn index() -> RawHtml<&'static str> { + RawHtml(include_str!("hello-world-channel.html")) +} + +const MESSAGE: &str = "Hello, world!"; + +#[derive(Deserialize, Clone, Debug, Copy)] +#[serde(crate = "rocket::serde")] +struct Signals { + delay: u64, +} + +#[get("/set-delay?")] +fn set_delay( + datastar: Json, + signals_channel: &State<(watch::Sender, watch::Receiver)>, +) { + let (tx, _) = &**signals_channel; + let _ = tx.send(datastar.into_inner()); +} + +#[get("/hello-world")] +fn hello_world( + signals_channel: &State<(watch::Sender, watch::Receiver)>, + mut shutdown: Shutdown, +) -> EventStream![Event + '_] { + let mut rx = signals_channel.inner().1.clone(); + + EventStream! { + 'animation: loop { + let delay = rx.borrow().delay; + + for i in 0..=MESSAGE.len() { + let elements = format!("
{}
", &MESSAGE[0..i]); + let patch = PatchElements::new(elements); + yield patch.write_as_rocket_sse_event(); + + tokio::select! { + biased; + _ = &mut shutdown => { + break 'animation; + } + _ = rocket::tokio::time::sleep(Duration::from_millis(delay)) => { + } + + result = rx.changed() => { + if result.is_err() { + break 'animation; + } + continue 'animation; + } + } + } + + tokio::select! { + biased; + _ = &mut shutdown => break 'animation, + result = rx.changed() => { + if result.is_err() { + break 'animation; + } + } + } + } + } +}