diff --git a/common/adc_traits.h b/common/adc_traits.h index 52dec2d..2e44758 100644 --- a/common/adc_traits.h +++ b/common/adc_traits.h @@ -67,6 +67,25 @@ concept adc_range_of_output_char_range = template concept adc_range_of_view_or_output_char_range = adc_range_of_view_char_range || adc_output_char_range; + +template +struct adc_char_identity { + template + requires std::same_as + constexpr T&& operator()(T&& v) // like std::identity + { + return std::forward(v); + } + + template + requires(!std::same_as && + std::is_constructible_v, std::ranges::sentinel_t>) + constexpr R operator()(T&& v) + { + return {v.begin(), v.end()}; + } +}; + // deduce returned type of callable // template // using adc_retval_t = std::invoke_result_t>; diff --git a/device/adc_device.h b/device/adc_device.h index 47ead98..2e3d143 100644 --- a/device/adc_device.h +++ b/device/adc_device.h @@ -5,6 +5,8 @@ #include #include +#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 -concept adc_device_attr_c = requires { - typename T::ident_t; - &T::ident; - &T::serialize; - &T::deserialize; - // std::declval().operator int(); -}; - - -template -concept adc_device_cmd_c = requires { - typename T::ident_t; - &T::ident; - &T::operator(); -}; - - -} // namespace traits - - -template +template 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) { diff --git a/device/adc_device_concepts.h b/device/adc_device_concepts.h new file mode 100644 index 0000000..02743e6 --- /dev/null +++ b/device/adc_device_concepts.h @@ -0,0 +1,54 @@ +#pragma once + +#include + +namespace adc::interfaces +{ + +// ADC device attribute concept +template +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; + + // serializer and desiarializer must return/accept at least a value of type T::default_serialized_t + { t.serialize() } -> std::convertible_to; + t.deserialize(std::declval()); +}; + + +// ADC device command concept +template +concept adc_device_cmd_c = requires(T t, const T const_t) { + typename T::ident_t; + + { const_t.ident() } -> std::same_as; + t(); // operator()() +}; + + +// ADC device concept + +template +concept adc_device_c = requires(T t, const T const_t) { + typename T::ident_t; + + requires adc_device_attr_c; + requires adc_device_cmd_c; + + typename T::attr_ident_t; + typename T::cmd_ident_t; + + { const_t.ident() } -> std::same_as; + + t(std::declval()); // operator()(cmd_ident_t) + + { + t[std::declval()] + } -> std::same_as; // attribute_t& operator[](attr_ident_t) +}; + + +} // namespace adc::interfaces diff --git a/net/adc_device_netserver.h b/net/adc_device_netserver.h index 065f279..e0cb6a7 100644 --- a/net/adc_device_netserver.h +++ b/net/adc_device_netserver.h @@ -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 serialized_t; + + class DeviceWrapper + { + std::function _get_id = []() -> serialized_t { throw std::system_error(); }; + std::function)> _get_attr = [](auto) -> serialized_t { + throw std::system_error(); + }; + std::function, std::span)> _set_attr = [](auto, auto) { + throw std::system_error(); + }; + std::function)> _exec_cmd = [](auto) { throw std::system_error(); }; + + public: + DeviceWrapper() { + // null device + }; + + template , + typename AttrIdDeserialT = traits::adc_char_identity, + typename CmdIdDeserialT = traits::adc_char_identity> + 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(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(attr_id_deser_func))]( + std::span 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; + + if constexpr (std::same_as || std::convertible_to) { + 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(attr_id_deser_func))]( + std::span attr_name, std::span 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(cmd_id_deser_func)]( + std::span 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 attr_name) + { + return _get_attr(attr_name); + } + + void setAttr(std::span attr_name, std::span val) + { + _set_attr(attr_name, val); + } + + void exec(std::span cmd_name) + { + _exec_cmd(cmd_name); + } + }; + + static DeviceWrapper nullDevice; + + std::unordered_map _devices; + public: template class Session : std::enable_shared_from_this> @@ -18,8 +106,14 @@ public: typedef NetServiceT netservice_t; typedef AdcDeviceNetServer* netsession_ctx_t; + typedef std::vector message_t; + template - 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>) { _ident = id; @@ -36,11 +130,11 @@ public: void start() { _netService.asyncReceive( - [this](std::error_code ec, std::vector msg) { + [this](std::error_code ec, message_t msg) { if (ec) { stop(); } else { - auto msg_sptr = std::make_shared>(std::move(msg)); + auto msg_sptr = std::make_shared(std::move(msg)); AdcDeviceProtoMessage dev_msg(*msg_sptr); @@ -69,23 +163,47 @@ public: protected: netsession_ident_t _ident; netservice_t _netService; - netsession_ctx_t _context; + AdcDeviceNetServer* _serverPtr; + AdcDeviceNetServer::DeviceWrapper& _bindDevice; std::chrono::duration _recvTimeout = std::chrono::seconds(3600); std::chrono::duration _sendTimeout = std::chrono::seconds(5); void handleMessage(auto& msg) { - if (msg.isACK()) { - msg.ack(); - } else if (msg.isNAMES()) { - } else if (msg.isHELLO()) { - } else if (msg.isGET()) { - } else if (msg.isSET()) { - } else if (msg.isCMD()) { - msg.ack(); - } else { - msg.err(std::error_code{}); // !!!!!!!!!!!! + 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()) { + } else if (msg.isSET()) { + } else if (msg.isCMD()) { + msg.ack(); + } else { + msg.err(std::error_code{}); // !!!!!!!!!!!! + } + } catch (std::system_error ex) { + msg.err(ex.code()); } } }; @@ -93,12 +211,26 @@ public: using AdcGenericNetServer::AdcGenericNetServer; - template - AdcDeviceNetServer& addDevice(DeviceT* dev_ptr) + template , + typename AttrIdDeserialT = traits::adc_char_identity, + typename CmdIdDeserialT = traits::adc_char_identity> + 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(id_ser_func)(dev_ptr->ident()); + _devices.try_emplace(dev_ptr, dev_ptr, std::forward(id_ser_func), + std::forward(attr_id_deser_func), + std::forward(cmd_id_deser_func)); } -protected: + template + AdcDeviceNetServer& delDevice(DeviceT* dev_ptr) + { + _devices.erase(dev_ptr); + } }; } // namespace adc