99 lines
5.8 KiB
C++
99 lines
5.8 KiB
C++
#pragma once
|
|
#include "runtime/Gallery_Runtime.hpp"
|
|
#include <frame_policy/src/Throttled_Latest_Only.hpp>
|
|
#include <atomic>
|
|
#include <mutex>
|
|
#include <optional>
|
|
#include <unordered_map>
|
|
|
|
namespace aethera::mcp {
|
|
|
|
struct Control_Service::Private {
|
|
struct Entry;
|
|
struct Entry_Retirement;
|
|
struct Entry_Stop_Lifetime;
|
|
|
|
struct Gallery_Frame_Slot {
|
|
using Native_Frame = std::variant<std::unique_ptr<render_2d::Frame_2D>, std::unique_ptr<render_3d::Frame_3D>>;
|
|
explicit Gallery_Frame_Slot(bool use_3d);
|
|
Native_Frame native; /* Sole owner of the dimension-specific physical frame stored in one Frame Policy slot. */
|
|
web::Gallery_Frame_Request request{}; /* Metadata for the current use of this physical slot. */
|
|
std::uint64_t generation{}; /* Slot-local reuse generation. */
|
|
};
|
|
|
|
struct Policy_Scene : Def<Policy_Scene, Root> {
|
|
struct Private;
|
|
};
|
|
|
|
struct Policy_Sink : Def<Policy_Sink, Root> {
|
|
struct Private;
|
|
};
|
|
|
|
struct Entry {
|
|
struct Pending_Send {
|
|
std::reference_wrapper<proxy<scene::Frame>> frame; /* Non-owning borrow of the policy slot; completion releases the borrow. */
|
|
frame_policy::Frame_Completion completion; /* Sole owner of the asynchronous Sink completion. */
|
|
};
|
|
|
|
Entry(std::string id, web::Gallery_Build build, Gallery_Output output);
|
|
~Entry();
|
|
Entry(const Entry&) = delete;
|
|
Entry& operator=(const Entry&) = delete;
|
|
void start();
|
|
void stop(std::shared_ptr<Entry_Retirement> retirement) noexcept;
|
|
void request_frame(web::Gallery_Frame_Request request);
|
|
void publication_feedback(web::Gallery_Publication_Feedback feedback) noexcept;
|
|
proxy<scene::Frame> create_frame();
|
|
scene::Render_Result render(proxy<scene::Frame>& frame, scene::Render_Completion completion);
|
|
void send(proxy<scene::Frame>& frame, frame_policy::Frame_Completion completion);
|
|
[[nodiscard]] nlohmann::json schema() const;
|
|
[[nodiscard]] nlohmann::json diagnostics() const;
|
|
[[nodiscard]] std::shared_ptr<Throttled_Latest_only> current_policy() const noexcept;
|
|
[[nodiscard]] std::optional<Pending_Send> take_pending_send(std::uint64_t sequence) noexcept;
|
|
|
|
std::unique_ptr<web::Gallery_Component> components; /* Sole owner of plot models, camera and axes; declared before Scene so it outlives every Scene borrow. */
|
|
web::Gallery_Scene scene; /* Sole owner of the dimension-specific Scene. */
|
|
std::atomic<std::shared_ptr<Throttled_Latest_only>> policy{}; /* Shared only across asynchronous stop retirement. */
|
|
std::string id; /* Stable catalog identifier. */
|
|
Gallery_Output output; /* Owns a publisher copy through asynchronous Entry retirement; its borrowed captures follow Gallery_Output's contract. */
|
|
std::chrono::steady_clock::time_point started_at{std::chrono::steady_clock::now()}; /* Runtime animation clock origin. */
|
|
std::atomic_uint64_t next_sequence{}; /* Authoritative next rendered-frame sequence source. */
|
|
std::atomic<std::shared_ptr<const web::Gallery_Frame_Request>> requested_frame{}; /* Latest explicit request consumed by one subsequent policy tick. */
|
|
std::atomic<std::shared_ptr<const nlohmann::json>> datoviz_observation{}; /* Latest immutable 3D backend diagnostic publication. */
|
|
std::atomic_uint64_t ignored_publications{}; /* Frames for which no publisher accepted ownership. */
|
|
std::atomic_uint64_t failed_publications{}; /* Asynchronous publications reported unsuccessful. */
|
|
mutable std::mutex pending_send_mutex; /* Protects the publisher-feedback to Frame Policy Sink completion boundary. */
|
|
std::unordered_map<std::uint64_t, Pending_Send> pending_sends; /* In-flight asynchronous publisher borrows keyed by frame sequence. */
|
|
};
|
|
|
|
struct Entry_Retirement {
|
|
std::shared_ptr<Entry> entry; /* Sole retirement owner after the registry has detached the Entry. */
|
|
std::function<void()> completion;
|
|
~Entry_Retirement() noexcept;
|
|
};
|
|
|
|
struct Entry_Stop_Lifetime {
|
|
std::shared_ptr<Entry_Retirement> retirement; /* Declared before policy so Entry retirement is released after the stopped policy. */
|
|
std::shared_ptr<Throttled_Latest_only> policy;
|
|
};
|
|
|
|
Gallery_Output output{}; /* Immutable configuration used when each Entry is constructed. */
|
|
std::unordered_map<std::string, std::shared_ptr<Entry>> plots; /* Stable plot registry; entries retire themselves asynchronously. */
|
|
bool stop_started{}; /* Sole Control_Service lifecycle authority; public operations are unavailable after the one shutdown begins. */
|
|
};
|
|
|
|
struct Control_Service::Private::Policy_Scene::Private : Prev_Private {
|
|
explicit Private(Entry* entry) : entry(entry) {}
|
|
proxy<scene::Frame> create_frame();
|
|
scene::Render_Result render(proxy<scene::Frame>& frame, scene::Render_Completion completion);
|
|
Entry* entry; /* Required non-owning borrow; Entry owns the policy and outlives asynchronous stop completion. */
|
|
};
|
|
|
|
struct Control_Service::Private::Policy_Sink::Private : Prev_Private {
|
|
explicit Private(Entry* entry) : entry(entry) {}
|
|
void send(proxy<scene::Frame>& frame, frame_policy::Frame_Completion completion);
|
|
Entry* entry; /* Required non-owning borrow; Entry owns the policy and outlives asynchronous stop completion. */
|
|
};
|
|
|
|
} // namespace aethera::mcp
|