...
This commit is contained in:
parent
8ae489f1c5
commit
f215ea7a6d
@ -1,11 +1,11 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
#include <format>
|
#include <format>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
||||||
ABSTRACT DEVICE COMPONENTS LIBRARY
|
ABSTRACT DEVICE COMPONENTS LIBRARY
|
||||||
@ -202,4 +202,12 @@ template <typename T>
|
|||||||
concept adc_tuple_like = adc_is_tuple_v<T> == true;
|
concept adc_tuple_like = adc_is_tuple_v<T> == true;
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
// from https://stackoverflow.com/questions/74383254/concept-that-models-only-the-stdchrono-duration-types
|
||||||
|
concept adc_time_duration_c = requires {
|
||||||
|
[]<class Rep, class Period>(std::type_identity<std::chrono::duration<Rep, Period>>) {}(std::type_identity<T>());
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
} // namespace adc::traits
|
} // namespace adc::traits
|
||||||
|
|||||||
@ -6,7 +6,6 @@ ABSTRACT DEVICE COMPONENTS LIBRARY
|
|||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <chrono>
|
|
||||||
#include <concepts>
|
#include <concepts>
|
||||||
|
|
||||||
#include "../common/adc_traits.h"
|
#include "../common/adc_traits.h"
|
||||||
@ -18,28 +17,21 @@ namespace adc::interfaces
|
|||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <traits::adc_time_duration_c... Ts>
|
||||||
// from https://stackoverflow.com/questions/74383254/concept-that-models-only-the-stdchrono-duration-types
|
|
||||||
concept adc_time_duration_c = requires {
|
|
||||||
[]<class Rep, class Period>(std::type_identity<std::chrono::duration<Rep, Period>>) {}(std::type_identity<T>());
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
template <adc_time_duration_c... Ts>
|
|
||||||
struct adc_duration_common_type;
|
struct adc_duration_common_type;
|
||||||
|
|
||||||
|
|
||||||
template <adc_time_duration_c T1, adc_time_duration_c T2>
|
template <traits::adc_time_duration_c T1, traits::adc_time_duration_c T2>
|
||||||
struct adc_duration_common_type<T1, T2> : std::common_type<T1, T2> {
|
struct adc_duration_common_type<T1, T2> : std::common_type<T1, T2> {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <adc_time_duration_c T1, adc_time_duration_c T2, adc_time_duration_c... Ts>
|
template <traits::adc_time_duration_c T1, traits::adc_time_duration_c T2, traits::adc_time_duration_c... Ts>
|
||||||
struct adc_duration_common_type<T1, T2, Ts...> : adc_duration_common_type<std::common_type_t<T1, T2>, Ts...> {
|
struct adc_duration_common_type<T1, T2, Ts...> : adc_duration_common_type<std::common_type_t<T1, T2>, Ts...> {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <adc_time_duration_c... Ts>
|
template <traits::adc_time_duration_c... Ts>
|
||||||
using adc_duration_common_type_t = typename adc_duration_common_type<Ts...>::type;
|
using adc_duration_common_type_t = typename adc_duration_common_type<Ts...>::type;
|
||||||
|
|
||||||
|
|
||||||
@ -92,7 +84,7 @@ template <typename SRVT,
|
|||||||
typename RMSGT = std::string, // receiving message type
|
typename RMSGT = std::string, // receiving message type
|
||||||
typename DURT = adc_common_duration_t // time duration type
|
typename DURT = adc_common_duration_t // time duration type
|
||||||
>
|
>
|
||||||
concept adc_netservice_c = traits::adc_input_char_range<SMSGT> && traits::adc_output_char_range<RMSGT> && adc_time_duration_c<DURT> &&
|
concept adc_netservice_c = traits::adc_input_char_range<SMSGT> && traits::adc_output_char_range<RMSGT> && traits::adc_time_duration_c<DURT> &&
|
||||||
requires(SRVT srv, const SRVT srv_const) {
|
requires(SRVT srv, const SRVT srv_const) {
|
||||||
typename SRVT::netservice_ident_t;
|
typename SRVT::netservice_ident_t;
|
||||||
|
|
||||||
|
|||||||
@ -40,6 +40,8 @@
|
|||||||
|
|
||||||
#include "adc_netmsg.h"
|
#include "adc_netmsg.h"
|
||||||
|
|
||||||
|
#include "adc_net_concepts.h"
|
||||||
|
|
||||||
|
|
||||||
namespace adc::traits
|
namespace adc::traits
|
||||||
{
|
{
|
||||||
@ -70,6 +72,192 @@ concept adc_asio_inet_stream_proto_c = requires(T t, asio_streambuff_iter_t begi
|
|||||||
namespace adc::impl
|
namespace adc::impl
|
||||||
{
|
{
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept adc_asio_transport_proto_c =
|
||||||
|
std::derived_from<T, asio::ip::tcp> || std::derived_from<T, asio::ip::udp> ||
|
||||||
|
std::derived_from<T, asio::local::seq_packet_protocol> || std::derived_from<T, asio::local::stream_protocol>;
|
||||||
|
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept adc_asio_stream_transport_proto_c =
|
||||||
|
std::derived_from<T, asio::ip::tcp> || std::derived_from<T, asio::local::stream_protocol>;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <adc_asio_transport_proto_c TRANSPORT_PROTOT,
|
||||||
|
interfaces::adc_netsession_proto_c<std::string_view> SESSION_PROTOT>
|
||||||
|
class AdcNetServiceASIOBase : public TRANSPORT_PROTOT, public SESSION_PROTOT
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef std::string netservice_ident_t;
|
||||||
|
|
||||||
|
using socket_t = typename TRANSPORT_PROTOT::socket;
|
||||||
|
using endpoint_t = typename TRANSPORT_PROTOT::endpoint;
|
||||||
|
|
||||||
|
struct asio_async_ctx_t {
|
||||||
|
bool use_future = false;
|
||||||
|
std::function<void(std::error_code)> accept_comp_token;
|
||||||
|
std::function<void(std::error_code)> connect_comp_token;
|
||||||
|
std::function<void(std::error_code)> send_comp_token;
|
||||||
|
|
||||||
|
template <traits::adc_output_char_range R>
|
||||||
|
static std::unordered_map<const asio_async_ctx_t*, std::function<void(std::error_code, const R&)>>
|
||||||
|
receive_comp_token;
|
||||||
|
};
|
||||||
|
|
||||||
|
static constexpr std::chrono::duration DEFAULT_ACCEPT_TIMEOUT = std::chrono::years::max();
|
||||||
|
static constexpr std::chrono::duration DEFAULT_CONNECT_TIMEOUT = std::chrono::seconds(10);
|
||||||
|
static constexpr std::chrono::duration DEFAULT_SEND_TIMEOUT = std::chrono::seconds(5);
|
||||||
|
static constexpr std::chrono::duration DEFAULT_RECEIVE_TIMEOUT = std::chrono::seconds(5);
|
||||||
|
|
||||||
|
|
||||||
|
netservice_ident_t ident() const
|
||||||
|
{
|
||||||
|
return _ident;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <traits::adc_time_duration_c TimeoutT = decltype(DEFAULT_CONNECT_TIMEOUT)>
|
||||||
|
auto asyncConnect(const endpoint_t& endpoint,
|
||||||
|
asio_async_ctx_t& ctx,
|
||||||
|
const TimeoutT& timeout = DEFAULT_CONNECT_TIMEOUT)
|
||||||
|
{
|
||||||
|
auto timer = getDeadlineTimer(timeout);
|
||||||
|
|
||||||
|
if (ctx.use_future) {
|
||||||
|
return _socket.async_connect(
|
||||||
|
endpoint, asio::use_future([&ctx, timer = std::move(timer)](std::error_code ec) { timer->cancel(); }));
|
||||||
|
} else {
|
||||||
|
return _socket.async_connect(endpoint, [&ctx, timer = std::move(timer)](std::error_code ec) {
|
||||||
|
timer->cancel();
|
||||||
|
ctx.connect_comp_token(ec);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <traits::adc_time_duration_c TimeoutT = decltype(DEFAULT_ACCEPT_TIMEOUT)>
|
||||||
|
auto asyncAccept(const endpoint_t& endpoint,
|
||||||
|
asio_async_ctx_t& ctx,
|
||||||
|
const TimeoutT& timeout = DEFAULT_ACCEPT_TIMEOUT)
|
||||||
|
{
|
||||||
|
if constexpr (std::derived_from<socket_t, asio::basic_datagram_socket<typename socket_t::protocol_type>>) {
|
||||||
|
return; // there is no acceptor for UDP protocol
|
||||||
|
}
|
||||||
|
|
||||||
|
typename TRANSPORT_PROTOT::acceptor acceptor;
|
||||||
|
try {
|
||||||
|
acceptor = typename TRANSPORT_PROTOT::acceptor(_ioContext, endpoint);
|
||||||
|
} catch (std::system_error err) {
|
||||||
|
ctx.accept_comp_token(err.code());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto timer = getDeadlineTimer(timeout);
|
||||||
|
|
||||||
|
if (ctx.use_future) {
|
||||||
|
return _socket.async_accept(
|
||||||
|
endpoint, asio::use_future([&ctx, timer = std::move(timer)](std::error_code ec) { timer->cancel(); }));
|
||||||
|
} else {
|
||||||
|
return _socket.async_accept(endpoint, [&ctx, timer = std::move(timer)](std::error_code ec) {
|
||||||
|
timer->cancel();
|
||||||
|
ctx.accept_comp_token(ec);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <traits::adc_output_char_range R, traits::adc_time_duration_c TimeoutT = decltype(DEFAULT_RECEIVE_TIMEOUT)>
|
||||||
|
auto asyncReceive(asio_async_ctx_t& ctx, const TimeoutT& timeout = DEFAULT_RECEIVE_TIMEOUT)
|
||||||
|
{
|
||||||
|
auto timer = getDeadlineTimer(timeout);
|
||||||
|
|
||||||
|
auto s_res = std::make_shared<std::invoke_result_t<decltype(SESSION_PROTOT::search), R>>();
|
||||||
|
|
||||||
|
if constexpr (std::derived_from<socket_t, asio::basic_stream_socket<typename socket_t::protocol_type>>) {
|
||||||
|
return asio::async_read_until(
|
||||||
|
_socket, _streamBuffer,
|
||||||
|
[s_res, this]<typename IT>(IT begin, IT end) {
|
||||||
|
*s_res = this->search(std::span(begin, end));
|
||||||
|
return std::make_tuple(std::get<1>(*s_res), std::get<2>(*s_res));
|
||||||
|
},
|
||||||
|
[&ctx, s_res, timer = std::move(timer), this](std::error_code ec, size_t) {
|
||||||
|
timer->cancel();
|
||||||
|
if (ec) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
R msg;
|
||||||
|
std::string_view net_pack{std::get<0>(*s_res), std::get<1>(*s_res)};
|
||||||
|
|
||||||
|
std::ranges::copy(this->fromProto(net_pack), std::back_inserter(msg));
|
||||||
|
_streamBuffer.consume(net_pack.size());
|
||||||
|
|
||||||
|
ctx.accept_comp_token(ec, std::move(msg));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <traits::adc_time_duration_c TimeoutT>
|
||||||
|
auto accept(const endpoint_t& endpoint, const TimeoutT& timeout)
|
||||||
|
{
|
||||||
|
asio_async_ctx_t ctx = {.use_future = true};
|
||||||
|
std::future<void> ftr = asyncAcept(endpoint, ctx, timeout);
|
||||||
|
ftr.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <traits::adc_time_duration_c TimeoutT>
|
||||||
|
auto connect(const endpoint_t& endpoint, const TimeoutT& timeout)
|
||||||
|
{
|
||||||
|
asio_async_ctx_t ctx = {.use_future = true};
|
||||||
|
std::future<void> ftr = asyncConnect(endpoint, ctx, timeout);
|
||||||
|
ftr.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <traits::adc_input_char_range R, traits::adc_time_duration_c TimeoutT>
|
||||||
|
auto send(const R& msg, const TimeoutT& timeout)
|
||||||
|
{
|
||||||
|
std::future<void> ftr = asyncSend(msg, timeout, asio::use_future);
|
||||||
|
ftr.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <traits::adc_input_char_range R, traits::adc_time_duration_c TimeoutT>
|
||||||
|
auto receive(const TimeoutT& timeout)
|
||||||
|
{
|
||||||
|
std::future<R> ftr = asyncReceive(timeout, asio::use_future);
|
||||||
|
return ftr.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
netservice_ident_t _ident;
|
||||||
|
|
||||||
|
asio::io_context& _ioContext;
|
||||||
|
|
||||||
|
socket_t _socket;
|
||||||
|
|
||||||
|
// acceptor_t _acceptor;
|
||||||
|
|
||||||
|
asio::streambuf _streamBuffer;
|
||||||
|
|
||||||
|
template <traits::adc_time_duration_c TimeoutT>
|
||||||
|
std::unique_ptr<asio::steady_timer> getDeadlineTimer(const TimeoutT& timeout, bool arm = true)
|
||||||
|
{
|
||||||
|
std::unique_ptr<asio::steady_timer> timer(_socket.get_executor());
|
||||||
|
|
||||||
|
if (arm) {
|
||||||
|
timer->expires_after(timeout);
|
||||||
|
|
||||||
|
timer->async_wait([this](const std::error_code& ec) {
|
||||||
|
if (!ec) {
|
||||||
|
_socket.cancel(std::make_error_code(std::errc::timed_out));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return timer;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
template <traits::adc_asio_inet_proto_c InetProtoT>
|
template <traits::adc_asio_inet_proto_c InetProtoT>
|
||||||
class AdcNetServiceASIO : public InetProtoT
|
class AdcNetServiceASIO : public InetProtoT
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user