10#ifndef NROS_CPP_CLIENT_HPP
11#define NROS_CPP_CLIENT_HPP
18#include "nros/size_bound.hpp"
21#include "nros_cpp_ffi.h"
32 const char* service_name,
const char* type_name,
35 void* context, uint8_t sched_context,
36 size_t* out_handle_id);
76 return send_request_sized<::nros::rx_buffer_capacity<ResponseType>::value>(req);
88 template <
size_t RespCap>
91 if (!initialized_)
return Fut();
93 uint8_t req_buf[::nros::detail::buffer_bounds<RequestType>::tx];
95 if (RequestType::ffi_serialize(&req, req_buf,
sizeof(req_buf), &req_len) != 0) {
99 nros_cpp_ret_t ret = nros_cpp_service_client_send_request(storage_, req_buf, req_len);
100 if (ret != 0)
return Fut();
102 return Fut(storage_, &nros_cpp_service_client_take_response,
117 return call_sized<::nros::rx_buffer_capacity<ResponseType>::value>(req, resp, timeout_ms);
121 template <
size_t RespCap>
124 auto fut = send_request_sized<RespCap>(req);
125 return fut.wait(executor_, timeout_ms, resp);
147 return call_polling_sized<::nros::rx_buffer_capacity<ResponseType>::value>(req, resp,
154 template <
size_t RespCap>
156 uint32_t timeout_ms = 100) {
158 uint8_t req_buf[::nros::detail::buffer_bounds<RequestType>::tx];
160 if (RequestType::ffi_serialize(&req, req_buf,
sizeof(req_buf), &req_len) != 0) {
163 uint8_t resp_buf[RespCap];
166 storage_, req_buf, req_len, resp_buf,
sizeof(resp_buf), &resp_len, timeout_ms);
167 if (ret != 0)
return Result(ret);
169 if (ResponseType::ffi_deserialize(resp_buf, resp_len, &resp) != 0) {
196 nros_cpp_service_client_server_available(
const_cast<uint8_t*
>(storage_), &out);
209 [[deprecated(
"Client::server_available is deprecated; use "
210 "Client::service_is_ready, which returns Expected<bool>")]]
int
213 if (!r.ok())
return -1;
214 return r.value() ? 1 : 0;
233 return Result(nros_cpp_service_client_wait_for_service(storage_, executor_, timeout_ms));
242 uint8_t req_buf[::nros::detail::buffer_bounds<RequestType>::tx];
244 if (RequestType::ffi_serialize(&req, req_buf,
sizeof(req_buf), &req_len) != 0) {
248 nros_cpp_service_client_send_on_handle(executor_, handle_id_, req_buf, req_len));
261 if (initialized_ && !callback_mode_) {
262 nros_cpp_service_client_destroy(storage_);
264 initialized_ =
false;
272 : executor_(other.executor_), initialized_(other.initialized_), user_fn_(other.user_fn_),
273 user_fn_ctx_(other.user_fn_ctx_), user_ctx_(other.user_ctx_),
274 handle_id_(other.handle_id_), callback_mode_(other.callback_mode_) {
275 if (other.initialized_ && !other.callback_mode_) {
276 nros_cpp_service_client_relocate(other.storage_, storage_);
278 other.initialized_ =
false;
282 if (
this != &other) {
283 if (initialized_ && !callback_mode_) {
284 nros_cpp_service_client_destroy(storage_);
286 executor_ = other.executor_;
287 initialized_ = other.initialized_;
288 user_fn_ = other.user_fn_;
289 user_fn_ctx_ = other.user_fn_ctx_;
290 user_ctx_ = other.user_ctx_;
291 handle_id_ = other.handle_id_;
292 callback_mode_ = other.callback_mode_;
293 if (other.initialized_ && !other.callback_mode_) {
294 nros_cpp_service_client_relocate(other.storage_, storage_);
296 other.initialized_ =
false;
303 Client() : storage_(), executor_(nullptr), initialized_(false) {}
314 static void response_trampoline(
const uint8_t* data,
size_t len,
void* ctx) {
315 auto* self =
static_cast<Client*
>(ctx);
316 if (self ==
nullptr)
return;
318 if (ResponseType::ffi_deserialize(data, len, &response) != 0)
return;
319 if (self->user_fn_ !=
nullptr) {
320 self->user_fn_(response);
321 }
else if (self->user_fn_ctx_ !=
nullptr) {
322 self->user_fn_ctx_(response, self->user_ctx_);
326 alignas(8) uint8_t storage_[NROS_SERVICE_CLIENT_SIZE];
332 void* user_ctx_ =
nullptr;
333 size_t handle_id_ =
static_cast<size_t>(-1);
334 bool callback_mode_ =
false;
349 &handle_, service_name, S::TYPE_NAME, S::Request::TYPE_HASH, ffi_qos, out.storage_);
351 out.executor_ = executor_handle_;
352 out.initialized_ =
true;
360template <
typename S,
typename F,
typename>
362 const ClientOptions& options) {
367 out.user_fn_ctx_ =
nullptr;
368 out.user_ctx_ =
nullptr;
370 uint8_t sched = (options.sched_context == SCHED_CONTEXT_UNSET)
372 :
static_cast<uint8_t
>(options.sched_context);
373 size_t handle =
static_cast<size_t>(-1);
375 &handle_, service_name, S::TYPE_NAME, S::Request::TYPE_HASH, ffi_qos,
377 &out, sched, &handle);
379 out.executor_ = executor_handle_;
380 out.handle_id_ = handle;
381 out.callback_mode_ =
true;
382 out.initialized_ =
true;
typename S::Response ResponseType
Definition client.hpp:58
Result async_send_request(const RequestType &req)
Definition client.hpp:240
Client()
Definition client.hpp:303
void(*)(const ResponseType &response, void *ctx) TypedResponseFnWithCtx
Definition client.hpp:65
Client & operator=(Client &&other)
Definition client.hpp:281
int server_available() const
Definition client.hpp:211
Result call_sized(const RequestType &req, ResponseType &resp, uint32_t timeout_ms=5000)
call with the REPLY buffer sized by the caller (issue 0964).
Definition client.hpp:122
size_t handle_id() const
Definition client.hpp:253
Result call_polling_sized(const RequestType &req, ResponseType &resp, uint32_t timeout_ms=100)
Definition client.hpp:155
typename S::Request RequestType
Definition client.hpp:57
~Client()
Definition client.hpp:260
Expected< bool > service_is_ready() const
Definition client.hpp:192
Future< ResponseType, RespCap > send_request_sized(const RequestType &req)
Definition client.hpp:89
Client(Client &&other)
Definition client.hpp:271
bool is_valid() const
Check if the client is initialized and valid.
Definition client.hpp:176
void(*)(const ResponseType &response) TypedResponseFn
Definition client.hpp:64
Future< ResponseType > send_request(const RequestType &req)
Definition client.hpp:75
Result call(const RequestType &req, ResponseType &resp, uint32_t timeout_ms=5000)
Definition client.hpp:116
Result call_polling(const RequestType &req, ResponseType &resp, uint32_t timeout_ms=100)
Definition client.hpp:146
Result wait_for_service(uint32_t timeout_ms=5000)
Definition client.hpp:231
Definition result.hpp:198
ErrorCode error() const
Definition result.hpp:221
bool ok() const
Definition result.hpp:214
Result create_client(Client< S > &out, const char *service_name, const QoS &qos=QoS::services())
Definition client.hpp:345
static constexpr Result success()
Named constructors.
Definition result.hpp:112
nros_cpp_ret_t nros_cpp_service_client_register(const nros_cpp_node_t *node, const char *service_name, const char *type_name, const char *type_hash, nros_cpp_qos_t qos, nros_cpp_service_response_callback_t callback, void *context, uint8_t sched_context, size_t *out_handle_id)
void(* nros_cpp_service_response_callback_t)(const uint8_t *data, size_t len, void *ctx)
Definition client.hpp:29
Inline storage-size macros for opaque entity buffers.
nros::Future<T> — single-shot deferred result.
int nros_cpp_ret_t
Definition future.hpp:21
ErrorCode
Definition result.hpp:30
@ Error
Generic failure not covered by a more specific code.
@ Unsupported
Operation not implemented by the active backend.
@ Timeout
Operation deadline elapsed before completion.
nros::Node and global session helpers.
nros::Result, nros::ErrorCode, and the NROS_TRY macro.