Files
Aethera/web_server/src/Web_Server.cpp
T
2026-08-21 10:16:16 +08:00

33 lines
4.1 KiB
C++

#include "Web_Server.hpp"
#include "Graph_Metadata.hpp" /* 按图请求描述数据。 */
#include "Graph_Session.hpp"
#include "Graph_WebSocket.hpp"
#include <asio/thread_pool.hpp>
#include <drogon/drogon.h>
#include <algorithm>
#include <functional>
#include <memory>
#include <thread>
namespace aethera::web {
namespace {
drogon::HttpResponsePtr json_response(nlohmann::json value) { auto response = drogon::HttpResponse::newHttpResponse(); response->setContentTypeCode(drogon::CT_APPLICATION_JSON); response->setBody(value.dump()); return response; }
drogon::HttpResponsePtr error_response(drogon::HttpStatusCode status, std::string message) { auto response = json_response({{"error", std::move(message)}}); response->setStatusCode(status); return response; }
}
int run_web_server(std::uint16_t port, const std::filesystem::path& asset_root) {
const auto hardware_threads = std::max(2U, std::thread::hardware_concurrency());
auto graph_pool = std::make_shared<asio::thread_pool>(std::min(8U, hardware_threads));
auto registry = std::make_shared<Graph_Registry>(graph_pool->get_executor());
auto websocket = std::make_shared<Graph_WebSocket_Controller>(registry);
auto& app = drogon::app();
app.registerHandler("/api/graphs", [](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback) { callback(json_response(graph_catalog_json())); }, {drogon::Get});
app.registerHandler("/api/graphs/{1}/descriptor", [](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback, std::string graph_id) { if (!find_graph(graph_id)) { callback(error_response(drogon::k404NotFound, "unknown graph")); return; } callback(json_response({{"prop", graph_prop_descriptor_json(graph_id)}, {"state", graph_state_descriptor_json(graph_id)}, {"state_api", "/api/graphs/" + graph_id + "/state"}, {"prop_api", "/api/graphs/" + graph_id + "/prop"}})); }, {drogon::Get});
app.registerHandler("/api/graphs/{1}/state", [registry](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback, std::string graph_id) { auto session = registry->acquire(graph_id); if (!session) { callback(error_response(drogon::k404NotFound, "unknown graph")); return; } auto output = std::make_shared<std::function<void(const drogon::HttpResponsePtr&)>>(std::move(callback)); session->async_state([output](nlohmann::json state) { (*output)(json_response(std::move(state))); }); }, {drogon::Get});
app.registerHandler("/api/graphs/{1}/prop", [registry](const drogon::HttpRequestPtr&, std::function<void(const drogon::HttpResponsePtr&)>&& callback, std::string graph_id) { auto session = registry->acquire(graph_id); if (!session) { callback(error_response(drogon::k404NotFound, "unknown graph")); return; } auto output = std::make_shared<std::function<void(const drogon::HttpResponsePtr&)>>(std::move(callback)); session->async_prop([output](nlohmann::json prop) { (*output)(json_response(std::move(prop))); }); }, {drogon::Get});
app.registerHandler("/api/graphs/{1}/prop", [registry](const drogon::HttpRequestPtr& request, std::function<void(const drogon::HttpResponsePtr&)>&& callback, std::string graph_id) { auto session = registry->acquire(graph_id); if (!session) { callback(error_response(drogon::k404NotFound, "unknown graph")); return; } nlohmann::json patch; try { patch = nlohmann::json::parse(request->body()); } catch (const nlohmann::json::exception&) { callback(error_response(drogon::k400BadRequest, "invalid JSON patch")); return; } auto output = std::make_shared<std::function<void(const drogon::HttpResponsePtr&)>>(std::move(callback)); session->async_patch_prop(std::move(patch), [output](nlohmann::json result) { (*output)(json_response(std::move(result))); }); }, {drogon::Patch});
app.registerController(websocket).setDocumentRoot(asset_root.string()).setHomePage("index.html").setStaticFileHeaders({{"Cache-Control", "no-store"}}).addListener("127.0.0.1", port).setThreadNum(std::min(8U, hardware_threads)).setIdleConnectionTimeout(90).run();
graph_pool->stop();
graph_pool->join();
return 0;
}
}