后台服务协程化
This commit is contained in:
@@ -1,78 +1,68 @@
|
||||
#include "Gallery_WebSocket_Controller.h"
|
||||
|
||||
#include "Asio_WebSocket_Scene_Loop.h"
|
||||
#include "Gallery_Plot_Session.h"
|
||||
#include "Web_Event_Adapter.h"
|
||||
#include <renderive/error/Error_Policy.hpp>
|
||||
|
||||
#include <trantor/utils/Logger.h>
|
||||
|
||||
#include <exception>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
|
||||
#include <utility>
|
||||
namespace renderive::web {
|
||||
|
||||
void Gallery_WebSocket_Controller::handleNewConnection(
|
||||
const drogon::HttpRequestPtr&,
|
||||
const drogon::WebSocketConnectionPtr& connection) {
|
||||
connection->setContext(std::make_shared<Gallery_Plot_Session>());
|
||||
connection->setPingMessage("renderive-gallery", std::chrono::seconds(20));
|
||||
LOG_INFO << "Renderive Gallery WebSocket connected: "
|
||||
<< connection->peerAddr().toIpPort();
|
||||
}
|
||||
|
||||
void Gallery_WebSocket_Controller::handleNewMessage(
|
||||
const drogon::WebSocketConnectionPtr& connection,
|
||||
std::string&& message,
|
||||
const drogon::WebSocketMessageType& type) {
|
||||
if (type == drogon::WebSocketMessageType::Ping ||
|
||||
type == drogon::WebSocketMessageType::Pong ||
|
||||
type == drogon::WebSocketMessageType::Close) {
|
||||
namespace {
|
||||
using Scene_Loop = Asio_WebSocket_Scene_Loop<Gallery_Plot_Session>;
|
||||
void send_response(const std::weak_ptr<drogon::WebSocketConnection>& weak_connection, Web_Response response) {
|
||||
const auto connection = weak_connection.lock();
|
||||
if (!connection || !connection->connected())
|
||||
return;
|
||||
const auto message_type = response.type == Web_Response_Type::Pixels ? drogon::WebSocketMessageType::Binary : drogon::WebSocketMessageType::Text;
|
||||
connection->send(response.payload.data(), response.payload.size(), message_type);
|
||||
}
|
||||
void fail_session(const std::weak_ptr<drogon::WebSocketConnection>& weak_connection, std::exception_ptr exception) {
|
||||
static_cast<void>(::renderive::error::capture("handling Gallery WebSocket scene loop", exception));
|
||||
LOG_ERROR << "Renderive Gallery WebSocket scene loop failed";
|
||||
if (const auto connection = weak_connection.lock(); connection && connection->connected())
|
||||
connection->shutdown(drogon::CloseCode::kUnexpectedCondition, "Renderive Gallery rendering failed");
|
||||
}
|
||||
}
|
||||
Gallery_WebSocket_Controller::Gallery_WebSocket_Controller(std::shared_ptr<asio::thread_pool> scene_pool) : scene_pool_(std::move(scene_pool)) {}
|
||||
void Gallery_WebSocket_Controller::handleNewConnection(const drogon::HttpRequestPtr&, const drogon::WebSocketConnectionPtr& connection) {
|
||||
const std::weak_ptr<drogon::WebSocketConnection> weak_connection = connection;
|
||||
connection->setContext(Scene_Loop::create(scene_pool_->get_executor(), [weak_connection](Web_Response response) {
|
||||
send_response(weak_connection, std::move(response));
|
||||
}, [weak_connection](std::exception_ptr exception) {
|
||||
fail_session(weak_connection, exception);
|
||||
}));
|
||||
connection->setPingMessage("renderive-gallery", std::chrono::seconds(20));
|
||||
LOG_INFO << "Renderive Gallery WebSocket connected: " << connection->peerAddr().toIpPort();
|
||||
}
|
||||
void Gallery_WebSocket_Controller::handleNewMessage(const drogon::WebSocketConnectionPtr& connection, std::string&& message, const drogon::WebSocketMessageType& type) {
|
||||
if (type == drogon::WebSocketMessageType::Ping || type == drogon::WebSocketMessageType::Pong || type == drogon::WebSocketMessageType::Close)
|
||||
return;
|
||||
}
|
||||
if (type != drogon::WebSocketMessageType::Text) {
|
||||
connection->shutdown(drogon::CloseCode::kInvalidMessage,
|
||||
"Renderive Gallery accepts text events only");
|
||||
connection->shutdown(drogon::CloseCode::kInvalidMessage, "Renderive Gallery accepts text events only");
|
||||
return;
|
||||
}
|
||||
if (message.size() > 64 * 1024) {
|
||||
connection->shutdown(drogon::CloseCode::kMessageTooBig,
|
||||
"Renderive Gallery event is too large");
|
||||
connection->shutdown(drogon::CloseCode::kMessageTooBig, "Renderive Gallery event is too large");
|
||||
return;
|
||||
}
|
||||
const auto event = Web_Event_Adapter::decode(message);
|
||||
if (!event) {
|
||||
connection->shutdown(drogon::CloseCode::kWrongMessageContent,
|
||||
"Invalid Renderive Gallery event");
|
||||
connection->shutdown(drogon::CloseCode::kWrongMessageContent, "Invalid Renderive Gallery event");
|
||||
return;
|
||||
}
|
||||
const auto session = connection->getContext<Gallery_Plot_Session>();
|
||||
const auto session = connection->getContext<Scene_Loop>();
|
||||
if (!session) {
|
||||
connection->shutdown(drogon::CloseCode::kUnexpectedCondition,
|
||||
"Renderive Gallery session is unavailable");
|
||||
connection->shutdown(drogon::CloseCode::kUnexpectedCondition, "Renderive Gallery session is unavailable");
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (auto response = session->handle(*event)) {
|
||||
const auto message_type = response->type == Web_Response_Type::Pixels
|
||||
? drogon::WebSocketMessageType::Binary
|
||||
: drogon::WebSocketMessageType::Text;
|
||||
connection->send(response->payload.data(), response->payload.size(),
|
||||
message_type);
|
||||
}
|
||||
} catch (...) {
|
||||
static_cast<void>(::renderive::error::capture(
|
||||
"handling Gallery WebSocket request", std::current_exception()));
|
||||
LOG_ERROR << "Renderive Gallery session failed";
|
||||
connection->shutdown(drogon::CloseCode::kUnexpectedCondition,
|
||||
"Renderive Gallery rendering failed");
|
||||
}
|
||||
if (session->submit(std::move(*event)) == Scene_Loop::Submit_Result::queue_full)
|
||||
connection->shutdown(drogon::CloseCode::kViolation, "Renderive Gallery scene queue is full");
|
||||
}
|
||||
|
||||
void Gallery_WebSocket_Controller::handleConnectionClosed(
|
||||
const drogon::WebSocketConnectionPtr& connection) {
|
||||
LOG_INFO << "Renderive Gallery WebSocket closed: "
|
||||
<< connection->peerAddr().toIpPort();
|
||||
void Gallery_WebSocket_Controller::handleConnectionClosed(const drogon::WebSocketConnectionPtr& connection) {
|
||||
LOG_INFO << "Renderive Gallery WebSocket closed: " << connection->peerAddr().toIpPort();
|
||||
if (const auto session = connection->getContext<Scene_Loop>())
|
||||
session->stop();
|
||||
connection->clearContext();
|
||||
}
|
||||
|
||||
} // namespace renderive::web
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user