diff --git a/cxx/comm_server.h b/cxx/comm_server.h index 83adfa6..20a0d05 100644 --- a/cxx/comm_server.h +++ b/cxx/comm_server.h @@ -1,6 +1,10 @@ #pragma once +#include + #include +#include +#include #include #include #include @@ -48,6 +52,67 @@ public: ~MccMountServer() {} + + template + asio::awaitable listen(MccServerEndpoint endpoint, CtorArgTs&&... ctor_args) + { + if (!endpoint.isValid()) { + _serverLogger->error("Cannot start listening! Invalid endpoint string representation ('{}')!", + endpoint.endpoint()); + co_return; + } + + // add root path to endpoint one + std::filesystem::path pt("/"); + pt += endpoint.path(); + + auto args = std::make_tuple(std::forward(ctor_args)...); + + if (endpoint.isLocalSerial()) { + asio::serial_port s_port(_asioContext); + + std::error_code ec; + + if constexpr (sizeof...(CtorArgTs)) { // options + setSerialOpts(s_port, std::forward(ctor_args)...); + } + + s_port.open(pt.string(), ec); + if (ec) { + _serverLogger->error("Cannot open serial device '{}' (Error = '{}')!", pt.string(), ec.message()); + co_return; + } + + listen(std::move(s_port)); + } else if (endpoint.isLocal()) { + // create abstract namespace socket endpoint if its path starts from '@' symbol + endpoint.makeAbstract('@'); + + + if (endpoint.isLocalStream()) { + listen(asio::local::stream_protocol::endpoint(pt.string())); + } else if (endpoint.isLocalSeqpacket()) { + listen(asio::local::seq_packet_protocol::endpoint(pt.string())); + } else { + co_return; // ???!!!! + } + } else if (endpoint.isTCP()) { + // resolve hostname + try { + asio::ip::tcp::resolver res(_asioContext); + + auto r_result = co_await res.async_resolve(endpoint.host(), endpoint.portView(), asio::deferred); + + listen(std::move(*r_result.begin())); + + } catch (const std::system_error& err) { + _serverLogger->error("An error occured while resolving '{}' hostname (Error = '{}')", endpoint.host(), + err.code().message()); + co_return; + } + } + } + void listen(traits::mcc_endpoint_c auto endpoint) { using epn_t = std::decay_t; @@ -206,6 +271,37 @@ private: void doAccept() { } + + + // helpers + template + void setSerialOpts(asio::serial_port& s_port, OptT&& opt, OptTs&&... opts) + { + std::error_code ec; + + s_port.set_option(opt, ec); + if (ec) { + std::string_view opt_name; + + if constexpr (std::same_as) { + opt_name = "baud rate"; + } else if constexpr (std::same_as) { + opt_name = "parity"; + } else if constexpr (std::same_as) { + opt_name = "flow control"; + } else if constexpr (std::same_as) { + opt_name = "stop bits"; + } else if constexpr (std::same_as) { + opt_name = "char size"; + } + + _serverLogger->error("Cannot set serial port '{}' option! Just skip!", opt_name); + } + + if constexpr (sizeof...(OptTs)) { + setSerialOpts(s_port, std::forward(opts)...); + } + } }; } // namespace mcc