From f9955f3a5afcb82a591e7f434c20fa224878c009 Mon Sep 17 00:00:00 2001 From: tv Date: Mon, 26 Oct 2026 05:27:19 +0100 Subject: add GET /stream endpoint --- src/api/mod.rs | 1 + src/api/store.rs | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) (limited to 'src/api') diff --git a/src/api/mod.rs b/src/api/mod.rs index 8f271f4..296fa5e 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -41,6 +41,7 @@ pub(crate) fn router(state: AppState, auth_state: AuthState, debug_api: bool) -> .put(store::put_store_entry) .delete(store::delete_store_entry), ) + .route("/stream", get(store::stream_store_root)) .route("/stream/{*key}", get(store::stream_store_entry)) .route("/peers", get(peers::list_peers)) .route("/peers/{peer}", delete(peers::delete_peer)) diff --git a/src/api/store.rs b/src/api/store.rs index aa9465c..c8a072f 100644 --- a/src/api/store.rs +++ b/src/api/store.rs @@ -303,16 +303,30 @@ async fn render_traced( .await } +/// `GET /stream`: follows the whole store, as `GET /store` reads it (events have an +/// empty `key`). +pub(crate) async fn stream_store_root( + State(state): State, +) -> Result { + stream(state, String::new(), Vec::new()).await +} + +/// `GET /stream/{key}`: follows one value. pub(crate) async fn stream_store_entry( State(state): State, Path(key): Path, ) -> Result { + let path = parse_key_path(&key)?; + stream(state, key, path).await +} + +/// Newline-delimited JSON events for the value at `path` (`key` as the client wrote it): +/// the current value, then one whenever the resolved value changes. +async fn stream(state: AppState, key: String, path: Vec) -> Result { if !state.is_ready().await { return Err(StatusCode::SERVICE_UNAVAILABLE); } - let path = parse_key_path(&key)?; - // Subscribe first, so nothing between the initial read and the loop is missed. let mut changes = state.change_events.subscribe(); -- cgit v1.3.1