add snplib_netproto.h

This commit is contained in:
2026-07-21 17:55:45 +03:00
parent 71fd97ca2f
commit 7360e7eede
3 changed files with 111 additions and 4 deletions

View File

@@ -0,0 +1,64 @@
#pragma once
#include "../concepts/snplib_concepts.h"
#include "../utils/snplib_string.h"
/*
Various simple network session protocols
*/
namespace snplib
{
static constexpr char SNPLIB_DEFAULT_NETPROTO_STOP_SEQ[] = "\n";
template <const char* STOP_SEQ = SNPLIB_DEFAULT_NETPROTO_STOP_SEQ>
struct snplib_netproto_stopseq_t {
static constexpr std::string_view NETPROTO_STOP_SEQ{
snplib_char_array_size(STOP_SEQ) ? STOP_SEQ : SNPLIB_DEFAULT_NETPROTO_STOP_SEQ};
// returns 2-element range of the input messsage and stop-sequence
template <std::ranges::range OR, snplib_input_char_range_c IR>
requires snplib_char_range_c<std::ranges::range_value_t<OR>> // range of char ranges
OR toBytes(IR&& message)
{
OR res;
std::back_inserter(res) = std::forward<IR>(message);
std::back_inserter(res) = std::remove_cvref_t<IR>{NETPROTO_STOP_SEQ.begin(), NETPROTO_STOP_SEQ.end()};
return res;
}
// returns a copy of the input message + tralling stop-sequence
template <snplib_output_char_range_c OR, snplib_input_char_range_c IR>
OR toBytes(IR&& message)
{
OR res;
std::ranges::copy(std::forward<IR>(message), std::back_inserter(res));
std::ranges::copy(NETPROTO_STOP_SEQ, std::back_inserter(res));
return res;
}
template <snplib_input_char_range_c IR>
auto toBytes(IR&& message)
{
if constexpr (std::ranges::contiguous_range<IR>) {
return std::array{std::span<const char>{message}, std::span<const char>{NETPROTO_STOP_SEQ}};
} else {
return std::array{std::ranges::subrange{message}, std::ranges::subrange{NETPROTO_STOP_SEQ}};
}
}
template <std::ranges::range OR, std::ranges::range IR>
OR fromBytes(IR&& bytes)
{
}
};
} // namespace snplib

View File

@@ -78,7 +78,7 @@ concept snplib_net_session_c =
template <typename T> template <typename T>
concept snplib_net_listener_c = requires(T t) { concept snplib_net_listener_c = requires(T t, const T t_const) {
// static constexpr member // static constexpr member
std::formattable<decltype(T::id), char>; std::formattable<decltype(T::id), char>;
[]() { [[maybe_unused]] static constexpr auto val = T::id; }(); []() { [[maybe_unused]] static constexpr auto val = T::id; }();
@@ -90,6 +90,8 @@ concept snplib_net_listener_c = requires(T t) {
{ t.startListen() } -> snplib_error_c; { t.startListen() } -> snplib_error_c;
t.stopListen(); t.stopListen();
{ t_const.endpoint() } -> snplib_net_endpoint_c;
}; };
@@ -111,12 +113,14 @@ enum class snplib_net_initiator_role_e : int { ROLE_SERVER, ROLE_CLIENT };
template <typename T> template <typename T>
concept snplib_net_initiator_c = concept snplib_net_initiator_c =
requires(T t) { requires(T t, const T t_const) {
// common part // common part
requires snplib_net_initiator_role_c<decltype(T::ROLE)>; requires snplib_net_initiator_role_c<decltype(T::ROLE)>;
[]() { [[maybe_unused]] static constexpr auto val = T::ROLE; }(); []() { [[maybe_unused]] static constexpr auto val = T::ROLE; }();
snplib_net_connection_c<typename T::connection_t>; snplib_net_connection_c<typename T::connection_t>;
{ t_const.endpoint() } -> snplib_net_endpoint_c;
} && ((T::ROLE != decltype(T::ROLE)::ROLE_SERVER) || requires(T t) { // use of short-circuiting logic!!! } && ((T::ROLE != decltype(T::ROLE)::ROLE_SERVER) || requires(T t) { // use of short-circuiting logic!!!
// server-role // server-role
{ t.accept() } -> snplib_async_retval_c<typename T::connection_t>; { t.accept() } -> snplib_async_retval_c<typename T::connection_t>;
@@ -260,11 +264,43 @@ public:
using LoggerT::logWarn; using LoggerT::logWarn;
template <typename... SessManagerCtorArgTs, typename... LoggerCtorArgTs> template <typename... SessManagerCtorArgTs, typename... LoggerCtorArgTs>
snplib_generic_netserver_t(std::unique_ptr<ListenerT> listener) : _listener(std::move(listener)) snplib_generic_netserver_t(std::tuple<SessManagerCtorArgTs...> sess_manager_ctor_args,
std::tuple<LoggerCtorArgTs...> logger_ctor_args)
: SessManagerT(std::make_from_tuple<SessManagerT>(std::move(sess_manager_ctor_args))),
LoggerT(std::make_from_tuple<LoggerT>(std::move(logger_ctor_args)))
{ {
} }
virtual ~snplib_generic_netserver_t() = default; virtual ~snplib_generic_netserver_t()
{
for (auto& wptr : _listeners) {
if (auto sptr = wptr.lock()) {
sptr->stopListen();
}
}
};
size_t addListener(std::unique_ptr<ListenerT> listener) {}
auto startServer(std::unique_ptr<ListenerT> listener)
{
auto err = listener->startListen();
if (err) {
co_return std::unexpect(snplib_deduced_error(err, std::make_error_code(std::errc::io_error)));
}
auto listener_sptr = std::make_shared<ListenerT>(std::move(listener));
_listeners.emplace_back(listener_sptr);
while (true) {
auto connection = co_await listener_sptr->accept();
if (connection) {
auto sptr = std::make_shared<SessionT>();
_sessions.insert(sptr);
sptr->start(std::move(connection.value()));
}
}
}
auto startServer() auto startServer()
{ {
@@ -292,6 +328,7 @@ public:
protected: protected:
std::unique_ptr<ListenerT> _listener{}; std::unique_ptr<ListenerT> _listener{};
std::vector<std::weak_ptr<ListenerT>> _listeners{};
std::set<std::weak_ptr<SessionT>> _sessions{}; std::set<std::weak_ptr<SessionT>> _sessions{};
}; };

View File

@@ -9,6 +9,12 @@
namespace snplib namespace snplib
{ {
// compile-time size of zero-terminated char array
static consteval size_t snplib_char_array_size(const char* arr)
{
return *arr ? 1 + snplib_char_array_size(arr + 1) : 0;
}
constexpr static bool snplib_is_space(char in) noexcept constexpr static bool snplib_is_space(char in) noexcept
{ {
static constexpr std::array ws = {' ', '\t', '\n', '\v', '\r', '\f'}; static constexpr std::array ws = {' ', '\t', '\n', '\v', '\r', '\f'};