add snplib_netproto.h
This commit is contained in:
64
include/snipplib/network/snplib_netproto.h
Normal file
64
include/snipplib/network/snplib_netproto.h
Normal 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
|
||||||
@@ -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{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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'};
|
||||||
|
|||||||
Reference in New Issue
Block a user