#pragma once #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> { public: typedef std::string netsession_ident_t; typedef NetServiceT netservice_t; typedef AdcDeviceNetServer* netsession_ctx_t; typedef std::vector message_t; template 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; } else { _ident = netsession_ident_t(id.begin(), id.end()); } } netsession_ident_t ident() const { return _ident; } void start() { _netService.asyncReceive( [this](std::error_code ec, message_t msg) { if (ec) { stop(); } else { auto msg_sptr = std::make_shared(std::move(msg)); AdcDeviceProtoMessage dev_msg(*msg_sptr); handleMessage(dev_msg); _netService.asyncSend( *msg_sptr, [msg_sptr, this](std::error_code ec) { if (ec) { stop(); } else { start(); } }, _sendTimeout); } }, _recvTimeout); } void stop() { _netService.close(); } protected: netsession_ident_t _ident; netservice_t _netService; 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) { 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()); } } }; using AdcGenericNetServer::AdcGenericNetServer; 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)); } template AdcDeviceNetServer& delDevice(DeviceT* dev_ptr) { _devices.erase(dev_ptr); } }; } // namespace adc