From 52b3cd46c76fd4be18aeb8422a08a073484b9fad Mon Sep 17 00:00:00 2001 From: Rutger Broekhoff Date: Sat, 29 Aug 2026 12:01:42 +0200 Subject: More module implementation partition units --- server/src/srv.cppm | 251 ++-------------------------------------------------- 1 file changed, 8 insertions(+), 243 deletions(-) (limited to 'server/src/srv.cppm') diff --git a/server/src/srv.cppm b/server/src/srv.cppm index 904bf1a..1d082fb 100644 --- a/server/src/srv.cppm +++ b/server/src/srv.cppm @@ -1,166 +1,14 @@ module; -#include #include -#include -#include -#include -#include -#include -#include -#include - -#include export module routemon:srv; -import std; import :api; -import :config; -import :gpx; import :http.server; -import :locale; -import :log; -import :problem; -import :req_ctx; -import :util; - -namespace beast = boost::beast; -namespace json = boost::json; -namespace net = boost::asio; -using tcp = boost::asio::ip::tcp; namespace routemon::srv { -class gpx_parse_error_category_impl : public std::error_category -{ -public: - char const* name() const noexcept override { return "gpx_parse"; } - - auto message(int condition) const noexcept -> std::string override - { - std::ignore = condition; - return "failed to parse GPX file"; - } -}; - -auto gpx_parse_error_category() noexcept -> gpx_parse_error_category_impl const& -{ - static auto const inst = gpx_parse_error_category_impl{}; - return inst; -} - -auto gpx_parse_error() noexcept -> std::error_code -{ - return std::error_code{1, gpx_parse_error_category()}; -} - -class gpx_parse_result -{ - std::variant res_; - -public: - auto set_exception(std::exception_ptr ex) noexcept { res_ = ex; } - auto set_gpx_file(gpx::file&& f) noexcept { res_ = std::move(f); } - - auto unwrap() -> gpx::file&& - { - return std::visit( - util::overloaded{ - [](std::exception_ptr ex) -> gpx::file&& - { - if (ex) - std::rethrow_exception(ex); - else - throw std::runtime_error{"no GPX file parse result available"}; - }, - [](gpx::file&& f) -> gpx::file&& { return std::move(f); }, - }, - std::move(res_)); - } -}; - -struct readable_gpx_body -{ - using value_type = gpx_parse_result; - - class reader - { - gpx::reader r_; - util::not_null res_; - - public: - template - explicit reader(bhttp::header&, value_type& v) : res_{&v} - { - } - - // The following methods (which are called by Beast) are marked - // noexcept, since Beast does not ensure that exceptions thrown - // here are appropriately directed to the caller of - // (async_)read(_some), so throwing here might cause the program - // to crash. - - auto - init(boost::optional /* n */, beast::error_code& ec) noexcept - -> void - { - try - { - r_.init(); - ec = {}; - } - catch (std::exception& ex) - { - res_->set_exception(std::current_exception()); - ec = gpx_parse_error(); - } - } - - auto - put(beast::concepts::const_buffer_sequence auto b, - beast::error_code& ec) noexcept -> std::size_t - { - auto total = 0uz; - try - { - for (auto it = net::buffer_sequence_begin(b); - it != net::buffer_sequence_end(b); it++) - { - r_.put( - std::string_view{ - static_cast(it->data()), it->size() - }); - total += it->size(); - } - ec = {}; - } - catch (std::exception& ex) - { - res_->set_exception(std::current_exception()); - ec = gpx_parse_error(); - } - return total; - } - - auto finish(beast::error_code& ec) noexcept - { - try - { - res_->set_gpx_file(r_.finish()); - ec = {}; - } - catch (std::exception& ex) - { - res_->set_exception(std::current_exception()); - ec = gpx_parse_error(); - } - } - }; -}; -static_assert(bhttp::concepts::body); -static_assert(bhttp::concepts::body_reader); - class handler { api::handler inner_; @@ -171,112 +19,29 @@ public: private: auto handle_process_gpx(l0_ctx ctx, http::readable_request r) - -> net::awaitable - { - auto gpx_file = gpx::file{}; - try - { - auto req = - co_await http::read_request(ctx, std::move(r)); - gpx_file = std::move(req->body().unwrap()); - } - catch (std::exception& ex) - { - // TODO: more detailed problem reporting - auto tpl = problem::tpl{ - .status = bhttp::status::bad_request, - .title = translate("Failed to parse GPX file"), - .type_uri = "https://routemon.fautchen.eu/problems/gpx-parse-failed", - }; - co_return http::problem_rsp( - ctx, tpl.instantiate(), http::keep_alive{false}); - } - - // TODO: catch handler exceptions and return 500 when raised? - // (keep-alive depends on whether whole request was read) - auto mres = inner_.process_gpx(std::move(gpx_file)); - if (!mres) - { - auto tpl = problem::tpl{ - .status = bhttp::status::internal_server_error, - .title = translate("Internal server error"), - .type_uri = "https://routemon.fautchen.eu/problems/" - "internal-server-error", - }; - co_return http::problem_rsp( - ctx, tpl.instantiate(), http::keep_alive{true}); - } - - auto rsp = http::make_rsp( - bhttp::status::ok, http::keep_alive{true}); - rsp.set(bhttp::field::content_type, "application/json"); - rsp.body() = json::serialize(json::value_from(*mres)); - rsp.prepare_payload(); - co_return rsp; - } + -> net::awaitable; auto handle_sysinfo(l0_ctx ctx, http::readable_request r) - -> net::awaitable - { - auto req = - co_await http::read_request(ctx, std::move(r)); - auto info = inner_.sysinfo(); - - auto rsp = http::make_rsp( - bhttp::status::ok, http::keep_alive{true}); - rsp.set(bhttp::field::content_type, "application/json"); - rsp.body() = json::serialize(json::value_from(info)); - rsp.prepare_payload(); - co_return rsp; - } + -> net::awaitable; public: - handler(api::handler&& inner) : inner_{std::move(inner)} {} - - auto make_routes() -> http::route_tree> - { - auto handler = [this](MemFn member) - { return std::bind_front(member, this); }; + handler(api::handler&& inner); - return http::dtree>{}.named_subtrees({ - {"gpx", - http::dtree{ - { - .post = handler(&handler::handle_process_gpx), - } - }.no_subtrees()}, - {"sysinfo", http::dtree{ - { - .get = handler(&handler::handle_sysinfo), - } - }.no_subtrees()}, - }); - } + auto make_routes() -> http::route_tree>; }; export class server { handler handler_; - http::server srv_; + http::server srv_; static auto make_global_middleware() - -> http::middleware_t - { - return http::middleware_compose< - http::base_ctx, http::trace_id_ctx, - http::trace_id_ctx>( - http::trace_id_middleware, - http::lax_cors_middleware>); - } + -> http::middleware_t; public: - server(log::logger const& l, locale::selector&& lsel, api::handler&& inner) - : handler_{std::move(inner)}, - srv_{l, std::move(lsel), make_global_middleware(), handler_.make_routes()} - { - } + server(log::logger const& l, locale::selector&& lsel, api::handler&& inner); - auto spawn(net::io_context& ioc) -> void { srv_.spawn(ioc); } + auto spawn(net::io_context& ioc) -> void; }; } // namespace routemon::srv -- cgit v1.3