...
This commit is contained in:
@@ -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()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user