This commit is contained in:
Timur A. Fatkhullin 2024-11-20 12:23:50 +03:00
parent ae6fbf18ca
commit 319276845a
2 changed files with 127 additions and 101 deletions

View File

@ -98,6 +98,11 @@ public:
typedef SessionIdentT netsession_ident_t; typedef SessionIdentT netsession_ident_t;
typedef NetServiceT netservice_t; typedef NetServiceT netservice_t;
// default server respond type
typedef std::vector<std::string> default_server_resp_t;
// asynchronous callback callable type for ADC device getter/setter/executor
typedef std::function<void(ServerResponseType, default_server_resp_t)> async_callback_func_t;
struct netsession_ctx_t { struct netsession_ctx_t {
AdcDeviceNetClient* clientPtr; AdcDeviceNetClient* clientPtr;
std::chrono::milliseconds recvTimeout; std::chrono::milliseconds recvTimeout;
@ -147,21 +152,14 @@ public:
// ADC device helper methods (blocking) // ADC device helper methods (blocking)
typedef std::vector<std::string> default_server_resp_t;
// get names of devices // get names of devices
template <traits::adc_range_of_output_char_range R> template <traits::adc_range_of_output_char_range R>
R deviceNames(ServerResponseType& rtype) R deviceNames(ServerResponseType& rtype)
{ {
typename netservice_t::send_msg_t bytes;
AdcDeviceProtoMessage msg(bytes);
msg.names();
using m_t = std::remove_cvref_t<decltype(msg)>;
// expected respond: ACK NAMES DEV1 DEV2 ... // expected respond: ACK NAMES DEV1 DEV2 ...
// return DEV1 DEV2 ... (or error description 'code category what') // return DEV1 DEV2 ... (or error description 'code category what')
return _getFromServer<R>(m_t::NAMES_KEY, bytes, rtype); return deviceFuncHelper<R>(constants::ADC_DEVICE_NETPROTO_KEY_NAMES, rtype);
} }
default_server_resp_t deviceNames(ServerResponseType& rtype) default_server_resp_t deviceNames(ServerResponseType& rtype)
@ -173,15 +171,10 @@ public:
template <traits::adc_range_of_output_char_range R, traits::adc_input_char_range DevNameT> template <traits::adc_range_of_output_char_range R, traits::adc_input_char_range DevNameT>
R bindDevice(DevNameT&& dev_name, ServerResponseType& rtype) R bindDevice(DevNameT&& dev_name, ServerResponseType& rtype)
{ {
typename netservice_t::send_msg_t bytes;
AdcDeviceProtoMessage msg(bytes);
msg.device(std::forward<DevNameT>(dev_name));
using m_t = std::remove_cvref_t<decltype(msg)>;
// expected respond: ACK DEVICE DEV_NAME // expected respond: ACK DEVICE DEV_NAME
// return DEV_NAME ... (or error description 'code category what') // return DEV_NAME ... (or error description 'code category what')
return _getFromServer<R>(m_t::DEVICE_KEY, bytes, rtype); return deviceFuncHelper<R>(constants::ADC_DEVICE_NETPROTO_KEY_DEVICE, rtype,
std::forward<DevNameT>(dev_name));
} }
template <traits::adc_input_char_range DevNameT> template <traits::adc_input_char_range DevNameT>
@ -195,16 +188,9 @@ public:
template <traits::adc_range_of_output_char_range R, traits::adc_input_char_range CmdNameT> template <traits::adc_range_of_output_char_range R, traits::adc_input_char_range CmdNameT>
R exec(CmdNameT&& cmd_name, ServerResponseType& rtype) R exec(CmdNameT&& cmd_name, ServerResponseType& rtype)
{ {
typename netservice_t::send_msg_t bytes;
AdcDeviceProtoMessage msg(bytes);
msg.cmd(std::forward<CmdNameT>(cmd_name));
using m_t = std::remove_cvref_t<decltype(msg)>;
// expected respond: ACK CMD CMD_NAME // expected respond: ACK CMD CMD_NAME
// return CMD_NAME ... (or error description 'code category what') // return CMD_NAME ... (or error description 'code category what')
return _getFromServer<R>(m_t::CMD_KEY, bytes, rtype); return deviceFuncHelper<R>(constants::ADC_DEVICE_NETPROTO_KEY_CMD, rtype, std::forward<CmdNameT>(cmd_name));
} }
template <traits::adc_input_char_range CmdNameT> template <traits::adc_input_char_range CmdNameT>
@ -218,15 +204,10 @@ public:
template <traits::adc_range_of_output_char_range R, traits::adc_input_char_range AttrNameT> template <traits::adc_range_of_output_char_range R, traits::adc_input_char_range AttrNameT>
R getAttr(AttrNameT&& attr_name, ServerResponseType& rtype) R getAttr(AttrNameT&& attr_name, ServerResponseType& rtype)
{ {
typename netservice_t::send_msg_t bytes;
AdcDeviceProtoMessage msg(bytes);
msg.get(std::forward<AttrNameT>(attr_name));
using m_t = std::remove_cvref_t<decltype(msg)>;
// expected respond: ACK GET ATTR_NAME ATTR_VALUE // expected respond: ACK GET ATTR_NAME ATTR_VALUE
// return ATTR_NAME ATTR_VALUE (or error description 'code category what') // return ATTR_NAME ATTR_VALUE (or error description 'code category what')
return _getFromServer<R>(m_t::GET_KEY, bytes, rtype); return deviceFuncHelper<R>(constants::ADC_DEVICE_NETPROTO_KEY_GET, rtype,
std::forward<AttrNameT>(attr_name));
} }
template <traits::adc_input_char_range AttrNameT> template <traits::adc_input_char_range AttrNameT>
@ -243,15 +224,10 @@ public:
typename... ValueTs> typename... ValueTs>
R setAttr(AttrNameT&& attr_name, ServerResponseType& rtype, ValueT&& value, ValueTs&&... values) R setAttr(AttrNameT&& attr_name, ServerResponseType& rtype, ValueT&& value, ValueTs&&... values)
{ {
typename netservice_t::send_msg_t bytes;
AdcDeviceProtoMessage msg(bytes);
msg.set(std::forward<AttrNameT>(attr_name), std::forward<ValueT>(value), std::forward<ValueTs>(values)...);
using m_t = std::remove_cvref_t<decltype(msg)>;
// expected respond: ACK SET ATTR_NAME ATTR_VALUE // expected respond: ACK SET ATTR_NAME ATTR_VALUE
// return ATTR_NAME ATTR_VALUE (or error description 'code category what') // return ATTR_NAME ATTR_VALUE (or error description 'code category what')
return _getFromServer<R>(m_t::SET_KEY, bytes, rtype); return deviceFuncHelper<R>(constants::ADC_DEVICE_NETPROTO_KEY_SET, rtype, std::forward<ValueT>(value),
std::forward<ValueTs>(values)...);
} }
template <traits::adc_input_char_range AttrNameT, typename ValueT, typename... ValueTs> template <traits::adc_input_char_range AttrNameT, typename ValueT, typename... ValueTs>
@ -264,6 +240,23 @@ public:
std::forward<ValueT>(value), std::forward<ValueTs>(values)...); std::forward<ValueT>(value), std::forward<ValueTs>(values)...);
} }
// ADC device helper methods (asynchronous)
// get device names
template <std::convertible_to<async_callback_func_t> CallbackT>
auto asyncDeviceNames(CallbackT&& callback_func)
{
return asyncDeviceFuncHelper(constants::ADC_DEVICE_NETPROTO_KEY_NAMES,
std::forward<CallbackT>(callback_func));
}
template <traits::adc_input_char_range DevNameT, std::convertible_to<async_callback_func_t> CallbackT>
auto asyncBindDevice(DevNameT&& dev_name, CallbackT&& callback_func)
{
return asyncDeviceFuncHelper(constants::ADC_DEVICE_NETPROTO_KEY_DEVICE,
std::forward<CallbackT>(callback_func), std::forward<DevNameT>(dev_name));
}
protected: protected:
netsession_ident_t _ident; netsession_ident_t _ident;
@ -279,12 +272,10 @@ public:
// helper methods // helper methods
template <traits::adc_range_of_output_char_range R> template <traits::adc_range_of_output_char_range R>
R _getFromServer(std::string_view key, const typename netservice_t::send_msg_t& bytes, ServerResponseType& type) R checkServerRespond(std::string_view key, const auto& bytes, ServerResponseType& type) const
{ {
auto rbytes = sendRecv(bytes); AdcDeviceProtoMessage dev_msg(bytes);
AdcDeviceProtoMessage dev_msg(rbytes);
if (!dev_msg.isValid()) { if (!dev_msg.isValid()) {
throw std::system_error(AdcDeviceNetClientSessionError::ERROR_INVALID_SERVER_RESPOND); throw std::system_error(AdcDeviceNetClientSessionError::ERROR_INVALID_SERVER_RESPOND);
@ -301,32 +292,59 @@ public:
} }
} }
template <traits::adc_range_of_output_char_range R>
void _sendRecvCallbackWrapper(auto err, R getFromServer(std::string_view key, const typename netservice_t::send_msg_t& bytes, ServerResponseType& type)
typename netservice_t::recv_msg_t msg,
auto&& ack_func,
auto&& error_func)
{ {
auto rbytes = sendRecv(bytes);
return checkServerRespond<R>(key, rbytes, type);
}
template <traits::adc_range_of_output_char_range R, typename... ArgTs>
R deviceFuncHelper(std::string_view key, ServerResponseType& rtype, ArgTs&&... args)
{
typename netservice_t::send_msg_t bytes;
AdcDeviceProtoMessage msg(bytes);
msg.setKeyValue(key, std::forward<ArgTs>(args)...);
return getFromServer<R>(key, bytes, rtype);
}
template <std::convertible_to<async_callback_func_t> CallbackT, typename... ArgTs>
auto asyncDeviceFuncHelper(std::string_view key, CallbackT&& callback_func, ArgTs&&... args)
{
auto bytes = std::shared_ptr<typename netservice_t::send_msg_t>();
AdcDeviceProtoMessage msg(*bytes);
msg.setKeyValue(key, std::forward<ArgTs>(args)...);
asyncSendRecv(*bytes, [bytes, key, wrapper = traits::adc_pf_wrapper(std::forward<CallbackT>(callback_func)),
this](auto err, auto rmsg) mutable {
if (err) { if (err) {
_clientPtr->logError("An error occured while receiving server respond: {}", _clientPtr->logError("An error occured while receiving server respond: {}",
netservice_t::formattableError(err)); netservice_t::formattableError(err));
} else { } else {
AdcDeviceProtoMessage dev_msg(msg); try {
ServerResponseType type;
auto attrs = checkServerRespond<default_server_resp_t>(key, rmsg, type);
if (!dev_msg.isValid()) { std::forward<CallbackT>(std::get<0>(wrapper))(type, attrs);
_clientPtr->logError("Invalid server respond");
return; } catch (const std::system_error& err) {
_clientPtr->logError("An error occured while getting server respond: {}", err.what());
}
}
});
} }
if (dev_msg.isACK()) { template <traits::adc_input_char_range SendMsgT>
std::forward<decltype(ack_func)>(ack_func)(dev_msg.attrs()); auto sendRecv(const SendMsgT& send_msg)
} else if (dev_msg.isERROR()) { {
std::forward<decltype(error_func)>(error_func)(dev_msg.attrs()); _netService.send(send_msg, _sendTimeout);
} else { return _netService.receive(_recvTimeout);
_clientPtr->logError("Unexpectable server respond (msg key: {})", dev_msg.key());
} }
}
};
template <traits::adc_input_char_range SendMsgT, typename TokenT> template <traits::adc_input_char_range SendMsgT, typename TokenT>
auto asyncSendRecv(const SendMsgT& send_msg, TokenT&& token) auto asyncSendRecv(const SendMsgT& send_msg, TokenT&& token)
@ -344,13 +362,6 @@ public:
_sendTimeout); _sendTimeout);
} }
template <traits::adc_input_char_range SendMsgT>
auto sendRecv(const SendMsgT& send_msg)
{
_netService.send(send_msg, _sendTimeout);
return _netService.receive(_recvTimeout);
}
}; // end of 'Session' class declaration }; // end of 'Session' class declaration
using base_t::base_t; using base_t::base_t;

