aboutsummaryrefslogtreecommitdiffstats
path: root/src/api/dashboard/mod.rs
diff options
context:
space:
mode:
authortv <tv@krebsco.de>2026-10-30 21:45:22 +0100
committertv <tv@krebsco.de>2026-10-30 21:45:22 +0100
commitdb6e1ad6592aefce8a99db8478fac0baae09b228 (patch)
tree7f7f133eba4dbc5e8bc18effab81868cf16dc75f /src/api/dashboard/mod.rs
parent114c9cb6f45abedb9b90ef6c9194570ff84fbda2 (diff)
dashboard: click on live/reconnecting triggers
Diffstat (limited to 'src/api/dashboard/mod.rs')
-rw-r--r--src/api/dashboard/mod.rs24
1 files changed, 21 insertions, 3 deletions
diff --git a/src/api/dashboard/mod.rs b/src/api/dashboard/mod.rs
index 7679787..dd454ec 100644
--- a/src/api/dashboard/mod.rs
+++ b/src/api/dashboard/mod.rs
@@ -21,10 +21,10 @@ use std::time::Duration;
use axum::http::{HeaderValue, StatusCode, header::CONTENT_TYPE};
use axum::response::sse::{Event, KeepAlive, Sse};
use axum::response::{Html, IntoResponse, Response};
-use axum::routing::get;
+use axum::routing::{get, post};
use axum::{Extension, Router};
use serde_json::{Map, Value as JsonValue, json};
-use tokio::sync::{broadcast, watch};
+use tokio::sync::{Notify, broadcast, watch};
use tokio::time::Instant;
use crate::locks::MutexExt;
@@ -60,6 +60,8 @@ struct Hub {
/// `{"paths": [...]}`, or `{"all": true}` if too many or not known.
documents: broadcast::Sender<Arc<String>>,
control: Mutex<Control>,
+ /// Someone asked for it now (`refresh`): a tick at once, members asked again.
+ poke: Notify,
/// True once the node stops: every client gets an `offline` event, and its stream
/// ends (so the HTTP server needn't wait for clients to go).
closing: watch::Receiver<bool>,
@@ -81,6 +83,7 @@ impl Hub {
latest,
patches,
documents,
+ poke: Notify::new(),
control: Mutex::new(Control {
running: false,
wanted_until: Instant::now(),
@@ -151,7 +154,13 @@ impl Hub {
})));
last = Some(snapshot);
}
- tokio::time::sleep(TICK).await;
+ let poked = tokio::select! {
+ () = tokio::time::sleep(TICK) => false,
+ () = self.poke.notified() => true,
+ };
+ if poked {
+ graph_due = Instant::now();
+ }
if let Some(changed) = document_changes(&mut changes) {
let _ = self.documents.send(Arc::new(changed.to_string()));
}
@@ -360,6 +369,7 @@ pub(crate) fn router(state: AppState, closing: watch::Receiver<bool>) -> Router<
.route("/admin/dashboard", get(page_html))
.route("/admin/dashboard/state", get(current_state))
.route("/admin/dashboard/events", get(events))
+ .route("/admin/dashboard/refresh", post(refresh))
.layer(Extension(Hub::new(state, closing)))
}
@@ -389,6 +399,14 @@ async fn page_html() -> Html<&'static str> {
Html(page().1.as_str())
}
+/// `POST /admin/dashboard/refresh`: a tick now rather than at the next `TICK`, and the
+/// members asked for their links again; what changed comes as events, as ever.
+async fn refresh(Extension(hub): Extension<Arc<Hub>>) -> StatusCode {
+ hub.want();
+ hub.poke.notify_one();
+ StatusCode::NO_CONTENT
+}
+
/// `GET /admin/dashboard/state`: the latest snapshot, for a client that wants it whole.
async fn current_state(Extension(hub): Extension<Arc<Hub>>) -> Response {
hub.want();