open62541pp 0.16.0
C++ wrapper of open62541
Loading...
Searching...
No Matches
client_service.hpp
Go to the documentation of this file.
1#pragma once
2
3#include <cassert>
4#include <functional> // invoke
5#include <memory>
6#include <type_traits>
7#include <utility> // forward
8
14#include "open62541pp/typeregistry.hpp" // getDataType
15
17
18/**
19 * Adapter to initiate open62541 async client operations with completion tokens.
20 */
21template <typename Response>
24
25 template <typename Context>
30
31 template <typename CompletionHandler>
33 ExceptionCatcher& exceptionCatcher, CompletionHandler&& handler
34 ) {
35 static_assert(std::is_invocable_v<CompletionHandler, Response&>);
36
37 struct Context {
38 ExceptionCatcher* catcher;
39 std::decay_t<CompletionHandler> handler;
40 };
41
42 const auto callback =
43 [](UA_Client*, void* userdata, uint32_t /* reqId */, void* responsePtr) {
44 std::unique_ptr<Context> context{static_cast<Context*>(userdata)};
45 assert(context != nullptr);
46 assert(context->catcher != nullptr);
47 context->catcher->invoke([context = context.get(), responsePtr] {
48 if (responsePtr == nullptr) {
49 throw BadStatus(UA_STATUSCODE_BADUNEXPECTEDERROR);
50 }
51 std::invoke(context->handler, *static_cast<Response*>(responsePtr));
52 });
53 };
54
55 return CallbackAndContext<Context>{
56 callback,
57 std::make_unique<Context>(
58 Context{&exceptionCatcher, std::forward<CompletionHandler>(handler)}
59 )
60 };
61 }
62
63 /**
64 * Initiate open62541 async client operation with user-defined completion token.
65 * @param client Instance of type Client
66 * @param initiation Callable to initiate the async operation. Following signature is expected:
67 * `void(UA_ClientAsyncServiceCallback callback, void* userdata)`
68 * @param token Completion token
69 */
70 template <typename Initiation, typename CompletionToken>
71 static auto initiate(Client& client, Initiation&& initiation, CompletionToken&& token) {
72 static_assert(std::is_invocable_v<Initiation, UA_ClientAsyncServiceCallback, void*>);
73
75 [&](auto&& handler) {
76 auto& catcher = opcua::detail::getExceptionCatcher(client);
77 try {
78 // NOLINTNEXTLINE(clang-analyzer-cplusplus.NewDeleteLeaks), false positive?
79 auto callbackAndContext = createCallbackAndContext(
80 catcher, std::forward<decltype(handler)>(handler)
81 );
82 std::invoke(
83 std::forward<Initiation>(initiation),
84 callbackAndContext.callback,
85 callbackAndContext.context.get()
86 );
87 // initiation call might raise an exception
88 // transfer ownership to the callback afterwards
89 callbackAndContext.context.release();
90 } catch (...) {
91 catcher.setException(std::current_exception());
92 }
93 },
94 std::forward<CompletionToken>(token)
95 );
96 }
97};
98
99/// Async client service requests.
100template <typename Request, typename Response, typename CompletionToken>
101auto sendRequestAsync(Client& client, const Request& request, CompletionToken&& token) {
103 client,
104 [&](UA_ClientAsyncServiceCallback callback, void* userdata) {
107 &request,
108 &getDataType<Request>(),
109 callback,
110 &getDataType<Response>(),
111 userdata,
112 nullptr
113 ));
114 },
115 std::forward<CompletionToken>(token)
116 );
117}
118
119/// Sync client service requests.
120template <typename Request, typename Response>
121Response sendRequest(Client& client, const Request& request) noexcept {
122 Response response{};
125 &request,
126 &getDataType<Request>(),
127 &response,
128 &getDataType<Response>()
129 );
130 return response;
131}
132
133} // namespace opcua::services::detail
High-level client class.
Definition client.hpp:121
Catch & store exceptions from user-defined callbacks in an exception-unaware context (open62541).
void(* UA_ClientAsyncServiceCallback)(UA_Client *client, void *userdata, UA_UInt32 requestId, void *response)
void __UA_Client_Service(UA_Client *client, const void *request, const UA_DataType *requestType, void *response, const UA_DataType *responseType)
UA_StatusCode __UA_Client_AsyncService(UA_Client *client, const void *request, const UA_DataType *requestType, UA_ClientAsyncServiceCallback callback, const UA_DataType *responseType, void *userdata, UA_UInt32 *requestId)
auto asyncInitiate(Initiation &&initiation, CompletionToken &&token, Args &&... args)
Definition async.hpp:40
UA_Client * getHandle(Client &client) noexcept
ExceptionCatcher * getExceptionCatcher(UA_Client *client) noexcept
Response sendRequest(Client &client, const Request &request) noexcept
Sync client service requests.
auto sendRequestAsync(Client &client, const Request &request, CompletionToken &&token)
Async client service requests.
constexpr void throwIfBad(UA_StatusCode code)
Check the status code and throw a BadStatus exception if the status code is bad.
Definition exception.hpp:87
Adapter to initiate open62541 async client operations with completion tokens.
static auto createCallbackAndContext(ExceptionCatcher &exceptionCatcher, CompletionHandler &&handler)
static auto initiate(Client &client, Initiation &&initiation, CompletionToken &&token)
Initiate open62541 async client operation with user-defined completion token.