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>
|
||||
concept snplib_net_listener_c = requires(T t) {
|
||||
concept snplib_net_listener_c = requires(T t, const T t_const) {
|
||||
// static constexpr member
|
||||
std::formattable<decltype(T::id), char>;
|
||||
[]() { [[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.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>
|
||||
concept snplib_net_initiator_c =
|
||||
requires(T t) {
|
||||
requires(T t, const T t_const) {
|
||||
// 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_const.endpoint() } -> snplib_net_endpoint_c;
|
||||
} && ((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>;
|
||||
@@ -260,11 +264,43 @@ public:
|
||||
using LoggerT::logWarn;
|
||||
|
||||
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()
|
||||
{
|
||||
@@ -292,6 +328,7 @@ public:
|
||||
|
||||
protected:
|
||||
std::unique_ptr<ListenerT> _listener{};
|
||||
std::vector<std::weak_ptr<ListenerT>> _listeners{};
|
||||
std::set<std::weak_ptr<SessionT>> _sessions{};
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,12 @@
|
||||
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
|
||||
{
|
||||
static constexpr std::array ws = {' ', '\t', '\n', '\v', '\r', '\f'};
|
||||
|
||||
Reference in New Issue
Block a user