This commit is contained in:
2026-07-20 18:49:46 +03:00
parent f6ff2fb20f
commit 71fd97ca2f

View File

@@ -1,7 +1,9 @@
#pragma once #pragma once
#include <set> #include <set>
#include "../concepts/snplib_concepts.h" #include "../concepts/snplib_concepts.h"
#include "../utils/snplib_logger.h"
namespace snplib namespace snplib
{ {
@@ -53,18 +55,26 @@ concept snplib_net_connection_c = requires(T t) {
template <typename T> template <typename T>
concept snplib_net_session_c = std::derived_from<T, std::enable_shared_from_this<T>> && requires(T t) { concept snplib_net_session_c =
// static constexpr member std::derived_from<T, std::enable_shared_from_this<T>> &&
std::formattable<decltype(T::id), char>; requires(T t, const T t_const) {
[]() { [[maybe_unused]] static constexpr auto val = T::id; }(); typename T::ident_t;
typename T::context_t;
snplib_net_connection_c<typename T::connection_t>; snplib_net_connection_c<typename T::connection_t>;
// { t.startSession(std::declval<typename T::connection_t>()) } -> snplib_async_retval_c; { t_const.ident() } -> std::same_as<typename T::ident_t>;
t.startSession(std::declval<typename T::connection_t>());
t.stopSession(); // { t.startSession(std::declval<typename T::connection_t>()) } -> snplib_async_retval_c;
}; t.startSession(std::declval<typename T::connection_t>());
t.stopSession();
} && (!std::is_void_v<typename T::context_t> || std::constructible_from<T, typename T::ident_t>) &&
(std::is_void_v<typename T::context_t> ||
(std::constructible_from<T, typename T::ident_t, typename T::context_t> ||
std::constructible_from<T, typename T::ident_t, typename T::context_t&>)); // can be constructible from value or
// lvalue-reference or const
// lvalue-reference of context_t-type
template <typename T> template <typename T>
@@ -83,6 +93,45 @@ concept snplib_net_listener_c = requires(T t) {
}; };
// a type that defines at least two compile-time constants:
// ROLE_SERVER and ROLE_CLIENT
template <typename T>
concept snplib_net_initiator_role_c = requires {
[]() {
[[maybe_unused]] static constexpr std::array arr{// server role (listener of connections)
T::ROLE_SERVER,
// cleant role (opener of connections)
T::ROLE_CLIENT};
}();
};
// default library-wide type of network connection initiator role
enum class snplib_net_initiator_role_e : int { ROLE_SERVER, ROLE_CLIENT };
template <typename T>
concept snplib_net_initiator_c =
requires(T t) {
// common part
requires snplib_net_initiator_role_c<decltype(T::ROLE)>;
[]() { [[maybe_unused]] static constexpr auto val = T::ROLE; }();
snplib_net_connection_c<typename T::connection_t>;
} && ((T::ROLE != decltype(T::ROLE)::ROLE_SERVER) || requires(T t) { // use of short-circuiting logic!!!
// server-role
{ t.accept() } -> snplib_async_retval_c<typename T::connection_t>;
{ t.startListen() } -> snplib_error_c;
t.stopListen();
}) && ((T::ROLE != decltype(T::ROLE)::ROLE_CLIENT) || requires(T t) { // use of short-circuiting logic!!!
// client-role
{ t.open() } -> snplib_async_retval_c<typename T::connection_t>;
t.close();
});
template <typename T> template <typename T>
concept snplib_netserver_c = requires(T t) { concept snplib_netserver_c = requires(T t) {
// static constexpr member // static constexpr member
@@ -104,17 +153,118 @@ concept snplib_netserver_c = requires(T t) {
}; };
template <typename T, typename SessionT>
concept snplib_session_manager_c =
requires(T t, SessionT::context_t cnx) {
requires snplib_net_session_c<SessionT>;
typename T::session_ptr_t; // e.g. std::shared_ptr<SessionT>
// must be a non-blocking method!
t.startSession(std::declval<typename T::session_ptr_t>());
t.stopSession(std::declval<typename T::session_ptr_t>());
// must return number of stopped sessions
{ t.stopSessions() } -> std::convertible_to<size_t>;
// true - if session exists
{ t.isActive(std::declval<typename T::session_ptr_t>()) } -> std::convertible_to<bool>;
} && (!std::is_void_v<typename SessionT::context_t> || requires(T t) {
{ t.createSession() } -> std::same_as<typename T::session_ptr_t>;
}) && (std::is_void_v<typename SessionT::context_t> || requires(T t, SessionT::context_t cnx) {
{ t.createSession(cnx) } -> std::same_as<typename T::session_ptr_t>;
});
;
/* SINGLE-PROTO*/ /* SINGLE-PROTO*/
template <snplib_net_listener_c ListenerT, snplib_net_session_c SessionT> template <snplib_net_session_c SessionT>
class snplib_session_manager_t
{
public:
typedef std::shared_ptr<SessionT> session_ptr_t;
session_ptr_t createSession(typename SessionT::context_t ctx)
{
std::lock_guard lock(_setMutex);
auto sptr = std::make_shared<SessionT>(ctx);
_sessions.insert(sptr);
return sptr;
}
//
// delegates an implementation to the derived class
//
template <std::derived_from<snplib_session_manager_t> SelfT>
auto startSession(this SelfT&& self, session_ptr_t ptr)
{
std::lock_guard lock(self._setMutex);
return std::forward<SelfT>(self)(std::move(ptr));
}
bool stopSession(session_ptr_t ptr)
{
std::lock_guard lock(_setMutex);
if (auto it = _sessions.find(ptr); it != _sessions.end()) {
if (auto sptr = it->lock()) { // it is safe in multi-threaded environment!
sptr->stopSession();
} // session pointer expired here
} else {
return false;
}
return true;
}
size_t stopSessions()
{
std::lock_guard lock(_setMutex);
size_t N = 0;
for (auto sess : _sessions) {
if (stopSession(sess)) {
++N;
}
}
return N;
}
protected:
std::unique_ptr<std::recursive_mutex> _setMutex{new std::recursive_mutex};
std::set<std::weak_ptr<SessionT>, std::owner_less<std::weak_ptr<SessionT>>> _sessions{};
};
template <snplib_net_listener_c ListenerT,
snplib_net_session_c SessionT,
snplib_session_manager_c<SessionT> SessManagerT,
snplib_logger_c LoggerT>
requires std::same_as<typename ListenerT::connection_t, typename SessionT::connection_t> requires std::same_as<typename ListenerT::connection_t, typename SessionT::connection_t>
class snplib_generic_netserver_t class snplib_generic_netserver_t : protected SessManagerT, public LoggerT
{ {
public: public:
// typedef std::error_code error_t; // typedef std::error_code error_t;
snplib_generic_netserver_t(std::unique_ptr<ListenerT> listener) : _listener(std::move(listener)) {} using LoggerT::logDebug;
using LoggerT::logError;
using LoggerT::logInfo;
using LoggerT::logTrace;
using LoggerT::logWarn;
template <typename... SessManagerCtorArgTs, typename... LoggerCtorArgTs>
snplib_generic_netserver_t(std::unique_ptr<ListenerT> listener) : _listener(std::move(listener))
{
}
virtual ~snplib_generic_netserver_t() = default;
auto startServer() auto startServer()
{ {