use axum::{extract::State, response::sse::{Event, KeepAlive, Sse}};
use futures::stream::Stream;
use serde::Serialize;
use std::convert::Infallible;
use crate::web::state::WebState;
#[derive(Serialize)]
struct LogHistory<'a> {
lines: &'a [crate::logging::LogLine],
}
pub async fn stream_logs(
State(state): State<WebState>,
) -> Sse<impl Stream<Item = Result<Event, Infallible>>> {
let mut rx = state.log_tx.subscribe();
let history = state.log_ring.snapshot().await;
let stream = async_stream::stream! {
let hist = LogHistory { lines: &history };
match serde_json::to_string(&hist) {
Ok(json) => yield Ok(Event::default().event("history").data(json)),
Err(e) => {
eprintln!("[wsb] log SSE history serialize error: {e}");
return;
}
}
loop {
match rx.recv().await {
Ok(line) => {
match serde_json::to_string(&line) {
Ok(json) => yield Ok(Event::default().event("log").data(json)),
Err(e) => {
eprintln!("[wsb] log SSE serialize error: {e}");
}
}
}
Err(tokio::sync::broadcast::error::RecvError::Lagged(n)) => {
eprintln!("[wsb] log SSE client lagged by {n} events");
continue;
}
Err(tokio::sync::broadcast::error::RecvError::Closed) => break,
}
}
};
Sse::new(stream).keep_alive(KeepAlive::default())
}