From 02e5bc387f9cd16b4003b00a6d5ab5750e831bd8 Mon Sep 17 00:00:00 2001 From: Filip Leonarski Date: Tue, 20 Oct 2026 01:00:54 +0200 Subject: [PATCH] broker: initialize and start clear the last collection's live rugnux status /rugnux/status kept answering with the previous collection's rugnux run after POST /initialize, and also after a /start whose collection does not run rugnux - the latter under the new run's tokens. RugnuxLiveStatus gets a Clear(), called from JFJochReceiverService::ClearResults(), which /start already uses to drop the previous run's status, plots and buffered images before the tokens change. Initialize now calls ClearResults() instead of ClearImageBuffer(), so a fresh start also drops the previous run's receiver status and plots. Authentication: every rugnux endpoint (GET/PUT /config/rugnux, PUT/DELETE /config/rugnux/model, GET /rugnux/status) was already in the broker's bearer-protected set and carries bearerAuth in jfjoch_api.yaml; the HTTP auth test now checks all five. The yaml descriptions of /initialize and rugnux_live_status say so; the C++ model and frontend client are regenerated (comments only). Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01PXc1zD1yxHqaR1DGdCTHL4 --- broker/JFJochServices.h | 2 +- broker/JFJochStateMachine.cpp | 6 ++--- broker/gen/model/Rugnux_live_status.h | 4 +-- broker/jfjoch_api.yaml | 4 +-- .../src/client/@tanstack/react-query.gen.ts | 2 +- frontend/src/client/sdk.gen.ts | 2 +- frontend/src/client/types.gen.ts | 2 +- frontend/src/client/zod.gen.ts | 2 +- receiver/JFJochReceiverService.cpp | 1 + receiver/JFJochReceiverService.h | 4 +-- receiver/RugnuxLiveStatus.cpp | 6 +++++ receiver/RugnuxLiveStatus.h | 2 ++ tests/BrokerHttpAuthTest.cpp | 10 ++++++- tests/RugnuxLiveStatusTest.cpp | 26 +++++++++++++++++++ 14 files changed, 58 insertions(+), 15 deletions(-) diff --git a/broker/JFJochServices.h b/broker/JFJochServices.h index d4274dc29..4db201dae 100644 --- a/broker/JFJochServices.h +++ b/broker/JFJochServices.h @@ -80,7 +80,7 @@ public: bool GetImageFromBuffer(std::vector &v, int64_t image_number = -1); ImageBufferStatus GetImageBufferStatus() const; void ClearImageBuffer() const; - void ClearResults() const; // previous run's status, plots and buffered images + void ClearResults() const; // previous run's status, plots, live rugnux status and buffered images void LoadDetectorPixelMask(PixelMask &mask); diff --git a/broker/JFJochStateMachine.cpp b/broker/JFJochStateMachine.cpp index 182f35170..cdae150db 100644 --- a/broker/JFJochStateMachine.cpp +++ b/broker/JFJochStateMachine.cpp @@ -329,9 +329,9 @@ void JFJochStateMachine::Initialize() { ResetError(); // Clear error, we don't care what was it start_exception = nullptr; // Re-initialising discards a pending start failure - // A fresh start: no images from before, and no live rugnux analysis or model left over from the - // previous user. - services.ClearImageBuffer(); + // A fresh start: no images, plots or live rugnux status from before, and no live rugnux analysis + // or model left over from the previous user. + services.ClearResults(); { std::unique_lock ul2(rugnux_mutex); RugnuxLiveSettings s = services.GetRugnuxLive(); diff --git a/broker/gen/model/Rugnux_live_status.h b/broker/gen/model/Rugnux_live_status.h index 9107a5682..cab0e75e8 100644 --- a/broker/gen/model/Rugnux_live_status.h +++ b/broker/gen/model/Rugnux_live_status.h @@ -12,7 +12,7 @@ /* * Rugnux_live_status.h * - * Live rugnux processing of the last collection; kept until the next collection starts. Times are taken when the image puller received a message, and are in seconds since the first image (before it arrives, since now). The frame rate is `(images_received - 1) / last_image_s`. + * Live rugnux processing of the last collection; kept until the next collection starts or `POST /initialize`. Times are taken when the image puller received a message, and are in seconds since the first image (before it arrives, since now). The frame rate is `(images_received - 1) / last_image_s`. */ #ifndef Rugnux_live_status_H_ @@ -29,7 +29,7 @@ namespace org::openapitools::server::model { /// -/// Live rugnux processing of the last collection; kept until the next collection starts. Times are taken when the image puller received a message, and are in seconds since the first image (before it arrives, since now). The frame rate is `(images_received - 1) / last_image_s`. +/// Live rugnux processing of the last collection; kept until the next collection starts or `POST /initialize`. Times are taken when the image puller received a message, and are in seconds since the first image (before it arrives, since now). The frame rate is `(images_received - 1) / last_image_s`. /// class Rugnux_live_status { diff --git a/broker/jfjoch_api.yaml b/broker/jfjoch_api.yaml index 4e9768dae..58da1644d 100644 --- a/broker/jfjoch_api.yaml +++ b/broker/jfjoch_api.yaml @@ -2770,7 +2770,7 @@ components: rugnux_live_status: type: object description: | - Live rugnux processing of the last collection; kept until the next collection starts. + Live rugnux processing of the last collection; kept until the next collection starts or `POST /initialize`. Times are taken when the image puller received a message, and are in seconds since the first image (before it arrives, since now). The frame rate is `(images_received - 1) / last_image_s`. required: @@ -2917,7 +2917,7 @@ paths: This operation will reconfigure network interface of the detector. During operation of the detector it is recommended to use the `POST /pedestal` operation instead. If storage cells are used, the execution time might be few minutes. - It also clears the image buffer, disables live rugnux analysis and removes the rugnux model. + It also clears the image buffer, the previous collection's plots and live rugnux status, disables live rugnux analysis and removes the rugnux model. This is async function - one needs to use `POST /wait_till_done` to ensure operation is done. responses: diff --git a/frontend/src/client/@tanstack/react-query.gen.ts b/frontend/src/client/@tanstack/react-query.gen.ts index 04691c492..616b11276 100644 --- a/frontend/src/client/@tanstack/react-query.gen.ts +++ b/frontend/src/client/@tanstack/react-query.gen.ts @@ -16,7 +16,7 @@ import type { deleteConfigRugnuxModelData, deleteConfigRugnuxModelError, getConf * This operation will reconfigure network interface of the detector. * During operation of the detector it is recommended to use the `POST /pedestal` operation instead. * If storage cells are used, the execution time might be few minutes. - * It also clears the image buffer, disables live rugnux analysis and removes the rugnux model. + * It also clears the image buffer, the previous collection's plots and live rugnux status, disables live rugnux analysis and removes the rugnux model. * * This is async function - one needs to use `POST /wait_till_done` to ensure operation is done. * diff --git a/frontend/src/client/sdk.gen.ts b/frontend/src/client/sdk.gen.ts index 1da0a08e2..ae9c88485 100644 --- a/frontend/src/client/sdk.gen.ts +++ b/frontend/src/client/sdk.gen.ts @@ -28,7 +28,7 @@ export type Optionsbody.find("protected_run") == std::string::npos); REQUIRE(client.Get(path, wrong)->status == 401); } + // Live rugnux settings and its model are the dataset's too: changed only with a token. + REQUIRE(client.Put("/config/rugnux", R"({"enable":false})", "application/json")->status == 401); + REQUIRE(client.Put("/config/rugnux/model", "", "application/octet-stream")->status == 401); + REQUIRE(client.Delete("/config/rugnux/model")->status == 401); + REQUIRE(client.Delete("/config/rugnux/model", wrong)->status == 401); } SECTION("either token opens them") { @@ -86,6 +92,8 @@ TEST_CASE("JFJochBrokerHttp_BearerTokens", "[broker]") { REQUIRE(res->body.find("protected_run") != std::string::npos); REQUIRE(client.Get("/statistics/data_collection", other)->status == 200); REQUIRE(client.Get("/preview/plot?type=bkg_estimate", good)->status == 200); + REQUIRE(client.Get("/rugnux/status", good)->status == 200); + REQUIRE(client.Get("/config/rugnux", other)->status == 200); } SECTION("the aggregate statistics drop the measurement block instead of refusing") { diff --git a/tests/RugnuxLiveStatusTest.cpp b/tests/RugnuxLiveStatusTest.cpp index 2c3f25d80..24c8be717 100644 --- a/tests/RugnuxLiveStatusTest.cpp +++ b/tests/RugnuxLiveStatusTest.cpp @@ -46,6 +46,32 @@ TEST_CASE("RugnuxLiveStatus_BeforeFirstImage", "[RugnuxLive]") { CHECK(!status.LastImage()); } +TEST_CASE("RugnuxLiveStatus_Clear", "[RugnuxLive]") { + RugnuxLiveStatus status; + status.Start(10, 1.0, std::chrono::steady_clock::now() - 2s); + status.ImageReceived(std::chrono::steady_clock::now() - 1s); + status.Step("indexing"); + status.Probe("lattice found"); + status.Result("OK", "fine", {{"Space group", "P 1"}}, {"a warning"}); + status.Finish(RugnuxLiveState::Done); + REQUIRE(status.LastImage()); + + status.Clear(); + const auto s = status.Get(); + CHECK(s.state == RugnuxLiveState::Idle); + CHECK(s.images_expected == 0); + CHECK(s.images_received == 0); + CHECK(s.steps.empty()); + CHECK(s.probe.empty()); + CHECK(s.verdict.empty()); + CHECK(s.summary.empty()); + CHECK(s.warnings.empty()); + CHECK(!s.start_to_first_image_s); + CHECK(!s.last_image_s); + CHECK(s.elapsed_s == 0.0); + CHECK(!status.LastImage()); +} + TEST_CASE("TestImagePuller_SetsReceiveTime", "[RugnuxLive]") { TestImagePuller puller; const auto before = std::chrono::steady_clock::now();