From 4a20eecc028b5a26ffd3481eff3999a5467eedc8 Mon Sep 17 00:00:00 2001 From: "Timur A. Fatkhullin" Date: Tue, 5 Nov 2024 18:02:28 +0300 Subject: [PATCH] AdcGenericNetServer, AdcDeviceNetServer, AdcDeviceNetServer::Session and AdcDeviceNetServerASIO classes now have template parameter 'IdentT' (type of identificator) --- common/adc_traits.h | 7 + net/adc_device_netserver.h | 27 +-- net/adc_netserver.h | 48 ++--- net/adc_netserver_spdlog.h | 288 +++++++++++++++++---------- net/asio/adc_device_netserver_asio.h | 60 +++--- tests/adc_asio_netserver_test.cpp | 2 +- 6 files changed, 251 insertions(+), 181 deletions(-) diff --git a/common/adc_traits.h b/common/adc_traits.h index 2e44758..51814a8 100644 --- a/common/adc_traits.h +++ b/common/adc_traits.h @@ -270,4 +270,11 @@ using adc_common_duration_t = adc_duration_common_type_t; +// concept for hashable types +template +concept adc_hashable_c = requires(T t) { + { std::hash{}(t) } -> std::convertible_to; +}; + + } // namespace adc::traits diff --git a/net/adc_device_netserver.h b/net/adc_device_netserver.h index 4c4b031..f23373e 100644 --- a/net/adc_device_netserver.h +++ b/net/adc_device_netserver.h @@ -105,10 +105,12 @@ namespace adc { - -class AdcDeviceNetServer : public AdcGenericNetServer +template +class AdcDeviceNetServer : public AdcGenericNetServer { public: + using typename AdcGenericNetServer::server_ident_t; + // type for serialized data (attr/command ID, attr values etc...) typedef std::vector serialized_t; @@ -206,29 +208,23 @@ protected: std::unordered_map _devices; public: - template - class Session : public std::enable_shared_from_this> + template + class Session : public std::enable_shared_from_this> { public: - typedef std::string netsession_ident_t; + typedef SessionIdentT netsession_ident_t; typedef NetServiceT netservice_t; typedef AdcDeviceNetServer* netsession_ctx_t; typedef std::vector message_t; - template - Session(R&& id, netservice_t srv, AdcDeviceNetServer* srv_ptr) - : _ident(), + Session(const netsession_ident_t& id, netservice_t srv, AdcDeviceNetServer* srv_ptr) + : _ident(id), _netService(std::move(srv)), _serverPtr(srv_ptr), _bindDevice(srv_ptr->_devices.size() ? &srv_ptr->_devices.begin()->second : &AdcDeviceNetServer::nullDevice) { - if constexpr (std::is_array_v>) { - _ident = id; - } else { - _ident = netsession_ident_t(id.begin(), id.end()); - } } netsession_ident_t ident() const @@ -368,10 +364,7 @@ public: // using AdcGenericNetServer::AdcGenericNetServer; - template - AdcDeviceNetServer(const R& id) : AdcGenericNetServer(id), _devices() - { - } + AdcDeviceNetServer(const server_ident_t& id) : AdcGenericNetServer(id), _devices() {} virtual ~AdcDeviceNetServer() = default; diff --git a/net/adc_netserver.h b/net/adc_netserver.h index dcb9404..c8cf56f 100644 --- a/net/adc_netserver.h +++ b/net/adc_netserver.h @@ -224,20 +224,13 @@ protected: /* very generic network server */ +template class AdcGenericNetServer : public AdcPosixGenericDaemon, public AdcNetSessionManager { public: - typedef std::string server_ident_t; + typedef IdentT server_ident_t; - template - AdcGenericNetServer(const R& id) : _serverIdent() - { - if constexpr (std::is_array_v>) { - _serverIdent = id; - } else { - _serverIdent = server_ident_t{id.begin(), id.end()}; - } - } + AdcGenericNetServer(const server_ident_t& id) : _serverIdent(id) {} AdcGenericNetServer(const AdcGenericNetServer&) = delete; @@ -289,6 +282,7 @@ public: // It must be assumed that this is asynchronous operation!!! template void start(SessionT::netsession_ident_t id, SessionT::netsession_ctx_t sess_ctx, AcceptorCtorArgTs&&... ctor_args) + requires traits::adc_hashable_c { if (!_isListening[this][id]) { auto acceptor = std::make_shared( @@ -340,7 +334,7 @@ protected: // inline static std::unordered_map _isListening{}; template inline static std::unordered_map> + std::unordered_map> _isListening{}; std::vector> _stopListenFunc; @@ -367,34 +361,16 @@ protected: }; -template -class AdcAbstractNetServer +namespace interfaces { -public: - struct ServerEvents { - std::function onOpen; - std::function onClose; - std::function)> onData; - std::function onError; - }; - - AdcAbstractNetServer(ServerEvents&& events) : _serverEvents(std::move(events)) {} - - template - void listen(const typename NetServiceT::endpoint_t& endpoint, AcceptorCtorArgTs&&... ctor_args) - { - auto acceptor = - std::make_shared(endpoint, std::forward(ctor_args)...); - } - - void stop() {} - -protected: - ServerEvents _serverEvents; - - typename NetServiceT::acceptor_t _acceptor; +template +concept adc_generic_netserver_c = requires { + typename T::server_ident_t; + requires std::derived_from>; }; +} // namespace interfaces + } // namespace adc diff --git a/net/adc_netserver_spdlog.h b/net/adc_netserver_spdlog.h index 9300435..9b13b0a 100644 --- a/net/adc_netserver_spdlog.h +++ b/net/adc_netserver_spdlog.h @@ -11,87 +11,19 @@ ABSTRACT DEVICE COMPONENTS LIBRARY #ifdef USE_SPDLOG_LIBRARY +#include + #include "../common/adc_spdlog.h" #include "../common/adc_traits.h" #include "adc_netserver.h" -namespace adc +namespace adc::spdlog { -template -class AdcNetServerSessionSpdlogDecorator : public AdcSpdlogGenericMarkDecorator -{ -protected: - using base_t = AdcSpdlogGenericMarkDecorator; - - std::string _sessionID; - -public: - using base_t::logDebug; - using base_t::logInfo; - using base_t::logMethodCalling; - - // using SessionT::sessionIdent; - using typename SessionT::session_ident_t; - - static_assert(traits::formattable, "NETWORK SESSION IDENT TYPE MUST BE A FORMATTABLE ONE!!!"); - - template - AdcNetServerSessionSpdlogDecorator(std::shared_ptr logger, ImplCtorArgTs&&... ctor_args) - : base_t("ADC NETSERVER SESSION", logger, std::forward(ctor_args)...) - { - logMethodCalling(__PRETTY_FUNCTION__); - - fmt::format_to(std::back_inserter(_sessionID), "{}", SessionT::sessionIdent()); - - this->setPattern(base_t::constructPattern(_sessionID)); - - logDebug("Creating network server session with ID = [{}] (ADDR = {})", _sessionID, this->_thisAddress); - logDebug("Use logger with ", this->loggerInfo()); - } - - virtual ~AdcNetServerSessionSpdlogDecorator() - { - logMethodCalling(__PRETTY_FUNCTION__); - - logDebug("Deleting network server session with ID = [{}] (ADDR = {})", _sessionID, this->_thisAddress); - }; - - virtual session_ident_t sessionIdent() const override - { - logMethodCalling(__PRETTY_FUNCTION__); - - return SessionT::sessionIdent(); - }; - - virtual void start() override - { - logMethodCalling(__PRETTY_FUNCTION__); - - logInfo("Starting network server session with ID = [{}]", _sessionID); - - SessionT::start(); - - logInfo("Network server session [{}] is started", _sessionID); - }; - - virtual void stop() override - { - logMethodCalling(__PRETTY_FUNCTION__); - - logInfo("Stopping network server session with ID = [{}]", _sessionID); - - SessionT::stop(); - - logInfo("Network server session [{}] is stopped", _sessionID); - }; -}; - - - -template -class AdcNetServerSpdlogDecorator : public AdcSpdlogGenericMarkDecorator +template + requires traits::formattable +class AdcGenericNetServerSpdlog : public AdcSpdlogGenericMarkDecorator { protected: using base_t = AdcSpdlogGenericMarkDecorator; @@ -99,6 +31,8 @@ protected: std::string _serverID; public: + using typename ServerT::server_ident_t; + using base_t::logCritical; using base_t::logDebug; using base_t::logError; @@ -106,51 +40,44 @@ public: using base_t::logMsg; using base_t::logWarn; - using typename ServerT::server_ident_t; - - static_assert(traits::formattable, "NETWORK SERVER IDENT TYPE MUST BE A FORMATTABLE ONE!!!"); - - template - AdcNetServerSpdlogDecorator(std::shared_ptr logger, ImplCtorArgTs&&... ctor_args) - : base_t("ADC NETSERVER", logger, std::forward(ctor_args)...) + template + AdcGenericNetServerSpdlog(const server_ident_t& id, + const R& mark = std::string_view("ADC GENERIC NETSERVER"), + std::shared_ptr<::spdlog::logger> logger = ::spdlog::null_logger_mt("NULL_LOGGER")) + : base_t(mark, logger, id) { this->logMethodCalling(__PRETTY_FUNCTION__); - fmt::format_to(std::back_inserter(_serverID), "{}", ServerT::serverIdent()); + fmt::format_to(std::back_inserter(_serverID), "{}", ServerT::_serverIdent); this->setPattern(base_t::constructPattern(_serverID)); - logDebug("Creating network server with ID = [{}] (ADDR = {})", _serverID, this->_thisAddress); + logDebug("Creating ADC-library generic network server with ID = [{}] (ADDR = {})", _serverID, + this->_thisAddress); logDebug("Use logger with ", this->loggerInfo()); } - - virtual ~AdcNetServerSpdlogDecorator() + virtual server_ident_t ident() const { this->logMethodCalling(__PRETTY_FUNCTION__); - logDebug("Deleting network server with ID = [{}] (ADDR = {})", _serverID, this->_thisAddress); + return ServerT::ident(); } - - virtual server_ident_t serverIdent() const + template + void start(SessionT::netsession_ident_t id, SessionT::netsession_ctx_t sess_ctx, AcceptorCtorArgTs&&... ctor_args) { this->logMethodCalling(__PRETTY_FUNCTION__); - return ServerT::serverIdent(); + if constexpr (traits::formattable) { + logInfo("Start accepting client connections for server session ID: {} ...", id); + } else { // here session ID has hashable type (see AdcGenericNetServer) + logInfo("Start accepting client connections for server session ID hash: {} ...", std::hash(id)); + } + + ServerT::start(std::move(id), std::move(sess_ctx), std::forward(ctor_args)...); } - virtual void start() - { - this->logMethodCalling(__PRETTY_FUNCTION__); - - logInfo("Starting network server"); - - ServerT::start(); - - logInfo("Network server is started"); - }; - virtual void stop() { this->logMethodCalling(__PRETTY_FUNCTION__); @@ -160,9 +87,166 @@ public: ServerT::stop(); logInfo("Network server is stopped"); - }; + } + + + template + bool isListening(const typename SessionT::netsession_ident_t& id) const + { + this->logMethodCalling(__PRETTY_FUNCTION__); + + ServerT::_isListening(id); + } + + + +protected: }; -} // namespace adc +// template +// class AdcNetServerSessionSpdlogDecorator : public AdcSpdlogGenericMarkDecorator +// { +// protected: +// using base_t = AdcSpdlogGenericMarkDecorator; + +// std::string _sessionID; + +// public: +// using base_t::logDebug; +// using base_t::logInfo; +// using base_t::logMethodCalling; + +// // using SessionT::sessionIdent; +// using typename SessionT::session_ident_t; + +// static_assert(traits::formattable, "NETWORK SESSION IDENT TYPE MUST BE A FORMATTABLE ONE!!!"); + +// template +// AdcNetServerSessionSpdlogDecorator(std::shared_ptr logger, ImplCtorArgTs&&... ctor_args) +// : base_t("ADC NETSERVER SESSION", logger, std::forward(ctor_args)...) +// { +// logMethodCalling(__PRETTY_FUNCTION__); + +// fmt::format_to(std::back_inserter(_sessionID), "{}", SessionT::sessionIdent()); + +// this->setPattern(base_t::constructPattern(_sessionID)); + +// logDebug("Creating network server session with ID = [{}] (ADDR = {})", _sessionID, this->_thisAddress); +// logDebug("Use logger with ", this->loggerInfo()); +// } + +// virtual ~AdcNetServerSessionSpdlogDecorator() +// { +// logMethodCalling(__PRETTY_FUNCTION__); + +// logDebug("Deleting network server session with ID = [{}] (ADDR = {})", _sessionID, this->_thisAddress); +// }; + +// virtual session_ident_t sessionIdent() const override +// { +// logMethodCalling(__PRETTY_FUNCTION__); + +// return SessionT::sessionIdent(); +// }; + +// virtual void start() override +// { +// logMethodCalling(__PRETTY_FUNCTION__); + +// logInfo("Starting network server session with ID = [{}]", _sessionID); + +// SessionT::start(); + +// logInfo("Network server session [{}] is started", _sessionID); +// }; + +// virtual void stop() override +// { +// logMethodCalling(__PRETTY_FUNCTION__); + +// logInfo("Stopping network server session with ID = [{}]", _sessionID); + +// SessionT::stop(); + +// logInfo("Network server session [{}] is stopped", _sessionID); +// }; +// }; + + + +// template +// class AdcNetServerSpdlogDecorator : public AdcSpdlogGenericMarkDecorator +// { +// protected: +// using base_t = AdcSpdlogGenericMarkDecorator; + +// std::string _serverID; + +// public: +// using base_t::logCritical; +// using base_t::logDebug; +// using base_t::logError; +// using base_t::logInfo; +// using base_t::logMsg; +// using base_t::logWarn; + +// using typename ServerT::server_ident_t; + +// static_assert(traits::formattable, "NETWORK SERVER IDENT TYPE MUST BE A FORMATTABLE ONE!!!"); + +// template +// AdcNetServerSpdlogDecorator(std::shared_ptr logger, ImplCtorArgTs&&... ctor_args) +// : base_t("ADC NETSERVER", logger, std::forward(ctor_args)...) +// { +// this->logMethodCalling(__PRETTY_FUNCTION__); + +// fmt::format_to(std::back_inserter(_serverID), "{}", ServerT::serverIdent()); + +// this->setPattern(base_t::constructPattern(_serverID)); + +// logDebug("Creating network server with ID = [{}] (ADDR = {})", _serverID, this->_thisAddress); +// logDebug("Use logger with ", this->loggerInfo()); +// } + + +// virtual ~AdcNetServerSpdlogDecorator() +// { +// this->logMethodCalling(__PRETTY_FUNCTION__); + +// logDebug("Deleting network server with ID = [{}] (ADDR = {})", _serverID, this->_thisAddress); +// } + + +// virtual server_ident_t serverIdent() const +// { +// this->logMethodCalling(__PRETTY_FUNCTION__); + +// return ServerT::serverIdent(); +// } + +// virtual void start() +// { +// this->logMethodCalling(__PRETTY_FUNCTION__); + +// logInfo("Starting network server"); + +// ServerT::start(); + +// logInfo("Network server is started"); +// }; + +// virtual void stop() +// { +// this->logMethodCalling(__PRETTY_FUNCTION__); + +// logInfo("Stopping network server ..."); + +// ServerT::stop(); + +// logInfo("Network server is stopped"); +// }; +// }; + +} // namespace adc::spdlog #endif diff --git a/net/asio/adc_device_netserver_asio.h b/net/asio/adc_device_netserver_asio.h index 47e0ea8..971bc15 100644 --- a/net/asio/adc_device_netserver_asio.h +++ b/net/asio/adc_device_netserver_asio.h @@ -14,12 +14,20 @@ namespace adc::impl { -class AdcDeviceNetServerASIO : public AdcDeviceNetServer +template +class AdcDeviceNetServerASIO : public AdcDeviceNetServer { + typedef AdcDeviceNetServer base_t; + public: - template - AdcDeviceNetServerASIO(const R& id, asio::io_context& io_context) - : AdcDeviceNetServer(id), _ioContext(io_context), _stopSignal(io_context), _restartSignal(io_context) + using typename base_t::server_ident_t; + typedef std::string session_ident_t; + + template + using Session = typename base_t::template Session; + + AdcDeviceNetServerASIO(const server_ident_t& id, asio::io_context& io_context) + : base_t(id), _ioContext(io_context), _stopSignal(io_context), _restartSignal(io_context) { } @@ -39,37 +47,30 @@ public: // may throw here! -#ifdef USE_OPENSSL_WITH_ASIO - if (endpoint.isTCP() || endpoint.isTLS()) { - asio::ip::tcp::endpoint ept(asio::ip::make_address(endpoint.host()), endpoint.port()); - if (endpoint.isTCP()) { - using srv_t = AdcNetServiceASIO; - AdcGenericNetServer::start>("TCP", this, _ioContext, ept); - - } else { - using srv_t = AdcNetServiceASIOTLS; - AdcGenericNetServer::start>("TLS", this, _ioContext, ept, std::move(tls_context), - tls_verify_mode); - } -#else if (endpoint.isTCP()) { asio::ip::tcp::endpoint ept(asio::ip::make_address(endpoint.host()), endpoint.port()); - using srv_t = AdcNetServiceASIO>; - AdcDeviceNetServer::start>("TCP", this, _ioContext, ept); + using srv_t = AdcNetServiceASIO; + base_t::template start>("TCP", this, _ioContext, ept); +#ifdef USE_OPENSSL_WITH_ASIO + } else if (endpoint.isTLS()) { + asio::ip::tcp::endpoint ept(asio::ip::make_address(endpoint.host()), endpoint.port()); + using srv_t = AdcNetServiceASIOTLS; + base_t::template start>("TLS", this, _ioContext, ept, std::move(tls_context), + tls_verify_mode); #endif } else if (endpoint.isLocal()) { if (endpoint.isLocalStream()) { asio::local::stream_protocol::endpoint ept(endpoint.template path()); using srv_t = AdcNetServiceASIO; - AdcGenericNetServer::start>("LOCAL STREAM", this, _ioContext, ept); + base_t::template start>("LOCAL STREAM", this, _ioContext, ept); // } else if (endpoint.isLocalDatagram()) { // asio::local::datagram_protocol::endpoint ept(endpoint.template path()); // using srv_t = AdcNetServiceASIO; - // AdcDeviceNetServer::start>("LOCAL DGRAM", this, _ioContext, ept); + // base_t::template start>("LOCAL DGRAM", this, _ioContext, ept); } else if (endpoint.isLocalSeqpacket()) { asio::local::seq_packet_protocol::endpoint ept(endpoint.template path()); using srv_t = AdcNetServiceASIO; - AdcGenericNetServer::start>("LOCAL SEQPACK", this, _ioContext, ept); + base_t::template start>("LOCAL SEQPACK", this, _ioContext, ept); } } else { throw std::system_error(std::make_error_code(std::errc::protocol_not_supported)); @@ -80,8 +81,7 @@ public: void start() {} template , std::ranges::range RRT = std::vector> - void setupSignals(const RST& stop_sig_num = std::vector{SIGINT, SIGTERM}, - const RRT& restart_sig_num = std::vector{SIGUSR1}) + void setupSignals(const RST& stop_sig_num = {SIGINT, SIGTERM}, const RRT& restart_sig_num = {SIGUSR1}) requires(std::convertible_to, int> && std::convertible_to, int>) { @@ -100,7 +100,7 @@ public: _restartSignal.async_wait([this](std::error_code ec, int signo) { signalReceived(ec, signo); - // ?!!!!!!! + restart(); }); } @@ -124,6 +124,16 @@ protected: { std::cout << "SIGNAL: " << signo << "\n"; }; + + virtual void restart() + { + this->stopAllSessions(); + + _restartSignal.async_wait([this](std::error_code ec, int signo) { + signalReceived(ec, signo); + restart(); + }); + } }; } // namespace adc::impl diff --git a/tests/adc_asio_netserver_test.cpp b/tests/adc_asio_netserver_test.cpp index 355d21e..f6919eb 100644 --- a/tests/adc_asio_netserver_test.cpp +++ b/tests/adc_asio_netserver_test.cpp @@ -8,7 +8,7 @@ #include "../net/adc_netproto.h" #include "../net/asio/adc_device_netserver_asio.h" -typedef adc::impl::AdcDeviceNetServerASIO server_t; +typedef adc::impl::AdcDeviceNetServerASIO server_t; typedef adc::AdcDeviceAttribute attr_t; class Device1 : public adc::AdcGenericDevice