// SPDX-FileCopyrightText: 2026 Filip Leonarski, Paul Scherrer Institute // SPDX-License-Identifier: GPL-3.0-only #pragma once #include #include #include #include #include #include #include #include "../common/JFJochMessages.h" // What a reader following the current collection needs from the broker (GET /live/start.cbor and // GET /live/events): the start message the writer of the master file received, then each data file // as a writer reports it closed and renamed into place, then the end of the collection. Fed by the // image pusher; read by the HTTP routes. One follower at a time. class LiveCollection { public: struct DataFile { uint64_t file_number = 0; std::string file; // relative to the collection's root, as the writer named it uint64_t first_image = 0; uint64_t image_count = 0; }; struct Snapshot { uint64_t generation = 0; // 0: no collection since the broker started bool started = false; // the start message is known uint64_t run_number = 0; std::string run_name; std::string file_prefix; uint64_t number_of_images = 0; int64_t images_per_file = 0; std::vector files; // in the order they were closed bool ended = false; uint64_t end_images = 0; std::string end_error; }; // A collection was accepted (/start); its start message comes with Begin, once the image pusher // starts the writers - for a DECTRIS detector only when the detector's own start message arrives. // A reader following it in between waits for it. void Expect(); // start_cbor: the start message as the writer of the master file received it. void Begin(const StartMessage &start, std::vector start_cbor); void FileClosed(uint64_t file_number, uint64_t image_count); // After every writer has acknowledged END: the data files and the master are in place. void End(uint64_t images, const std::string &error = ""); // The measurement is over: ends a collection the image pusher did not end, with this error. void EndIfOpen(const std::string &error); // The start message of the current collection; nothing before it is known. std::optional> StartCBOR() const; // Blocks until the start message arrives (when not `started_seen`), the collection has more than // `files_seen` files, has ended, a new collection has begun, or `wait` passes; returns the state then. Snapshot Wait(uint64_t generation, bool started_seen, size_t files_seen, std::chrono::milliseconds wait); Snapshot Get() const; // The single follower slot; false when another follower holds it. bool AcquireFollower(); void ReleaseFollower(); private: mutable std::mutex m; std::condition_variable cv; Snapshot state; StartMessage start_message; std::vector start_cbor; bool follower = false; };