This commit is contained in:
Timur A. Fatkhullin
2024-10-21 01:21:53 +03:00
parent 117d8c4a3d
commit b8fdae9d16
4 changed files with 411 additions and 41 deletions

View File

@@ -1,5 +1,7 @@
#pragma once
#include <system_error>
#include "adc_device_netmsg.h"
#include "adc_netserver.h"
@@ -8,6 +10,100 @@
namespace adc
{
enum class AdcDeviceNetServerSessionError : int {
ERROR_OK,
ERROR_NULL_DEVICE,
ERROR_UNKNOWN_PROTO_KWD,
ERROR_UNKNOWN_DEVICE_ID,
ERROR_NO_DEVICE_ID,
ERROR_NO_PROTO_KWDNAME,
ERROR_NO_PROTO_ATTRNAME,
ERROR_NO_PROTO_ATTRVALUE,
ERROR_NO_PROTO_CMDNAME,
ERROR_UNKNOWN_ERROR
};
}
// place here to allow clang compilation
namespace std
{
template <>
class is_error_code_enum<adc::AdcDeviceNetServerSessionError> : public true_type
{
};
} // namespace std
namespace adc
{
struct AdcDeviceNetServerSessionErrorCategory : std::error_category {
AdcDeviceNetServerSessionErrorCategory() : std::error_category() {}
const char* name() const noexcept
{
return "ADC_DEVICE_NESERVER_SESSION";
}
std::string message(int ec) const
{
AdcDeviceNetServerSessionError err = static_cast<AdcDeviceNetServerSessionError>(ec);
switch (err) {
case AdcDeviceNetServerSessionError::ERROR_OK:
return "OK";
case AdcDeviceNetServerSessionError::ERROR_NULL_DEVICE:
return "device was not bound";
case AdcDeviceNetServerSessionError::ERROR_UNKNOWN_PROTO_KWD:
return "invalid formatted message: unrecognized message keyword";
case AdcDeviceNetServerSessionError::ERROR_UNKNOWN_DEVICE_ID:
return "invalid device identificator";
case AdcDeviceNetServerSessionError::ERROR_NO_DEVICE_ID:
return "invalid formatted message: device identificator is omitted";
case AdcDeviceNetServerSessionError::ERROR_NO_PROTO_KWDNAME:
return "invalid formatted message: keyword name is omitted";
case AdcDeviceNetServerSessionError::ERROR_NO_PROTO_CMDNAME:
return "invalid formatted message: command name is omitted";
case AdcDeviceNetServerSessionError::ERROR_NO_PROTO_ATTRNAME:
return "invalid formatted message: attribute name is omitted";
case AdcDeviceNetServerSessionError::ERROR_NO_PROTO_ATTRVALUE:
return "invalid formatted message: attribute value is omitted";
case AdcDeviceNetServerSessionError::ERROR_UNKNOWN_ERROR:
return "catch unhandled exception";
default:
return "UNKNOWN";
}
}
static const AdcDeviceNetServerSessionErrorCategory& get()
{
static const AdcDeviceNetServerSessionErrorCategory constInst;
return constInst;
}
};
} // namespace adc
namespace std
{
inline std::error_code make_error_code(adc::AdcDeviceNetServerSessionError ec)
{
return std::error_code(static_cast<int>(ec), adc::AdcDeviceNetServerSessionErrorCategory::get());
}
} // namespace std
namespace adc
{
class AdcDeviceNetServer : public AdcGenericNetServer
{
@@ -16,14 +112,22 @@ protected:
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();
public:
using char_range_t = std::span<const char>;
private:
serialized_t _id;
// std::function<serialized_t()> _get_id = []() -> serialized_t { throw std::system_error(); };
std::function<serialized_t(const char_range_t&)> _get_attr = [](auto) -> serialized_t {
throw std::system_error(std::make_error_code(AdcDeviceNetServerSessionError::ERROR_NULL_DEVICE));
};
std::function<void(std::span<const char>, std::span<const char>)> _set_attr = [](auto, auto) {
throw std::system_error();
std::function<void(const char_range_t&, const char_range_t&)> _set_attr = [](auto, auto) {
throw std::system_error(std::make_error_code(AdcDeviceNetServerSessionError::ERROR_NULL_DEVICE));
};
std::function<void(const char_range_t&)> _exec_cmd = [](auto) {
throw std::system_error(std::make_error_code(AdcDeviceNetServerSessionError::ERROR_NULL_DEVICE));
};
std::function<void(std::span<const char>)> _exec_cmd = [](auto) { throw std::system_error(); };
public:
DeviceWrapper() {
@@ -31,21 +135,22 @@ protected:
};
template <interfaces::adc_device_c DeviceT,
typename IdSerialT = traits::adc_char_identity<typename DeviceT::ident_t>,
// 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
const serialized_t& id,
AttrIdDeserialT&& attr_id_deser_func = {},
CmdIdDeserialT&& cmd_id_deser_func = {})
: _id(id)
{
_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_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 {
const char_range_t& 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)>;
@@ -59,13 +164,13 @@ protected:
};
_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 {
const char_range_t& attr_name, const char_range_t& 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 {
const char_range_t& cmd_name) mutable {
auto cmd_id = std::get<0>(wrapper)(cmd_name);
(*dev_ptr)(cmd_id);
};
@@ -74,20 +179,21 @@ protected:
serialized_t ident() const
{
return _get_id();
// return _get_id();
return _id;
}
serialized_t getAttr(std::span<const char> attr_name)
serialized_t getAttr(const char_range_t& attr_name)
{
return _get_attr(attr_name);
}
void setAttr(std::span<const char> attr_name, std::span<const char> val)
void setAttr(const char_range_t& attr_name, const char_range_t& val)
{
_set_attr(attr_name, val);
}
void exec(std::span<const char> cmd_name)
void exec(const char_range_t& cmd_name)
{
_exec_cmd(cmd_name);
}
@@ -138,7 +244,7 @@ public:
AdcDeviceProtoMessage dev_msg(*msg_sptr);
handleMessage(dev_msg);
processMessage(dev_msg);
_netService.asyncSend(
*msg_sptr,
@@ -169,17 +275,31 @@ public:
std::chrono::duration<size_t> _recvTimeout = std::chrono::seconds(3600);
std::chrono::duration<size_t> _sendTimeout = std::chrono::seconds(5);
void handleMessage(auto& msg)
void processMessage(auto& msg)
{
typedef std::vector<serialized_t> attr_vec_t;
attr_vec_t attrs;
auto get_elem = [&attrs](size_t idx) -> DeviceWrapper::char_range_t {
if (idx < attrs.size()) {
auto& el = attrs[idx];
return DeviceWrapper::char_range_t{el.begin(), el.end()};
} else {
return DeviceWrapper::char_range_t{};
}
};
try {
if (msg.isACK()) {
msg.ack();
} else if (msg.isDEVICE()) {
auto dev_name = msg.attrs(1, 1);
if (dev_name.size()) {
attrs = msg.template attrs<attr_vec_t>(0, 1);
if (attrs.size()) {
auto dev_name = get_elem(0);
bool found = false;
for (auto& [ptr, dev_wr] : _serverPtr->_devices) {
if (dev_wr.ident() == dev_name[0]) {
if (dev_wr.ident() == dev_name) {
_bindDevice = dev_wr;
found = true;
break;
@@ -188,19 +308,50 @@ public:
if (found) {
msg.ack();
} else {
msg.err(std::error_code{});
msg.err(std::make_error_code(AdcDeviceNetServerSessionError::ERROR_UNKNOWN_DEVICE_ID));
}
} else {
msg.err(std::error_code{});
msg.err(std::make_error_code(AdcDeviceNetServerSessionError::ERROR_NO_DEVICE_ID));
}
} else if (msg.isNAMES()) {
std::vector<serialized_t> names;
for (auto& [ptr, dev_wr] : _serverPtr->_devices) {
names.emplace_back(dev_wr.ident());
}
msg.ack(names);
} else if (msg.isHELLO()) {
} else if (msg.isGET()) {
} else if (msg.isGET()) { // get attribute value
attrs = msg.template attrs<attr_vec_t>(0, 1);
if (attrs.size()) {
auto val = _bindDevice.getAttr(get_elem(0));
msg.ack(get_elem(0), {val.begin(), val.end()});
} else { // no attr name!
msg.err(std::make_error_code(AdcDeviceNetServerSessionError::ERROR_NO_PROTO_ATTRNAME));
}
} else if (msg.isSET()) {
attrs = msg.template attrs<attr_vec_t>(0);
if (attrs.size() >= 2) {
auto val = msg.template joinAttrs<DeviceWrapper::char_range_t>(1);
_bindDevice.setAttr(get_elem(0), val);
msg.ack(get_elem(0), serialized_t{val.begin(), val.end()});
} else { // no attr name or its value!
if (attrs.size() == 1) {
msg.err(std::make_error_code(AdcDeviceNetServerSessionError::ERROR_NO_PROTO_ATTRVALUE));
} else {
msg.err(std::make_error_code(AdcDeviceNetServerSessionError::ERROR_NO_PROTO_ATTRNAME));
}
}
} else if (msg.isCMD()) {
msg.ack();
attrs = msg.template attrs<attr_vec_t>(0, 1);
if (attrs.size()) {
auto cmd_name = get_elem(0);
_bindDevice.exec(cmd_name);
msg.ack(cmd_name);
} else { // no cmd name!
msg.err(std::make_error_code(AdcDeviceNetServerSessionError::ERROR_NO_PROTO_CMDNAME));
}
} else {
msg.err(std::error_code{}); // !!!!!!!!!!!!
msg.err(std::make_error_code(AdcDeviceNetServerSessionError::ERROR_UNKNOWN_PROTO_KWD));
}
} catch (std::system_error ex) {
msg.err(ex.code());
@@ -221,9 +372,11 @@ public:
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),
_devices.try_emplace(dev_ptr, dev_ptr, id, std::forward<AttrIdDeserialT>(attr_id_deser_func),
std::forward<CmdIdDeserialT>(cmd_id_deser_func));
// _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));
}
template <interfaces::adc_device_c DeviceT>