后台服务协程化

This commit is contained in:
2026-08-18 12:15:41 +08:00
parent 1e1de64199
commit 77f856714d
19 changed files with 164 additions and 25 deletions
+11 -3
View File
@@ -67,11 +67,19 @@ private:
co_return;
throw asio::system_error(error);
}
auto response = session.handle(event);
using Completion_Channel = asio::experimental::concurrent_channel<void(asio::error_code, Web_Async_Response)>;
auto completion_channel = std::make_shared<Completion_Channel>(events_.get_executor(), 1);
session.async_handle(event, [completion_channel](Web_Async_Response response) {
completion_channel->try_send(asio::error_code{}, std::move(response));
});
asio::error_code completion_error;
auto completed = co_await completion_channel->async_receive(asio::redirect_error(asio::use_awaitable, completion_error));
if (completion_error) throw asio::system_error(completion_error);
if (completed.exception) std::rethrow_exception(completed.exception);
if (stopped_.load(std::memory_order_acquire))
co_return;
if (response)
response_handler_(std::move(*response));
if (completed.response)
response_handler_(std::move(*completed.response));
}
}
asio::experimental::concurrent_channel<void(asio::error_code, Web_Event)> events_;
+45
View File
@@ -8,6 +8,7 @@
#include <chrono>
#include <cmath>
#include <cstdint>
#include <exception>
#include <optional>
#include <string>
#include <string_view>
@@ -308,6 +309,40 @@ struct Gallery_Plot_Session::Impl {
return std::nullopt;
return Web_Response{Web_Response_Type::Pixels, std::move(*pixels)};
}
void async_handle_frame_request(Web_Response_Completion completion) {
const auto request_started = std::chrono::steady_clock::now();
if (!scene) {
completion({});
return;
}
const bool submitted = scene->async_request_frame(
[this, request_started, completion](Scene_Render_Result render_result, std::exception_ptr exception) mutable {
if (exception) {
completion({{}, std::move(exception)});
return;
}
if (render_result != Scene_Render_Result::none) {
completion({});
return;
}
try {
const auto encode_started = std::chrono::steady_clock::now();
auto pixels = scene->encode_latest_pixels();
const auto encode_finished = std::chrono::steady_clock::now();
if (pixels)
scene->record_pixel_response(request_started, encode_started, encode_finished, pixels->size());
if (!pixels) {
completion({});
return;
}
completion({Web_Response{Web_Response_Type::Pixels, std::move(*pixels)}, {}});
}
catch (...) {
completion({{}, std::current_exception()});
}
});
if (!submitted) completion({});
}
std::optional<Web_Response> handle(const Web_Event& event) {
if (std::holds_alternative<Frame_Request>(event))
return handle_frame_request();
@@ -336,10 +371,20 @@ struct Gallery_Plot_Session::Impl {
},
event);
}
void async_handle(const Web_Event& event, Web_Response_Completion completion) {
if (std::holds_alternative<Frame_Request>(event)) {
async_handle_frame_request(std::move(completion));
return;
}
completion({handle(event), {}});
}
};
Gallery_Plot_Session::Gallery_Plot_Session() : impl_(std::make_unique<Impl>()) {}
Gallery_Plot_Session::~Gallery_Plot_Session() = default;
std::optional<Web_Response> Gallery_Plot_Session::handle(const Web_Event& event) {
return impl_->handle(event);
}
void Gallery_Plot_Session::async_handle(const Web_Event& event, Web_Response_Completion completion) {
impl_->async_handle(event, std::move(completion));
}
} // namespace renderive::web
+1 -1
View File
@@ -15,7 +15,7 @@ public:
Gallery_Plot_Session& operator=(const Gallery_Plot_Session&) = delete;
[[nodiscard]] std::optional<Web_Response> handle(const Web_Event& event);
void async_handle(const Web_Event& event, Web_Response_Completion completion);
private:
struct Impl;
std::unique_ptr<Impl> impl_;
+37 -9
View File
@@ -25,20 +25,21 @@ struct Web_Plot_Session::Impl {
scene = std::move(*built_scene);
scene->activate_view();
}
std::optional<Web_Response> encode_frame() {
std::string pixels;
scene->with_frame([&](Image_View image) {
pixels = encode_pixel_frame(image, ++sequence);
});
if (pixels.empty()) return std::nullopt;
return Web_Response{Web_Response_Type::Pixels, std::move(pixels)};
}
std::optional<Web_Response> handle(const Web_Event& event) {
return std::visit([this](const auto& value) -> std::optional<Web_Response> {
using T = std::decay_t<decltype(value)>;
if constexpr (std::same_as<T, Frame_Request>) {
const auto result = scene->render_frame();
if (!result || scene->wait_for_render() != Scene_Render_Result::none)
return std::nullopt;
std::string pixels;
scene->with_frame([&](Image_View image) {
pixels = encode_pixel_frame(image, ++sequence);
});
if (pixels.empty()) return std::nullopt;
return Web_Response{Web_Response_Type::Pixels,
std::move(pixels)};
if (!result || scene->wait_for_render() != Scene_Render_Result::none) return std::nullopt;
return encode_frame();
} else if constexpr (std::same_as<T, Viewport_Resize>) {
viewport = value.size;
rebuild();
@@ -48,10 +49,37 @@ struct Web_Plot_Session::Impl {
return std::nullopt;
}, event);
}
void async_handle(const Web_Event& event, Web_Response_Completion completion) {
if (!std::holds_alternative<Frame_Request>(event)) {
completion({handle(event), {}});
return;
}
const auto result = scene->render_frame(
[this, completion](Scene_Render_Result render_result, std::exception_ptr exception) mutable {
if (exception) {
completion({{}, std::move(exception)});
return;
}
if (render_result != Scene_Render_Result::none) {
completion({});
return;
}
try {
completion({encode_frame(), {}});
}
catch (...) {
completion({{}, std::current_exception()});
}
});
if (!result || *result != Plot_Render_Status::rendered) completion({});
}
};
Web_Plot_Session::Web_Plot_Session() : impl_(std::make_unique<Impl>()) {}
Web_Plot_Session::~Web_Plot_Session() = default;
std::optional<Web_Response> Web_Plot_Session::handle(const Web_Event& event) {
return impl_->handle(event);
}
void Web_Plot_Session::async_handle(const Web_Event& event, Web_Response_Completion completion) {
impl_->async_handle(event, std::move(completion));
}
} // namespace renderive::web
+8 -2
View File
@@ -2,6 +2,8 @@
#include "Web_Event.h"
#include <exception>
#include <functional>
#include <memory>
#include <optional>
#include <string>
@@ -14,7 +16,11 @@ struct Web_Response {
Web_Response_Type type = Web_Response_Type::Pixels;
std::string payload;
};
struct Web_Async_Response {
std::optional<Web_Response> response;
std::exception_ptr exception;
};
using Web_Response_Completion = std::function<void(Web_Async_Response)>;
class Web_Plot_Session final {
public:
Web_Plot_Session();
@@ -23,7 +29,7 @@ public:
Web_Plot_Session& operator=(const Web_Plot_Session&) = delete;
[[nodiscard]] std::optional<Web_Response> handle(const Web_Event& event);
void async_handle(const Web_Event& event, Web_Response_Completion completion);
private:
struct Impl;
std::unique_ptr<Impl> impl_;
@@ -3,6 +3,7 @@
#include "Gallery_Performance_Types.h"
#include "Gallery_Types.h"
#include "adminive/adminive.hpp"
#include <renderive/scene/base/Scene_Base.hpp>
#include <nlohmann/json.hpp>
#include <chrono>
#include <cstddef>
@@ -22,6 +23,7 @@ public:
virtual void resize(int width, int height) = 0;
virtual void dispatch(const Gallery_Input_Event& event) = 0;
[[nodiscard]] virtual bool request_frame() = 0;
[[nodiscard]] virtual bool async_request_frame(Scene_Render_Completion completion) = 0;
[[nodiscard]] virtual std::optional<std::string> encode_latest_pixels() = 0;
virtual void record_pixel_response(std::chrono::steady_clock::time_point request_started, std::chrono::steady_clock::time_point encode_started, std::chrono::steady_clock::time_point encode_finished, std::size_t pixel_bytes) = 0;
[[nodiscard]] virtual std::string action(const Gallery_Action_Request& request, bool& recognized) = 0;
+10 -1
View File
@@ -26,6 +26,7 @@
#include <span>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
namespace renderive::web {
@@ -159,7 +160,15 @@ public:
++render_count_;
return true;
}
bool async_request_frame(Scene_Render_Completion completion) override {
update_samples();
const auto result = scene_->render_frame(
[this, completion = std::move(completion)](Scene_Render_Result render_result, std::exception_ptr exception) mutable {
if (!exception && render_result == Scene_Render_Result::none) ++render_count_;
completion(render_result, std::move(exception));
});
return result && *result == Plot_Render_Status::rendered;
}
std::optional<std::string> encode_latest_pixels() override {
std::string result;
scene_->with_frame([&](Image_View image) {
+9 -1
View File
@@ -13,6 +13,7 @@
#include <memory>
#include <stdexcept>
#include <string>
#include <utility>
#include <vector>
namespace renderive::web {
@@ -137,7 +138,14 @@ public:
++render_count_;
return true;
}
bool async_request_frame(Scene_Render_Completion completion) override {
const auto result = scene_->request_frame(
[this, completion = std::move(completion)](Scene_Render_Result render_result, std::exception_ptr exception) mutable {
if (!exception && render_result == Scene_Render_Result::none) ++render_count_;
completion(render_result, std::move(exception));
});
return result == Frame_Request_Result::none;
}
std::optional<std::string> encode_latest_pixels() override {
const auto frame = scene_->latest_frame();
if (!frame || frame->rgba8.empty()) return std::nullopt;