...
This commit is contained in:
parent
117d8c4a3d
commit
b8fdae9d16
@ -21,11 +21,12 @@ set(ADC_DEVICE_HEADERS
|
|||||||
device/adc_device_attribute.h
|
device/adc_device_attribute.h
|
||||||
device/adc_device_command.h
|
device/adc_device_command.h
|
||||||
device/adc_device.h
|
device/adc_device.h
|
||||||
|
device/adc_device_concepts.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
set(ADC_NETWORK_HEADERS
|
set(ADC_NETWORK_HEADERS
|
||||||
net/adc_netmsg.h
|
# net/adc_netmsg.h
|
||||||
# net/adc_netmessage.h
|
# net/adc_netmessage.h
|
||||||
net/adc_netproto.h
|
net/adc_netproto.h
|
||||||
net/adc_netservice.h
|
net/adc_netservice.h
|
||||||
@ -33,6 +34,7 @@ set(ADC_NETWORK_HEADERS
|
|||||||
net/adc_netserver.h
|
net/adc_netserver.h
|
||||||
net/adc_net_concepts.h
|
net/adc_net_concepts.h
|
||||||
net/adc_device_netmsg.h
|
net/adc_device_netmsg.h
|
||||||
|
net/adc_device_netserver.h
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -74,6 +76,7 @@ if (SPDLOG_LIBRARY)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
option(USE_UWEBSOCKET "Use of uWebsocket library for websocket-related staff" ON)
|
option(USE_UWEBSOCKET "Use of uWebsocket library for websocket-related staff" ON)
|
||||||
|
|
||||||
if (USE_UWEBSOCKET)
|
if (USE_UWEBSOCKET)
|
||||||
|
|||||||
@ -174,18 +174,26 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename KeyT, typename... ValuePartTs>
|
template <typename KeyT>
|
||||||
requires traits::adc_output_char_range<ByteSeqT>
|
requires traits::adc_output_char_range<ByteSeqT>
|
||||||
AdcKeyValueMessage& setKeyValue(KeyT&& key, ValuePartTs&&... values)
|
AdcKeyValueMessage& setKey(const KeyT& key)
|
||||||
{
|
{
|
||||||
if (std::ranges::size(_byteSequence)) {
|
if (std::ranges::size(_byteSequence)) {
|
||||||
_byteSequence = ByteSeqT();
|
_byteSequence = ByteSeqT();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::ranges::copy(utils::AdcDefaultValueConverter<COMPOSITE_VALUE_DELIM>::template serialize<ByteSeqT>(
|
std::ranges::copy(utils::AdcDefaultValueConverter<COMPOSITE_VALUE_DELIM>::template serialize<ByteSeqT>(key),
|
||||||
std::forward<KeyT>(key)),
|
|
||||||
std::back_inserter(_byteSequence));
|
std::back_inserter(_byteSequence));
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename KeyT, typename... ValuePartTs>
|
||||||
|
requires traits::adc_output_char_range<ByteSeqT>
|
||||||
|
AdcKeyValueMessage& setKeyValue(const KeyT& key, ValuePartTs&&... values)
|
||||||
|
{
|
||||||
|
setKey(key);
|
||||||
|
|
||||||
if constexpr (sizeof...(ValuePartTs)) {
|
if constexpr (sizeof...(ValuePartTs)) {
|
||||||
std::ranges::copy(keyValueDelimiter, std::back_inserter(_byteSequence));
|
std::ranges::copy(keyValueDelimiter, std::back_inserter(_byteSequence));
|
||||||
setValueHelper(std::forward<ValuePartTs>(values)...);
|
setValueHelper(std::forward<ValuePartTs>(values)...);
|
||||||
@ -194,6 +202,36 @@ public:
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename KeyT, std::ranges::input_range ValuePartRangeT>
|
||||||
|
requires traits::adc_output_char_range<ByteSeqT>
|
||||||
|
AdcKeyValueMessage& setKeyValue(const KeyT& key, const ValuePartRangeT& values)
|
||||||
|
{
|
||||||
|
setKey(key);
|
||||||
|
|
||||||
|
for (auto const& el : values) {
|
||||||
|
std::ranges::copy(keyValueDelimiter, std::back_inserter(_byteSequence));
|
||||||
|
setValueHelper(el);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename KeyT, traits::adc_tuple_like ValuePartTupleT>
|
||||||
|
requires traits::adc_output_char_range<ByteSeqT>
|
||||||
|
AdcKeyValueMessage& setKeyValue(const KeyT& key, const ValuePartTupleT& values)
|
||||||
|
{
|
||||||
|
setKey(key);
|
||||||
|
|
||||||
|
if constexpr (std::tuple_size_v<ValuePartTupleT>) {
|
||||||
|
std::apply([this]<typename... Ts>(Ts&&... args) { setValueHelper(std::forward<Ts>(args)...); }, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename... ValuePartTs>
|
template <typename... ValuePartTs>
|
||||||
requires traits::adc_output_char_range<ByteSeqT>
|
requires traits::adc_output_char_range<ByteSeqT>
|
||||||
AdcKeyValueMessage& setValue(ValuePartTs&&... values)
|
AdcKeyValueMessage& setValue(ValuePartTs&&... values)
|
||||||
@ -201,9 +239,32 @@ public:
|
|||||||
std::vector<char> kw;
|
std::vector<char> kw;
|
||||||
std::ranges::copy(key<std::span<const char>>(), std::back_inserter(kw));
|
std::ranges::copy(key<std::span<const char>>(), std::back_inserter(kw));
|
||||||
|
|
||||||
return setValue(kw, std::forward<ValuePartTs>(values)...);
|
return setKeyValue(kw, std::forward<ValuePartTs>(values)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename KeyT, std::ranges::input_range ValuePartRangeT>
|
||||||
|
requires traits::adc_output_char_range<ByteSeqT> &&
|
||||||
|
(!traits::adc_input_char_range<std::ranges::range_value_t<ValuePartRangeT>>)
|
||||||
|
AdcKeyValueMessage& setValue(const ValuePartRangeT& values)
|
||||||
|
{
|
||||||
|
std::vector<char> kw;
|
||||||
|
std::ranges::copy(key<std::span<const char>>(), std::back_inserter(kw));
|
||||||
|
|
||||||
|
return setKeyValue(kw, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename KeyT, traits::adc_tuple_like ValuePartTupleT>
|
||||||
|
requires traits::adc_output_char_range<ByteSeqT>
|
||||||
|
AdcKeyValueMessage& setValue(const ValuePartTupleT& values)
|
||||||
|
{
|
||||||
|
std::vector<char> kw;
|
||||||
|
std::ranges::copy(key<std::span<const char>>(), std::back_inserter(kw));
|
||||||
|
|
||||||
|
return setKeyValue(kw, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
ByteSeqT& _byteSequence;
|
ByteSeqT& _byteSequence;
|
||||||
|
|
||||||
@ -374,11 +435,40 @@ public:
|
|||||||
|
|
||||||
void ack()
|
void ack()
|
||||||
{
|
{
|
||||||
base_t::setKeyValue(ACK_KEY);
|
base_t::setKey(ACK_KEY);
|
||||||
|
|
||||||
keyHash();
|
keyHash();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <typename ParT, typename... ParTs>
|
||||||
|
void ack(const ParT& param, const ParTs&... params)
|
||||||
|
{
|
||||||
|
base_t::setKeyValue(ACK_KEY, param, params...);
|
||||||
|
|
||||||
|
keyHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <std::ranges::range ParT>
|
||||||
|
requires(!traits::adc_input_char_range<std::ranges::range_value_t<ParT>>)
|
||||||
|
void ack(const ParT& param)
|
||||||
|
{
|
||||||
|
base_t::setKeyValue(ACK_KEY, param);
|
||||||
|
|
||||||
|
keyHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <traits::adc_tuple_like ParT>
|
||||||
|
void ack(const ParT& param)
|
||||||
|
{
|
||||||
|
base_t::setKeyValue(ACK_KEY, param);
|
||||||
|
|
||||||
|
keyHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template <traits::adc_input_char_range AttrNameT, typename ValueT, typename... ValueTs>
|
template <traits::adc_input_char_range AttrNameT, typename ValueT, typename... ValueTs>
|
||||||
void set(AttrNameT&& attr_name, ValueT&& value, ValueTs&&... values)
|
void set(AttrNameT&& attr_name, ValueT&& value, ValueTs&&... values)
|
||||||
{
|
{
|
||||||
@ -429,7 +519,32 @@ public:
|
|||||||
|
|
||||||
void names()
|
void names()
|
||||||
{
|
{
|
||||||
base_t::setKeyValue(NAMES_KEY);
|
base_t::setKey(NAMES_KEY);
|
||||||
|
|
||||||
|
keyHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename DevNameT, typename... DevNameTs>
|
||||||
|
void names(const DevNameT& dev_name, const DevNameTs&... dev_names)
|
||||||
|
{
|
||||||
|
base_t::setKeyValue(NAMES_KEY, dev_name, dev_names...);
|
||||||
|
|
||||||
|
keyHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <std::ranges::input_range R>
|
||||||
|
requires(!traits::adc_input_char_range<std::ranges::range_value_t<R>>)
|
||||||
|
void names(const R& dev_names)
|
||||||
|
{
|
||||||
|
base_t::setKeyValue(NAMES_KEY, dev_names);
|
||||||
|
|
||||||
|
keyHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <traits::adc_tuple_like T>
|
||||||
|
void names(const T& dev_names)
|
||||||
|
{
|
||||||
|
base_t::setKeyValue(NAMES_KEY, dev_names);
|
||||||
|
|
||||||
keyHash();
|
keyHash();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
#include "adc_device_netmsg.h"
|
#include "adc_device_netmsg.h"
|
||||||
#include "adc_netserver.h"
|
#include "adc_netserver.h"
|
||||||
|
|
||||||
@ -8,6 +10,100 @@
|
|||||||
namespace adc
|
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
|
class AdcDeviceNetServer : public AdcGenericNetServer
|
||||||
{
|
{
|
||||||
@ -16,14 +112,22 @@ protected:
|
|||||||
|
|
||||||
class DeviceWrapper
|
class DeviceWrapper
|
||||||
{
|
{
|
||||||
std::function<serialized_t()> _get_id = []() -> serialized_t { throw std::system_error(); };
|
public:
|
||||||
std::function<serialized_t(std::span<const char>)> _get_attr = [](auto) -> serialized_t {
|
using char_range_t = std::span<const char>;
|
||||||
throw std::system_error();
|
|
||||||
|
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) {
|
std::function<void(const char_range_t&, const char_range_t&)> _set_attr = [](auto, auto) {
|
||||||
throw std::system_error();
|
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:
|
public:
|
||||||
DeviceWrapper() {
|
DeviceWrapper() {
|
||||||
@ -31,21 +135,22 @@ protected:
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <interfaces::adc_device_c DeviceT,
|
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 AttrIdDeserialT = traits::adc_char_identity<typename DeviceT::attr_ident_t>,
|
||||||
typename CmdIdDeserialT = traits::adc_char_identity<typename DeviceT::cmd_ident_t>>
|
typename CmdIdDeserialT = traits::adc_char_identity<typename DeviceT::cmd_ident_t>>
|
||||||
DeviceWrapper(DeviceT* dev_ptr,
|
DeviceWrapper(DeviceT* dev_ptr,
|
||||||
IdSerialT&& id_ser_func = {}, // serializer of device ID
|
const serialized_t& id,
|
||||||
AttrIdDeserialT&& attr_id_deser_func = {},
|
AttrIdDeserialT&& attr_id_deser_func = {},
|
||||||
CmdIdDeserialT&& cmd_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))]() {
|
// _get_id = [dev_ptr, wrapper = traits::adc_pf_wrapper(std::forward<IdSerialT>(id_ser_func))]() {
|
||||||
auto id = std::get<0>(wrapper)(dev_ptr->ident());
|
// auto id = std::get<0>(wrapper)(dev_ptr->ident());
|
||||||
return serialized_t{id.begin(), id.end()};
|
// return serialized_t{id.begin(), id.end()};
|
||||||
};
|
// };
|
||||||
|
|
||||||
_get_attr = [dev_ptr, wrapper = traits::adc_pf_wrapper(std::forward<AttrIdDeserialT>(attr_id_deser_func))](
|
_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 attr_id = std::get<0>(wrapper)(attr_name);
|
||||||
auto val = (*dev_ptr)[attr_id].serialize();
|
auto val = (*dev_ptr)[attr_id].serialize();
|
||||||
using val_t = std::remove_cvref_t<decltype(val)>;
|
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))](
|
_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);
|
auto attr_id = std::get<0>(wrapper)(attr_name);
|
||||||
(*dev_ptr)[attr_id].deserialize(val);
|
(*dev_ptr)[attr_id].deserialize(val);
|
||||||
};
|
};
|
||||||
|
|
||||||
_exec_cmd = [dev_ptr, wrapper = traits::adc_pf_wrapper<CmdIdDeserialT>(cmd_id_deser_func)](
|
_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);
|
auto cmd_id = std::get<0>(wrapper)(cmd_name);
|
||||||
(*dev_ptr)(cmd_id);
|
(*dev_ptr)(cmd_id);
|
||||||
};
|
};
|
||||||
@ -74,20 +179,21 @@ protected:
|
|||||||
|
|
||||||
serialized_t ident() const
|
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);
|
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);
|
_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);
|
_exec_cmd(cmd_name);
|
||||||
}
|
}
|
||||||
@ -138,7 +244,7 @@ public:
|
|||||||
|
|
||||||
AdcDeviceProtoMessage dev_msg(*msg_sptr);
|
AdcDeviceProtoMessage dev_msg(*msg_sptr);
|
||||||
|
|
||||||
handleMessage(dev_msg);
|
processMessage(dev_msg);
|
||||||
|
|
||||||
_netService.asyncSend(
|
_netService.asyncSend(
|
||||||
*msg_sptr,
|
*msg_sptr,
|
||||||
@ -169,17 +275,31 @@ public:
|
|||||||
std::chrono::duration<size_t> _recvTimeout = std::chrono::seconds(3600);
|
std::chrono::duration<size_t> _recvTimeout = std::chrono::seconds(3600);
|
||||||
std::chrono::duration<size_t> _sendTimeout = std::chrono::seconds(5);
|
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 {
|
try {
|
||||||
if (msg.isACK()) {
|
if (msg.isACK()) {
|
||||||
msg.ack();
|
msg.ack();
|
||||||
} else if (msg.isDEVICE()) {
|
} else if (msg.isDEVICE()) {
|
||||||
auto dev_name = msg.attrs(1, 1);
|
attrs = msg.template attrs<attr_vec_t>(0, 1);
|
||||||
if (dev_name.size()) {
|
if (attrs.size()) {
|
||||||
|
auto dev_name = get_elem(0);
|
||||||
bool found = false;
|
bool found = false;
|
||||||
for (auto& [ptr, dev_wr] : _serverPtr->_devices) {
|
for (auto& [ptr, dev_wr] : _serverPtr->_devices) {
|
||||||
if (dev_wr.ident() == dev_name[0]) {
|
if (dev_wr.ident() == dev_name) {
|
||||||
_bindDevice = dev_wr;
|
_bindDevice = dev_wr;
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
@ -188,19 +308,50 @@ public:
|
|||||||
if (found) {
|
if (found) {
|
||||||
msg.ack();
|
msg.ack();
|
||||||
} else {
|
} else {
|
||||||
msg.err(std::error_code{});
|
msg.err(std::make_error_code(AdcDeviceNetServerSessionError::ERROR_UNKNOWN_DEVICE_ID));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
msg.err(std::error_code{});
|
msg.err(std::make_error_code(AdcDeviceNetServerSessionError::ERROR_NO_DEVICE_ID));
|
||||||
}
|
}
|
||||||
} else if (msg.isNAMES()) {
|
} 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.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()) {
|
} 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()) {
|
} 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 {
|
} else {
|
||||||
msg.err(std::error_code{}); // !!!!!!!!!!!!
|
msg.err(std::make_error_code(AdcDeviceNetServerSessionError::ERROR_UNKNOWN_PROTO_KWD));
|
||||||
}
|
}
|
||||||
} catch (std::system_error ex) {
|
} catch (std::system_error ex) {
|
||||||
msg.err(ex.code());
|
msg.err(ex.code());
|
||||||
@ -221,9 +372,11 @@ public:
|
|||||||
CmdIdDeserialT&& cmd_id_deser_func = {}) // deserializer of command ID
|
CmdIdDeserialT&& cmd_id_deser_func = {}) // deserializer of command ID
|
||||||
{
|
{
|
||||||
auto id = std::forward<IdSerialT>(id_ser_func)(dev_ptr->ident());
|
auto id = std::forward<IdSerialT>(id_ser_func)(dev_ptr->ident());
|
||||||
_devices.try_emplace(dev_ptr, dev_ptr, std::forward<IdSerialT>(id_ser_func),
|
_devices.try_emplace(dev_ptr, dev_ptr, id, std::forward<AttrIdDeserialT>(attr_id_deser_func),
|
||||||
std::forward<AttrIdDeserialT>(attr_id_deser_func),
|
|
||||||
std::forward<CmdIdDeserialT>(cmd_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>
|
template <interfaces::adc_device_c DeviceT>
|
||||||
|
|||||||
@ -97,6 +97,39 @@ public:
|
|||||||
virtual ~AdcNetSessionManager() = default;
|
virtual ~AdcNetSessionManager() = default;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
AdcNetSessionManager() = default;
|
||||||
|
|
||||||
|
AdcNetSessionManager(const AdcNetSessionManager&) = delete;
|
||||||
|
AdcNetSessionManager(AdcNetSessionManager&& other)
|
||||||
|
{
|
||||||
|
if (this == &other) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& func : _moveCtorFunc) {
|
||||||
|
func(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
_stopSessionFunc = std::move(other._stopSessionFunc);
|
||||||
|
_moveCtorFunc = std::move(other._moveCtorFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
AdcNetSessionManager& operator=(const AdcNetSessionManager&) = delete;
|
||||||
|
AdcNetSessionManager& operator=(AdcNetSessionManager&& other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
for (auto& func : _moveCtorFunc) {
|
||||||
|
func(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
_stopSessionFunc = std::move(other._stopSessionFunc);
|
||||||
|
_moveCtorFunc = std::move(other._moveCtorFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
template <interfaces::adc_netsession_c SessionT>
|
template <interfaces::adc_netsession_c SessionT>
|
||||||
constexpr static bool anySessionPredicate(const typename SessionT::netsession_ident_t&)
|
constexpr static bool anySessionPredicate(const typename SessionT::netsession_ident_t&)
|
||||||
{
|
{
|
||||||
@ -107,6 +140,7 @@ protected:
|
|||||||
template <interfaces::adc_netsession_c SessionT>
|
template <interfaces::adc_netsession_c SessionT>
|
||||||
static std::unordered_map<const AdcNetSessionManager*, std::set<std::weak_ptr<SessionT>>> _serverSessions;
|
static std::unordered_map<const AdcNetSessionManager*, std::set<std::weak_ptr<SessionT>>> _serverSessions;
|
||||||
std::vector<std::function<bool()>> _stopSessionFunc;
|
std::vector<std::function<bool()>> _stopSessionFunc;
|
||||||
|
std::vector<std::function<void(const AdcNetSessionManager*)>> _moveCtorFunc;
|
||||||
|
|
||||||
template <interfaces::adc_netsession_c SessionT>
|
template <interfaces::adc_netsession_c SessionT>
|
||||||
void startSession(std::shared_ptr<SessionT>& sess_ptr)
|
void startSession(std::shared_ptr<SessionT>& sess_ptr)
|
||||||
@ -115,16 +149,24 @@ protected:
|
|||||||
if (res.second) {
|
if (res.second) {
|
||||||
sess_ptr.start();
|
sess_ptr.start();
|
||||||
|
|
||||||
_stopSessionFunc.emplace_back([res]() {
|
_stopSessionFunc.emplace_back([res, this]() {
|
||||||
if (!res.first.expired()) { // session is still existing
|
if (!res.first.expired()) { // session is still existing
|
||||||
auto sess = res.first.lock();
|
auto sess = res.first.lock();
|
||||||
sess->stop();
|
sess->stop();
|
||||||
|
_serverSessions<SessionT>[this].erase(res.first);
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// define move-function only once per SessionT!
|
||||||
|
if (_serverSessions<SessionT>[this].size() == 1) {
|
||||||
|
_moveCtorFunc.emplace_back([this](const AdcNetSessionManager* new_instance) {
|
||||||
|
_serverSessions<SessionT>[new_instance] = std::move(_serverSessions<SessionT>[this]);
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -134,20 +176,31 @@ protected:
|
|||||||
{
|
{
|
||||||
size_t N = 0;
|
size_t N = 0;
|
||||||
|
|
||||||
|
std::set<std::weak_ptr<SessionT>> remove_wptr;
|
||||||
|
|
||||||
for (auto& wptr : _serverSessions<SessionT>[this]) {
|
for (auto& wptr : _serverSessions<SessionT>[this]) {
|
||||||
if (std::shared_ptr<SessionT> sptr = wptr.lock()) {
|
if (std::shared_ptr<SessionT> sptr = wptr.lock()) {
|
||||||
if constexpr (std::same_as<PredT, decltype(anySessionPredicate<SessionT>)>) {
|
if constexpr (std::same_as<PredT, decltype(anySessionPredicate<SessionT>)>) {
|
||||||
sptr->stop();
|
sptr->stop();
|
||||||
|
remove_wptr.emplace(wptr);
|
||||||
++N;
|
++N;
|
||||||
} else {
|
} else {
|
||||||
if (std::forward<PredT>(comp_func)(sptr->ident())) {
|
if (std::forward<PredT>(comp_func)(sptr->ident())) {
|
||||||
sptr->stop();
|
sptr->stop();
|
||||||
|
remove_wptr.emplace(wptr);
|
||||||
++N;
|
++N;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else { // remove already stopped sessions?!!
|
||||||
|
remove_wptr.emplace(wptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (auto& wptr : remove_wptr) {
|
||||||
|
_serverSessions<SessionT>[this].erase(wptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
return N;
|
return N;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -161,6 +214,7 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
_stopSessionFunc.clear();
|
_stopSessionFunc.clear();
|
||||||
|
_moveCtorFunc.clear(); // there are nothing to move after stopping of all sessions
|
||||||
|
|
||||||
return N;
|
return N;
|
||||||
}
|
}
|
||||||
@ -172,7 +226,6 @@ protected:
|
|||||||
|
|
||||||
class AdcGenericNetServer : public AdcPosixGenericDaemon, public AdcNetSessionManager
|
class AdcGenericNetServer : public AdcPosixGenericDaemon, public AdcNetSessionManager
|
||||||
{
|
{
|
||||||
protected:
|
|
||||||
public:
|
public:
|
||||||
typedef std::string server_ident_t;
|
typedef std::string server_ident_t;
|
||||||
|
|
||||||
@ -186,8 +239,46 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
AdcGenericNetServer(const AdcGenericNetServer&) = delete;
|
||||||
|
AdcGenericNetServer(AdcGenericNetServer&& other)
|
||||||
|
: AdcPosixGenericDaemon(std::move(other)), AdcNetSessionManager(std::move(other))
|
||||||
|
{
|
||||||
|
if (this == &other) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
_serverIdent = std::move(other._serverIdent);
|
||||||
|
_stopListenFunc = std::move(other._stopListenFunc);
|
||||||
|
|
||||||
|
for (auto& func : other._moveCtorFunc) {
|
||||||
|
func(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
_moveCtorFunc = std::move(other._moveCtorFunc);
|
||||||
|
}
|
||||||
|
|
||||||
virtual ~AdcGenericNetServer() = default;
|
virtual ~AdcGenericNetServer() = default;
|
||||||
|
|
||||||
|
AdcGenericNetServer& operator=(const AdcGenericNetServer&) = delete;
|
||||||
|
AdcGenericNetServer& operator=(AdcGenericNetServer&& other)
|
||||||
|
{
|
||||||
|
if (this != &other) {
|
||||||
|
AdcPosixGenericDaemon::operator=(std::move(other));
|
||||||
|
AdcNetSessionManager::operator=(std::move(other));
|
||||||
|
|
||||||
|
_serverIdent = std::move(other._serverIdent);
|
||||||
|
_stopListenFunc = std::move(other._stopListenFunc);
|
||||||
|
|
||||||
|
for (auto& func : other._moveCtorFunc) {
|
||||||
|
func(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
_moveCtorFunc = std::move(other._moveCtorFunc);
|
||||||
|
}
|
||||||
|
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
virtual server_ident_t ident() const
|
virtual server_ident_t ident() const
|
||||||
{
|
{
|
||||||
@ -214,6 +305,13 @@ public:
|
|||||||
|
|
||||||
doAccept<SessionT>(acceptor, id, sess_ctx);
|
doAccept<SessionT>(acceptor, id, sess_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// only once per SessionT
|
||||||
|
if (_isListening<SessionT>[this].size() == 1) {
|
||||||
|
_moveCtorFunc = [this](const AdcGenericNetServer* new_instance) {
|
||||||
|
_isListening<SessionT>[new_instance] = std::move(_isListening<SessionT>[this]);
|
||||||
|
};
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -247,6 +345,7 @@ protected:
|
|||||||
_isListening{};
|
_isListening{};
|
||||||
|
|
||||||
std::vector<std::function<void()>> _stopListenFunc;
|
std::vector<std::function<void()>> _stopListenFunc;
|
||||||
|
std::vector<std::function<void(const AdcGenericNetServer*)>> _moveCtorFunc;
|
||||||
|
|
||||||
server_ident_t _serverIdent;
|
server_ident_t _serverIdent;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user