From ec3b9533840712f41918c85c91cdfc05a1609ca1 Mon Sep 17 00:00:00 2001 From: Kurt Sassenrath Date: Tue, 5 Sep 2023 16:25:57 -0700 Subject: [PATCH] Various updates to initial server code. Need to create user sessions and handle msgpack-encoded packets. The plan is to use a branch of oh::msgpack with tl::expected. --- source/common/include/logging.h | 1 + source/common/include/logging/formatters.h | 14 ++- source/common/include/logging/theme.h | 6 ++ source/server.cpp | 106 +++++++++++++++++++-- 4 files changed, 116 insertions(+), 11 deletions(-) diff --git a/source/common/include/logging.h b/source/common/include/logging.h index 66452f9..a2e3771 100644 --- a/source/common/include/logging.h +++ b/source/common/include/logging.h @@ -21,6 +21,7 @@ #include #include +#include #include #include diff --git a/source/common/include/logging/formatters.h b/source/common/include/logging/formatters.h index a6dcf40..886530c 100644 --- a/source/common/include/logging/formatters.h +++ b/source/common/include/logging/formatters.h @@ -77,14 +77,22 @@ struct fmt::formatter> } }; +template <> +struct fmt::formatter : fmt::formatter { + template + auto format(auto const& v, FormatContext& ctx) const { + return fmt::formatter::format(v.message(), ctx); + } +}; + // Support conversion of typical standard error codes into a human-readable // string. template <> -struct fmt::formatter : fmt::formatter { +struct fmt::formatter : fmt::formatter { template auto format(std::errc const& v, FormatContext& ctx) const { - return fmt::formatter::format( - std::make_error_code(v).message(), ctx); + return fmt::formatter::format( + std::make_error_code(v), ctx); } }; diff --git a/source/common/include/logging/theme.h b/source/common/include/logging/theme.h index 8084dd7..cfac7f6 100644 --- a/source/common/include/logging/theme.h +++ b/source/common/include/logging/theme.h @@ -84,12 +84,18 @@ template requires std::is_enum_v struct theme : static_theme {}; + +// Errors +template <> +struct theme : static_theme {}; + template <> struct theme : static_theme {}; template <> struct theme : static_theme {}; + template <> struct theme> { constexpr static fmt::color colors[] = { diff --git a/source/server.cpp b/source/server.cpp index 1148cee..47c8f85 100644 --- a/source/server.cpp +++ b/source/server.cpp @@ -22,18 +22,75 @@ #include #include +#include +#include +#include + #include #include -#include + +#include +#include +#include +#include + +using namespace parselink; namespace net = boost::asio; -using namespace parselink; +using net::co_spawn; +using net::awaitable; +using net::use_awaitable; +using net::deferred; +using net::detached; + +//----------------------------------------------------------------------------- +// TODO(ksassenrath): These are logging formatters for various boost/asio types. +// Not all code is exposed to them, so they cannot be defined inside the +// generic logging/formatters.h header. They should go somewhere else. +//----------------------------------------------------------------------------- +template <> +struct parselink::logging::theme + : parselink::logging::static_theme {}; + +template <> +struct fmt::formatter + : fmt::formatter { + template + constexpr auto format(auto const& v, FormatContext& ctx) const { + return fmt::formatter::format(v.message(), ctx); + } +}; + +template +concept endpoint = requires(T const& t) { + {t.address()}; + {t.port()}; +}; + +template +struct parselink::logging::theme + : parselink::logging::static_theme {}; + +template +struct fmt::formatter + : fmt::formatter { + template + constexpr auto format(auto const& v, FormatContext& ctx) const { + return fmt::format_to(ctx.out(), "{}:{}", v.address().to_string(), + v.port()); + } +}; + +//----------------------------------------------------------------------------- +// End formatters +//----------------------------------------------------------------------------- namespace { logging::logger logger("server"); + constexpr auto no_ex_coro = net::as_tuple(use_awaitable); + constexpr auto no_ex_defer = net::as_tuple(deferred); } - class monolithic_server : public server { public: monolithic_server(std::string_view address, std::uint16_t user_port, @@ -42,9 +99,14 @@ public: std::error_code run() noexcept override; private: + + awaitable echo(net::ip::tcp::socket socket); + awaitable user_listen(); + net::io_context io_context_; net::ip::address addr_; - net::ip::tcp::acceptor user_acceptor_; + std::uint16_t user_port_; + std::uint16_t websocket_port_; }; @@ -52,10 +114,36 @@ monolithic_server::monolithic_server(std::string_view address, std::uint16_t user_port, std::uint16_t websocket_port) : io_context_{1} , addr_(net::ip::address::from_string(std::string{address})) - , user_acceptor_{io_context_, {addr_, user_port}} { - logger.debug("Creating monolithic_server with" - "\n\taddress {},\n\tuser_port {},\n\twebsocket_port {}", - address, user_port, websocket_port); + , user_port_{user_port} + , websocket_port_{websocket_port} { + logger.debug("Creating monolithic_server(address = {}, user_port = {}, " + "websocket_port = {})", address, user_port_, websocket_port_); +} + +awaitable monolithic_server::echo(net::ip::tcp::socket socket) { + std::array buffer; + while (true) { + auto [ec, n] = co_await socket.async_read_some(net::buffer(buffer), no_ex_coro); + if (ec) { + logger.error("Read from socket failed: {}", ec); + co_return; + } + auto [ec2, x] = co_await net::async_write(socket, net::buffer(buffer, n), no_ex_coro); + if (ec2) { + logger.error("Write to socket failed: {}", ec); + co_return; + } + } +} + +awaitable monolithic_server::user_listen() { + auto exec = co_await net::this_coro::executor; + net::ip::tcp::acceptor acceptor{exec, {addr_, user_port_}}; + while (true) { + auto socket = co_await acceptor.async_accept(use_awaitable); + logger.debug("Accepted new connection from {}", socket.remote_endpoint()); + co_spawn(exec, echo(std::move(socket)), detached); + } } std::error_code monolithic_server::run() noexcept { @@ -67,6 +155,8 @@ std::error_code monolithic_server::run() noexcept { io_context_.stop(); }); + co_spawn(io_context_, user_listen(), detached); + io_context_.run(); return {};