sse: seq plumbing + subscribe-first dedupe dance
This commit is contained in:
parent
8c186d4fb7
commit
1340a654e7
5 changed files with 197 additions and 37 deletions
|
|
@ -191,6 +191,12 @@ async fn serve_shared_js() -> impl IntoResponse {
|
|||
|
||||
#[derive(Serialize)]
|
||||
struct StateSnapshot {
|
||||
/// Bus seq at the moment this snapshot was assembled. Clients dedupe
|
||||
/// their buffered SSE traffic against this value: events with
|
||||
/// `seq <= snapshot.seq` are already reflected (or pre-date the
|
||||
/// snapshot); `seq > snapshot.seq` is post-snapshot. Reset to 0 on
|
||||
/// harness restart — clients treat reconnect as a fresh world.
|
||||
seq: u64,
|
||||
label: String,
|
||||
dashboard_port: u16,
|
||||
/// `"online"` | `"needs_login_idle"` | `"needs_login_in_progress"`.
|
||||
|
|
@ -226,6 +232,9 @@ struct SessionView {
|
|||
}
|
||||
|
||||
async fn api_state(State(state): State<AppState>) -> axum::Json<StateSnapshot> {
|
||||
// Capture seq *before* any reads so the dedupe contract is
|
||||
// "events with seq > snapshot.seq are post-snapshot, never missed."
|
||||
let seq = state.bus.current_seq();
|
||||
drop_if_finished(&state.session);
|
||||
let login = *state.login.lock().unwrap();
|
||||
let session_snapshot = state.session.lock().unwrap().clone();
|
||||
|
|
@ -251,6 +260,7 @@ async fn api_state(State(state): State<AppState>) -> axum::Json<StateSnapshot> {
|
|||
let model = state.bus.model();
|
||||
let token_usage = state.bus.last_usage();
|
||||
axum::Json(StateSnapshot {
|
||||
seq,
|
||||
label: state.label.clone(),
|
||||
dashboard_port,
|
||||
status,
|
||||
|
|
@ -338,10 +348,15 @@ async fn post_send(State(state): State<AppState>, Form(form): Form<SendForm>) ->
|
|||
}
|
||||
}
|
||||
|
||||
async fn events_history(
|
||||
State(state): State<AppState>,
|
||||
) -> axum::Json<Vec<crate::events::LiveEvent>> {
|
||||
axum::Json(state.bus.history())
|
||||
async fn events_history(State(state): State<AppState>) -> axum::Json<serde_json::Value> {
|
||||
// Capture seq *before* the read so dedupe is "drop buffered events
|
||||
// you've already seen in history", never "lose an event that fired
|
||||
// between the read and the timestamp." Historical rows have no
|
||||
// per-row seq; only the high-water mark matters for the dedupe
|
||||
// window.
|
||||
let seq = state.bus.current_seq();
|
||||
let events = state.bus.history();
|
||||
axum::Json(serde_json::json!({ "seq": seq, "events": events }))
|
||||
}
|
||||
|
||||
async fn events_stream(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue