Skip to content

Commit 6b759fe

Browse files
authored
Add hello-world-channel example. (#3)
1 parent 6443d3a commit 6b759fe

File tree

3 files changed

+132
-0
lines changed

3 files changed

+132
-0
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,3 +110,7 @@ required-features = ["axum", "tracing"]
110110
[[example]]
111111
name = "rocket-hello"
112112
required-features = ["rocket"]
113+
114+
[[example]]
115+
name = "rocket-hello-channel"
116+
required-features = ["rocket"]

examples/hello-world-channel.html

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
<!-- This is auto-generated by Datastar. DO NOT EDIT. -->
2+
3+
<!DOCTYPE html>
4+
<html lang="en">
5+
6+
<head>
7+
<title>Datastar SDK Demo</title>
8+
<script src="https://unpkg.com/@tailwindcss/browser@4"></script>
9+
<script type="module" src="https://cdn.jsdelivr.net/gh/starfederation/datastar@main/bundles/datastar.js"></script>
10+
</head>
11+
12+
<body class="bg-white dark:bg-gray-900 text-lg max-w-xl mx-auto my-16">
13+
<div data-signals-delay="400"
14+
class="bg-white dark:bg-gray-800 text-gray-500 dark:text-gray-400 rounded-lg px-6 py-8 ring shadow-xl ring-gray-900/5 space-y-2">
15+
<div class="flex justify-between items-center">
16+
<h1 class="text-gray-900 dark:text-white text-3xl font-semibold">
17+
Datastar SDK Demo
18+
</h1>
19+
<img src="https://data-star.dev/static/images/rocket-64x64.png" alt="Rocket" width="64" height="64" />
20+
</div>
21+
<p class="mt-2">
22+
SSE events will be streamed from the backend to the frontend.
23+
</p>
24+
<div class="space-x-2">
25+
<label for="delay">
26+
Delay in milliseconds
27+
</label>
28+
<input data-bind-delay id="delay" type="number" step="100" min="0"
29+
class="w-36 rounded-md border border-gray-300 px-3 py-2 placeholder-gray-400 shadow-sm focus:border-sky-500 focus:outline focus:outline-sky-500 dark:disabled:border-gray-700 dark:disabled:bg-gray-800/20" />
30+
</div>
31+
<button data-on-click="@get(&#39;/set-delay&#39;)"
32+
class="rounded-md bg-sky-500 px-5 py-2.5 leading-5 font-semibold text-white hover:bg-sky-700 hover:text-gray-100 cursor-pointer">
33+
Start
34+
</button>
35+
</div>
36+
<div class="my-16 text-8xl font-bold text-transparent" data-on-load="@get(&#39;/hello-world&#39;)"
37+
style="background: linear-gradient(to right in oklch, red, orange, yellow, green, blue, blue, violet); background-clip: text">
38+
<div id="message">Hello, world!</div>
39+
</div>
40+
</body>
41+
42+
</html>

examples/rocket-hello-channel.rs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
use {
2+
core::time::Duration,
3+
datastar::prelude::PatchElements,
4+
rocket::{
5+
Shutdown, State, get, launch,
6+
response::{content::RawHtml, stream::Event, stream::EventStream},
7+
routes,
8+
serde::{Deserialize, json::Json},
9+
tokio::sync::watch,
10+
},
11+
};
12+
13+
#[launch]
14+
fn rocket() -> _ {
15+
rocket::build()
16+
.mount("/", routes![index, hello_world, set_delay])
17+
.manage(watch::channel(Signals { delay: 400 }))
18+
}
19+
20+
#[get("/")]
21+
fn index() -> RawHtml<&'static str> {
22+
RawHtml(include_str!("hello-world-channel.html"))
23+
}
24+
25+
const MESSAGE: &str = "Hello, world!";
26+
27+
#[derive(Deserialize, Clone, Debug, Copy)]
28+
#[serde(crate = "rocket::serde")]
29+
struct Signals {
30+
delay: u64,
31+
}
32+
33+
#[get("/set-delay?<datastar>")]
34+
fn set_delay(
35+
datastar: Json<Signals>,
36+
signals_channel: &State<(watch::Sender<Signals>, watch::Receiver<Signals>)>,
37+
) {
38+
let (tx, _) = &**signals_channel;
39+
let _ = tx.send(datastar.into_inner());
40+
}
41+
42+
#[get("/hello-world")]
43+
fn hello_world(
44+
signals_channel: &State<(watch::Sender<Signals>, watch::Receiver<Signals>)>,
45+
mut shutdown: Shutdown,
46+
) -> EventStream![Event + '_] {
47+
let mut rx = signals_channel.inner().1.clone();
48+
49+
EventStream! {
50+
'animation: loop {
51+
let delay = rx.borrow().delay;
52+
53+
for i in 0..=MESSAGE.len() {
54+
let elements = format!("<div id='message'>{}</div>", &MESSAGE[0..i]);
55+
let patch = PatchElements::new(elements);
56+
yield patch.write_as_rocket_sse_event();
57+
58+
tokio::select! {
59+
biased;
60+
_ = &mut shutdown => {
61+
break 'animation;
62+
}
63+
_ = rocket::tokio::time::sleep(Duration::from_millis(delay)) => {
64+
}
65+
66+
result = rx.changed() => {
67+
if result.is_err() {
68+
break 'animation;
69+
}
70+
continue 'animation;
71+
}
72+
}
73+
}
74+
75+
tokio::select! {
76+
biased;
77+
_ = &mut shutdown => break 'animation,
78+
result = rx.changed() => {
79+
if result.is_err() {
80+
break 'animation;
81+
}
82+
}
83+
}
84+
}
85+
}
86+
}

0 commit comments

Comments
 (0)