...
This commit is contained in:
parent
0b3e80261b
commit
117d8c4a3d
@ -67,6 +67,25 @@ concept adc_range_of_output_char_range =
|
||||
template <typename R>
|
||||
concept adc_range_of_view_or_output_char_range = adc_range_of_view_char_range<R> || adc_output_char_range<R>;
|
||||
|
||||
|
||||
template <adc_char_range R>
|
||||
struct adc_char_identity {
|
||||
template <adc_char_range T>
|
||||
requires std::same_as<R, T>
|
||||
constexpr T&& operator()(T&& v) // like std::identity
|
||||
{
|
||||
return std::forward<T>(v);
|
||||
}
|
||||
|
||||
template <adc_char_range T>
|
||||
requires(!std::same_as<R, T> &&
|
||||
std::is_constructible_v<R, std::ranges::iterator_t<T>, std::ranges::sentinel_t<T>>)
|
||||
constexpr R operator()(T&& v)
|
||||
{
|
||||
return {v.begin(), v.end()};
|
||||
}
|
||||
};
|
||||
|
||||
// deduce returned type of callable
|
||||
// template <typename T>
|
||||
// using adc_retval_t = std::invoke_result_t<std::remove_cvref_t<T>>;
|
||||
|
||||
@ -5,6 +5,8 @@
|
||||
#include <ranges>
|
||||
#include <system_error>
|
||||
|
||||
#include "adc_device_concepts.h"
|
||||
|
||||
namespace adc
|
||||
{
|
||||
|
||||
@ -33,7 +35,10 @@ namespace adc
|
||||
struct AdcGenericDeviceErrorCategory : public std::error_category {
|
||||
AdcGenericDeviceErrorCategory() : std::error_category() {}
|
||||
|
||||
const char* name() const noexcept { return "ADC_GENERIC_DEVICE"; }
|
||||
const char* name() const noexcept
|
||||
{
|
||||
return "ADC_GENERIC_DEVICE";
|
||||
}
|
||||
|
||||
std::string message(int ec) const
|
||||
{
|
||||
@ -66,32 +71,7 @@ inline std::error_code make_error_code(AdcGenericDeviceErrorCode ec)
|
||||
|
||||
|
||||
|
||||
namespace traits
|
||||
{
|
||||
|
||||
// ADC device attribute concept
|
||||
template <typename T>
|
||||
concept adc_device_attr_c = requires {
|
||||
typename T::ident_t;
|
||||
&T::ident;
|
||||
&T::serialize;
|
||||
&T::deserialize;
|
||||
// std::declval<T>().operator int();
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
concept adc_device_cmd_c = requires {
|
||||
typename T::ident_t;
|
||||
&T::ident;
|
||||
&T::operator();
|
||||
};
|
||||
|
||||
|
||||
} // namespace traits
|
||||
|
||||
|
||||
template <typename IdentT, traits::adc_device_attr_c AttributeT, traits::adc_device_cmd_c CommandT>
|
||||
template <typename IdentT, interfaces::adc_device_attr_c AttributeT, interfaces::adc_device_cmd_c CommandT>
|
||||
class AdcGenericDevice
|
||||
{
|
||||
public:
|
||||
@ -110,7 +90,10 @@ public:
|
||||
|
||||
/* PUBLIC METHODS */
|
||||
|
||||
IdentT ident() const { return _ident; }
|
||||
IdentT ident() const
|
||||
{
|
||||
return _ident;
|
||||
}
|
||||
|
||||
AdcGenericDevice& operator()(const cmd_ident_t& cmd_ident)
|
||||
{
|
||||
|
||||
54
device/adc_device_concepts.h
Normal file
54
device/adc_device_concepts.h
Normal file
@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
|
||||
namespace adc::interfaces
|
||||
{
|
||||
|
||||
// ADC device attribute concept
|
||||
template <typename T>
|
||||
concept adc_device_attr_c = requires(T t, const T const_t) {
|
||||
typename T::ident_t;
|
||||
typename T::default_serialized_t;
|
||||
|
||||
{ const_t.ident() } -> std::same_as<typename T::ident_t>;
|
||||
|
||||
// serializer and desiarializer must return/accept at least a value of type T::default_serialized_t
|
||||
{ t.serialize() } -> std::convertible_to<typename T::default_serialized_t>;
|
||||
t.deserialize(std::declval<typename T::default_serialized_t>());
|
||||
};
|
||||
|
||||
|
||||
// ADC device command concept
|
||||
template <typename T>
|
||||
concept adc_device_cmd_c = requires(T t, const T const_t) {
|
||||
typename T::ident_t;
|
||||
|
||||
{ const_t.ident() } -> std::same_as<typename T::ident_t>;
|
||||
t(); // operator()()
|
||||
};
|
||||
|
||||
|
||||
// ADC device concept
|
||||
|
||||
template <typename T>
|
||||
concept adc_device_c = requires(T t, const T const_t) {
|
||||
typename T::ident_t;
|
||||
|
||||
requires adc_device_attr_c<typename T::attribute_t>;
|
||||
requires adc_device_cmd_c<typename T::command_t>;
|
||||
|
||||
typename T::attr_ident_t;
|
||||
typename T::cmd_ident_t;
|
||||
|
||||
{ const_t.ident() } -> std::same_as<typename T::ident_t>;
|
||||
|
||||
t(std::declval<typename T::cmd_ident_t>()); // operator()(cmd_ident_t)
|
||||
|
||||
{
|
||||
t[std::declval<typename T::attr_ident_t>()]
|
||||
} -> std::same_as<typename T::attribute_t&>; // attribute_t& operator[](attr_ident_t)
|
||||
};
|
||||
|
||||
|
||||
} // namespace adc::interfaces
|
||||
@ -3,12 +3,100 @@
|
||||
#include "adc_device_netmsg.h"
|
||||
#include "adc_netserver.h"
|
||||
|
||||
#include "../device/adc_device_concepts.h"
|
||||
|
||||
namespace adc
|
||||
{
|
||||
|
||||
|
||||
class AdcDeviceNetServer : public AdcGenericNetServer
|
||||
{
|
||||
protected:
|
||||
typedef std::vector<char> serialized_t;
|
||||
|
||||
class DeviceWrapper
|
||||
{
|
||||
std::function<serialized_t()> _get_id = []() -> serialized_t { throw std::system_error(); };
|
||||
std::function<serialized_t(std::span<const char>)> _get_attr = [](auto) -> serialized_t {
|
||||
throw std::system_error();
|
||||
};
|
||||
std::function<void(std::span<const char>, std::span<const char>)> _set_attr = [](auto, auto) {
|
||||
throw std::system_error();
|
||||
};
|
||||
std::function<void(std::span<const char>)> _exec_cmd = [](auto) { throw std::system_error(); };
|
||||
|
||||
public:
|
||||
DeviceWrapper() {
|
||||
// null device
|
||||
};
|
||||
|
||||
template <interfaces::adc_device_c DeviceT,
|
||||
typename IdSerialT = traits::adc_char_identity<typename DeviceT::ident_t>,
|
||||
typename AttrIdDeserialT = traits::adc_char_identity<typename DeviceT::attr_ident_t>,
|
||||
typename CmdIdDeserialT = traits::adc_char_identity<typename DeviceT::cmd_ident_t>>
|
||||
DeviceWrapper(DeviceT* dev_ptr,
|
||||
IdSerialT&& id_ser_func = {}, // serializer of device ID
|
||||
AttrIdDeserialT&& attr_id_deser_func = {},
|
||||
CmdIdDeserialT&& cmd_id_deser_func = {})
|
||||
{
|
||||
_get_id = [dev_ptr, wrapper = traits::adc_pf_wrapper(std::forward<IdSerialT>(id_ser_func))]() {
|
||||
auto id = std::get<0>(wrapper)(dev_ptr->ident());
|
||||
return serialized_t{id.begin(), id.end()};
|
||||
};
|
||||
|
||||
_get_attr = [dev_ptr, wrapper = traits::adc_pf_wrapper(std::forward<AttrIdDeserialT>(attr_id_deser_func))](
|
||||
std::span<const char> attr_name) mutable {
|
||||
auto attr_id = std::get<0>(wrapper)(attr_name);
|
||||
auto val = (*dev_ptr)[attr_id].serialize();
|
||||
using val_t = std::remove_cvref_t<decltype(val)>;
|
||||
|
||||
if constexpr (std::same_as<serialized_t, val_t> || std::convertible_to<val_t, serialized_t>) {
|
||||
return val;
|
||||
} else {
|
||||
// !!!!!!!! TODO: val_t maust be a char range
|
||||
return serialized_t{val.begin(), val.end()};
|
||||
}
|
||||
};
|
||||
|
||||
_set_attr = [dev_ptr, wrapper = traits::adc_pf_wrapper(std::forward<AttrIdDeserialT>(attr_id_deser_func))](
|
||||
std::span<const char> attr_name, std::span<const char> val) mutable {
|
||||
auto attr_id = std::get<0>(wrapper)(attr_name);
|
||||
(*dev_ptr)[attr_id].deserialize(val);
|
||||
};
|
||||
|
||||
_exec_cmd = [dev_ptr, wrapper = traits::adc_pf_wrapper<CmdIdDeserialT>(cmd_id_deser_func)](
|
||||
std::span<const char> cmd_name) mutable {
|
||||
auto cmd_id = std::get<0>(wrapper)(cmd_name);
|
||||
(*dev_ptr)(cmd_id);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
serialized_t ident() const
|
||||
{
|
||||
return _get_id();
|
||||
}
|
||||
|
||||
serialized_t getAttr(std::span<const char> attr_name)
|
||||
{
|
||||
return _get_attr(attr_name);
|
||||
}
|
||||
|
||||
void setAttr(std::span<const char> attr_name, std::span<const char> val)
|
||||
{
|
||||
_set_attr(attr_name, val);
|
||||
}
|
||||
|
||||
void exec(std::span<const char> cmd_name)
|
||||
{
|
||||
_exec_cmd(cmd_name);
|
||||
}
|
||||
};
|
||||
|
||||
static DeviceWrapper nullDevice;
|
||||
|
||||
std::unordered_map<void*, DeviceWrapper> _devices;
|
||||
|
||||
public:
|
||||
template <interfaces::adc_netservice_c NetServiceT>
|
||||
class Session : std::enable_shared_from_this<Session<NetServiceT>>
|
||||
@ -18,8 +106,14 @@ public:
|
||||
typedef NetServiceT netservice_t;
|
||||
typedef AdcDeviceNetServer* netsession_ctx_t;
|
||||
|
||||
typedef std::vector<char> message_t;
|
||||
|
||||
template <traits::adc_input_char_range R>
|
||||
Session(R&& id, netservice_t srv, netsession_ctx_t ctx) : _ident(), _netService(std::move(srv)), _context(ctx)
|
||||
Session(R&& id, netservice_t srv, AdcDeviceNetServer* srv_ptr)
|
||||
: _ident(),
|
||||
_netService(std::move(srv)),
|
||||
_serverPtr(srv_ptr),
|
||||
_bindDevice(_serverPtr->_devices.size() ? _serverPtr->_devices[0] : AdcDeviceNetServer::nullDevice)
|
||||
{
|
||||
if constexpr (std::is_array_v<std::remove_cvref_t<R>>) {
|
||||
_ident = id;
|
||||
@ -36,11 +130,11 @@ public:
|
||||
void start()
|
||||
{
|
||||
_netService.asyncReceive(
|
||||
[this](std::error_code ec, std::vector<char> msg) {
|
||||
[this](std::error_code ec, message_t msg) {
|
||||
if (ec) {
|
||||
stop();
|
||||
} else {
|
||||
auto msg_sptr = std::make_shared<std::vector<char>>(std::move(msg));
|
||||
auto msg_sptr = std::make_shared<message_t>(std::move(msg));
|
||||
|
||||
AdcDeviceProtoMessage dev_msg(*msg_sptr);
|
||||
|
||||
@ -69,15 +163,36 @@ public:
|
||||
protected:
|
||||
netsession_ident_t _ident;
|
||||
netservice_t _netService;
|
||||
netsession_ctx_t _context;
|
||||
AdcDeviceNetServer* _serverPtr;
|
||||
AdcDeviceNetServer::DeviceWrapper& _bindDevice;
|
||||
|
||||
std::chrono::duration<size_t> _recvTimeout = std::chrono::seconds(3600);
|
||||
std::chrono::duration<size_t> _sendTimeout = std::chrono::seconds(5);
|
||||
|
||||
void handleMessage(auto& msg)
|
||||
{
|
||||
try {
|
||||
if (msg.isACK()) {
|
||||
msg.ack();
|
||||
} else if (msg.isDEVICE()) {
|
||||
auto dev_name = msg.attrs(1, 1);
|
||||
if (dev_name.size()) {
|
||||
bool found = false;
|
||||
for (auto& [ptr, dev_wr] : _serverPtr->_devices) {
|
||||
if (dev_wr.ident() == dev_name[0]) {
|
||||
_bindDevice = dev_wr;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
msg.ack();
|
||||
} else {
|
||||
msg.err(std::error_code{});
|
||||
}
|
||||
} else {
|
||||
msg.err(std::error_code{});
|
||||
}
|
||||
} else if (msg.isNAMES()) {
|
||||
} else if (msg.isHELLO()) {
|
||||
} else if (msg.isGET()) {
|
||||
@ -87,18 +202,35 @@ public:
|
||||
} else {
|
||||
msg.err(std::error_code{}); // !!!!!!!!!!!!
|
||||
}
|
||||
} catch (std::system_error ex) {
|
||||
msg.err(ex.code());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
using AdcGenericNetServer::AdcGenericNetServer;
|
||||
|
||||
template <typename DeviceT>
|
||||
AdcDeviceNetServer& addDevice(DeviceT* dev_ptr)
|
||||
template <interfaces::adc_device_c DeviceT,
|
||||
typename IdSerialT = traits::adc_char_identity<typename DeviceT::ident_t>,
|
||||
typename AttrIdDeserialT = traits::adc_char_identity<typename DeviceT::attr_ident_t>,
|
||||
typename CmdIdDeserialT = traits::adc_char_identity<typename DeviceT::cmd_ident_t>>
|
||||
AdcDeviceNetServer& addDevice(DeviceT* dev_ptr,
|
||||
IdSerialT&& id_ser_func = {}, // serializer of device ID
|
||||
AttrIdDeserialT&& attr_id_deser_func = {}, // deserializer of attribute ID
|
||||
CmdIdDeserialT&& cmd_id_deser_func = {}) // deserializer of command ID
|
||||
{
|
||||
auto id = std::forward<IdSerialT>(id_ser_func)(dev_ptr->ident());
|
||||
_devices.try_emplace(dev_ptr, dev_ptr, std::forward<IdSerialT>(id_ser_func),
|
||||
std::forward<AttrIdDeserialT>(attr_id_deser_func),
|
||||
std::forward<CmdIdDeserialT>(cmd_id_deser_func));
|
||||
}
|
||||
|
||||
protected:
|
||||
template <interfaces::adc_device_c DeviceT>
|
||||
AdcDeviceNetServer& delDevice(DeviceT* dev_ptr)
|
||||
{
|
||||
_devices.erase(dev_ptr);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace adc
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user