Files
Aethera/mcp/core/Control_Service.ipp
T
2026-09-03 15:31:39 +08:00

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