#[macro_use] extern crate rocket; use maud::{html, Markup, PreEscaped, DOCTYPE}; use rocket::response::stream::{Event, EventStream}; use rocket::tokio::time::{interval, Duration}; struct SsePayload { } #[get("/sse")] async fn sse() -> EventStream![] { EventStream! { let mut interval = interval(Duration::from_secs(2)); loop { interval.tick().await; yield Event::data(format!("Updated time: {:?}", chrono::Utc::now())); } } } #[get("/")] fn index() -> Markup { html! { (DOCTYPE) html lang="en" { head { meta charset="utf-8"; title { "Live Updates with SSE" } style { "body { color: white; display: flex; flex-direction: column; align-items: center; justify-content: center; height: 100vh; background: rgb(34,187,195); background: linear-gradient(0deg, rgba(34,187,195,1) 0%, rgba(102,45,253,1) 100%); font-family: sans-serif; } .glassy { background: rgba(255, 255, 255, 0.2); border-radius: 16px; box-shadow: 0 4px 30px rgba(0, 0, 0, 0.1); backdrop-filter: blur(2.8px); -webkit-backdrop-filter: blur(2.8px); border: 1px solid rgba(255, 255, 255, 0.3); } .data-grid { margin: 2em; padding: 2em; display: flex; flex-direction: column; align-items: center; justify-content: center; border-radius: 18px; } .data-cell { margin: 0.5em 1em; padding: 1em; border-radius: 18px; display: flex; flex-direction: column; width: 100%; } " } script { (PreEscaped("const eventSource = new EventSource('/sse'); eventSource.onmessage = (event) => { document.getElementById('updates').innerText = event.data; };")) } } body style="" { h1 style="align-items: center;" { "willdaten dashboard" } div class="glassy data-grid" { div class="glassy data-cell" { h3 { "Fetcher" } div id="updates" { "Waiting for updates..." } } div class="glassy data-cell" { h3 { "Database" } div id="updates" { "Waiting for updates..." } } div class="glassy data-cell" { h3 { "Statistics" } div id="updates" { "Waiting for updates..." } } } } } } } #[launch] fn rocket() -> _ { rocket::build().mount("/", routes![index, sse]) }