View File

@ -291,6 +291,27 @@ protected:
}; };
/* ADC client-server network protocol definitions */
namespace constants
{
static constexpr std::string_view ADC_DEVICE_NETPROTO_KEY_ACK{"ACK"};
static constexpr std::string_view ADC_DEVICE_NETPROTO_KEY_SET{"SET"};
static constexpr std::string_view ADC_DEVICE_NETPROTO_KEY_GET{"GET"};
static constexpr std::string_view ADC_DEVICE_NETPROTO_KEY_CMD{"CMD"};
static constexpr std::string_view ADC_DEVICE_NETPROTO_KEY_ERR{"ERR"};
static constexpr std::string_view ADC_DEVICE_NETPROTO_KEY_HELLO{"HELLO"};
static constexpr std::string_view ADC_DEVICE_NETPROTO_KEY_DEVICE{"DEVICE"};
static constexpr std::string_view ADC_DEVICE_NETPROTO_KEY_NAMES{"NAMES"};
static constexpr std::array ADC_DEVICE_NETPROTO_VALID_KEY{
ADC_DEVICE_NETPROTO_KEY_ACK, ADC_DEVICE_NETPROTO_KEY_SET, ADC_DEVICE_NETPROTO_KEY_GET,
ADC_DEVICE_NETPROTO_KEY_CMD, ADC_DEVICE_NETPROTO_KEY_ERR, ADC_DEVICE_NETPROTO_KEY_HELLO,
ADC_DEVICE_NETPROTO_KEY_DEVICE, ADC_DEVICE_NETPROTO_KEY_NAMES};
} // namespace constants
template <traits::adc_char_range ByteSeqT, template <traits::adc_char_range ByteSeqT,
const char KEY_VALUE_DELIM[] = constants::ADC_DEFAULT_KEY_VALUE_DELIMITER1, const char KEY_VALUE_DELIM[] = constants::ADC_DEFAULT_KEY_VALUE_DELIMITER1,
const char VALUE_DELIM[] = constants::ADC_DEFAULT_VALUE_DELIMITER, const char VALUE_DELIM[] = constants::ADC_DEFAULT_VALUE_DELIMITER,
@ -301,20 +322,7 @@ class AdcDeviceProtoMessage
using base_t = AdcKeyValueMessage<ByteSeqT, KEY_VALUE_DELIM, VALUE_DELIM, COMPOSITE_VALUE_DELIM>; using base_t = AdcKeyValueMessage<ByteSeqT, KEY_VALUE_DELIM, VALUE_DELIM, COMPOSITE_VALUE_DELIM>;
public: public:
static constexpr std::string_view ACK_KEY{"ACK"}; typedef std::array<size_t, constants::ADC_DEVICE_NETPROTO_VALID_KEY.size()> keyword_hash_array_t;
static constexpr std::string_view SET_KEY{"SET"};
static constexpr std::string_view GET_KEY{"GET"};
static constexpr std::string_view CMD_KEY{"CMD"};
static constexpr std::string_view ERR_KEY{"ERR"};
static constexpr std::string_view HELLO_KEY{"HELLO"};
static constexpr std::string_view DEVICE_KEY{"DEVICE"};
static constexpr std::string_view NAMES_KEY{"NAMES"};
static constexpr std::array VALID_KEY{ACK_KEY, SET_KEY, GET_KEY, CMD_KEY,
ERR_KEY, HELLO_KEY, DEVICE_KEY, NAMES_KEY};
typedef std::array<size_t, VALID_KEY.size()> keyword_hash_array_t;
enum KEY_IDX : size_t { enum KEY_IDX : size_t {
ACK_KEY_IDX, ACK_KEY_IDX,
@ -324,7 +332,8 @@ public:
ERR_KEY_IDX, ERR_KEY_IDX,
HELLO_KEY_IDX, HELLO_KEY_IDX,
DEVICE_KEY_IDX, DEVICE_KEY_IDX,
NAMES_KEY_IDX NAMES_KEY_IDX,
INVALID_KEY_IDX
}; };
private: // include here to allow clang compilation private: // include here to allow clang compilation
@ -333,9 +342,9 @@ private: // include here to allow clang compilation
template <size_t... I> template <size_t... I>
static constexpr auto computeKeywordHashesImpl(std::index_sequence<I...>) static constexpr auto computeKeywordHashesImpl(std::index_sequence<I...>)
{ {
return keyword_hash_array_t{utils::AdcFNV1aHash(VALID_KEY[I])...}; return keyword_hash_array_t{utils::AdcFNV1aHash(constants::ADC_DEVICE_NETPROTO_VALID_KEY[I])...};
} }
template <typename Indices = std::make_index_sequence<VALID_KEY.size()>> template <typename Indices = std::make_index_sequence<constants::ADC_DEVICE_NETPROTO_VALID_KEY.size()>>
static constexpr auto computeKeywordHashes() static constexpr auto computeKeywordHashes()
{ {
return computeKeywordHashesImpl(Indices{}); return computeKeywordHashesImpl(Indices{});
@ -350,6 +359,9 @@ private: // include here to allow clang compilation
bool isKey(size_t idx) const bool isKey(size_t idx) const
{ {
if (idx >= INVALID_KEY_IDX)
return false;
return _keyHash == KEY_HASHES[idx]; return _keyHash == KEY_HASHES[idx];
} }
@ -452,9 +464,11 @@ public:
} }
using base_t::setKeyValue; // import to public area
void ack() void ack()
{ {
base_t::setKey(ACK_KEY); base_t::setKey(constants::ADC_DEVICE_NETPROTO_KEY_ACK);
keyHash(); keyHash();
} }
@ -463,7 +477,7 @@ public:
template <typename ParT, typename... ParTs> template <typename ParT, typename... ParTs>
void ack(const ParT& param, const ParTs&... params) void ack(const ParT& param, const ParTs&... params)
{ {
base_t::setKeyValue(ACK_KEY, param, params...); base_t::setKeyValue(constants::ADC_DEVICE_NETPROTO_KEY_ACK, param, params...);
keyHash(); keyHash();
} }
@ -474,7 +488,7 @@ public:
requires(!traits::adc_input_char_range<ParT>) requires(!traits::adc_input_char_range<ParT>)
void ack(const ParT& param) void ack(const ParT& param)
{ {
base_t::setKeyValue(ACK_KEY, param); base_t::setKeyValue(constants::ADC_DEVICE_NETPROTO_KEY_ACK, param);
keyHash(); keyHash();
} }
@ -483,7 +497,7 @@ public:
template <traits::adc_tuple_like ParT> template <traits::adc_tuple_like ParT>
void ack(const ParT& param) void ack(const ParT& param)
{ {
base_t::setKeyValue(ACK_KEY, param); base_t::setKeyValue(constants::ADC_DEVICE_NETPROTO_KEY_ACK, param);
keyHash(); keyHash();
} }
@ -492,8 +506,8 @@ public:
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)
{ {
base_t::setKeyValue(SET_KEY, std::forward<AttrNameT>(attr_name), std::forward<ValueT>(value), base_t::setKeyValue(constants::ADC_DEVICE_NETPROTO_KEY_SET, std::forward<AttrNameT>(attr_name),
std::forward<ValueTs>(values)...); std::forward<ValueT>(value), std::forward<ValueTs>(values)...);
keyHash(); keyHash();
} }
@ -501,7 +515,7 @@ public:
template <traits::adc_input_char_range AttrNameT> template <traits::adc_input_char_range AttrNameT>
void get(AttrNameT&& attr_name) void get(AttrNameT&& attr_name)
{ {
base_t::setKeyValue(GET_KEY, std::forward<AttrNameT>(attr_name)); base_t::setKeyValue(constants::ADC_DEVICE_NETPROTO_KEY_GET, std::forward<AttrNameT>(attr_name));
keyHash(); keyHash();
} }
@ -509,14 +523,14 @@ public:
template <traits::adc_input_char_range CmdNameT> template <traits::adc_input_char_range CmdNameT>
void cmd(CmdNameT&& cmd_name) void cmd(CmdNameT&& cmd_name)
{ {
base_t::setKeyValue(CMD_KEY, std::forward<CmdNameT>(cmd_name)); base_t::setKeyValue(constants::ADC_DEVICE_NETPROTO_KEY_CMD, std::forward<CmdNameT>(cmd_name));
keyHash(); keyHash();
} }
void err(const std::error_code& ec) void err(const std::error_code& ec)
{ {
base_t::setKeyValue(ERR_KEY, ec.value(), ec.category().name(), ec.message()); base_t::setKeyValue(constants::ADC_DEVICE_NETPROTO_KEY_ERR, ec.value(), ec.category().name(), ec.message());
keyHash(); keyHash();
} }
@ -524,7 +538,8 @@ public:
template <traits::adc_input_char_range SenderNameT, typename... ParamTs> template <traits::adc_input_char_range SenderNameT, typename... ParamTs>
void hello(SenderNameT&& name, ParamTs&&... params) void hello(SenderNameT&& name, ParamTs&&... params)
{ {
base_t::setKeyValue(HELLO_KEY, std::forward<SenderNameT>(name), std::forward<ParamTs>(params)...); base_t::setKeyValue(constants::ADC_DEVICE_NETPROTO_KEY_HELLO, std::forward<SenderNameT>(name),
std::forward<ParamTs>(params)...);
keyHash(); keyHash();
} }
@ -532,14 +547,14 @@ public:
template <traits::adc_input_char_range DevNameT> template <traits::adc_input_char_range DevNameT>
void device(DevNameT&& dev_name) void device(DevNameT&& dev_name)
{ {
base_t::setKeyValue(DEVICE_KEY, std::forward<DevNameT>(dev_name)); base_t::setKeyValue(constants::ADC_DEVICE_NETPROTO_KEY_DEVICE, std::forward<DevNameT>(dev_name));
keyHash(); keyHash();
} }
void names() void names()
{ {
base_t::setKey(NAMES_KEY); base_t::setKey(constants::ADC_DEVICE_NETPROTO_KEY_NAMES);
keyHash(); keyHash();
} }
@ -547,7 +562,7 @@ public:
template <typename DevNameT, typename... DevNameTs> template <typename DevNameT, typename... DevNameTs>
void names(const DevNameT& dev_name, const DevNameTs&... dev_names) void names(const DevNameT& dev_name, const DevNameTs&... dev_names)
{ {
base_t::setKeyValue(NAMES_KEY, dev_name, dev_names...); base_t::setKeyValue(constants::ADC_DEVICE_NETPROTO_KEY_NAMES, dev_name, dev_names...);
keyHash(); keyHash();
} }
@ -556,7 +571,7 @@ public:
requires(!traits::adc_input_char_range<std::ranges::range_value_t<R>>) requires(!traits::adc_input_char_range<std::ranges::range_value_t<R>>)
void names(const R& dev_names) void names(const R& dev_names)
{ {
base_t::setKeyValue(NAMES_KEY, dev_names); base_t::setKeyValue(constants::ADC_DEVICE_NETPROTO_KEY_NAMES, dev_names);
keyHash(); keyHash();
} }
@ -564,7 +579,7 @@ public:
template <traits::adc_tuple_like T> template <traits::adc_tuple_like T>
void names(const T& dev_names) void names(const T& dev_names)
{ {
base_t::setKeyValue(NAMES_KEY, dev_names); base_t::setKeyValue(constants::ADC_DEVICE_NETPROTO_KEY_NAMES, dev_names);
keyHash(); keyHash();
} }