17 #include "rclcpp/generic_client.hpp"
18 #include "rclcpp/typesupport_helpers.hpp"
20 #include "rosidl_runtime_c/service_type_support_struct.h"
21 #include "rosidl_typesupport_introspection_cpp/identifier.hpp"
22 #include "rosidl_typesupport_introspection_cpp/service_introspection.hpp"
26 GenericClient::GenericClient(
28 const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr & node_graph,
29 const std::string & service_name,
30 const std::string & service_type,
32 : ClientBase(node_base, node_graph)
34 const rosidl_service_type_support_t * service_ts;
37 service_type,
"rosidl_typesupport_cpp");
40 service_type,
"rosidl_typesupport_cpp", *ts_lib_);
43 service_ts->response_typesupport,
44 rosidl_typesupport_introspection_cpp::typesupport_identifier);
45 response_members_ =
static_cast<const rosidl_typesupport_introspection_cpp::MessageMembers *
>(
46 response_type_support_intro->data);
47 }
catch (std::runtime_error & err) {
50 "Invalid service type: %s",
56 this->get_client_handle().get(),
57 this->get_rcl_node_handle(),
63 auto rcl_node_handle = this->get_rcl_node_handle();
72 rclcpp::exceptions::throw_from_rcl_error(ret,
"could not create generic client");
77 GenericClient::create_response()
79 void * response =
new uint8_t[response_members_->size_of_];
80 response_members_->init_function(response, rosidl_runtime_cpp::MessageInitialization::ZERO);
81 return std::shared_ptr<void>(
85 response_members_->fini_function(p);
86 delete[]
reinterpret_cast<uint8_t *
>(p);
90 std::shared_ptr<rmw_request_id_t>
91 GenericClient::create_request_header()
93 return std::shared_ptr<rmw_request_id_t>(
new rmw_request_id_t);
97 GenericClient::handle_response(
98 const std::shared_ptr<rmw_request_id_t> & request_header,
99 const std::shared_ptr<void> & response)
101 auto optional_pending_request =
102 this->get_and_erase_pending_request(request_header->sequence_number);
103 if (!optional_pending_request) {
106 auto & value = *optional_pending_request;
107 if (std::holds_alternative<Promise>(value)) {
108 auto & promise = std::get<Promise>(value);
109 promise.set_value(response);
110 }
else if (std::holds_alternative<CallbackTypeValueVariant>(value)) {
111 auto & inner = std::get<CallbackTypeValueVariant>(value);
112 const auto & callback = std::get<CallbackType>(inner);
113 auto & promise = std::get<Promise>(inner);
114 auto & future = std::get<SharedFuture>(inner);
115 promise.set_value(response);
116 callback(std::move(future));
121 GenericClient::prune_pending_requests()
123 std::lock_guard guard(pending_requests_mutex_);
124 auto ret = pending_requests_.size();
125 pending_requests_.clear();
130 GenericClient::remove_pending_request(int64_t request_id)
132 std::lock_guard guard(pending_requests_mutex_);
133 return pending_requests_.erase(request_id) != 0u;
139 return this->remove_pending_request(future.request_id);
145 return this->remove_pending_request(future.request_id);
148 std::optional<GenericClient::CallbackInfoVariant>
149 GenericClient::get_and_erase_pending_request(int64_t request_number)
151 std::unique_lock<std::mutex> lock(pending_requests_mutex_);
152 auto it = pending_requests_.find(request_number);
153 if (it == pending_requests_.end()) {
154 RCUTILS_LOG_DEBUG_NAMED(
156 "Received invalid sequence number. Ignoring...");
159 auto value = std::move(it->second.second);
160 pending_requests_.erase(request_number);
164 GenericClient::FutureAndRequestId
165 GenericClient::async_send_request(
const Request & request)
168 auto future = promise.get_future();
169 auto req_id = async_send_request_impl(
176 GenericClient::async_send_request_impl(
const Request & request, CallbackInfoVariant value)
178 int64_t sequence_number;
179 std::lock_guard<std::mutex> lock(pending_requests_mutex_);
182 rclcpp::exceptions::throw_from_rcl_error(ret,
"failed to send request");
184 pending_requests_.try_emplace(
186 std::make_pair(std::chrono::system_clock::now(), std::move(value)));
187 return sequence_number;
RCLCPP_PUBLIC Logger get_child(const std::string &suffix)
Return a logger that is a descendant of this logger.
Pure virtual interface class for the NodeBase part of the Node API.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_client_init(rcl_client_t *client, const rcl_node_t *node, const rosidl_service_type_support_t *type_support, const char *service_name, const rcl_client_options_t *options)
Initialize a rcl client.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_send_request(const rcl_client_t *client, const void *ros_request, int64_t *sequence_number)
Send a ROS request using a client.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCLCPP_PUBLIC std::string expand_topic_or_service_name(const std::string &name, const std::string &node_name, const std::string &namespace_, bool is_service=false)
Expand a topic or service name and throw if it is not valid.
RCLCPP_PUBLIC Logger get_node_logger(const rcl_node_t *node)
Return a named logger using an rcl_node_t.
RCLCPP_PUBLIC std::shared_ptr< rcpputils::SharedLibrary > get_typesupport_library(const std::string &type, const std::string &typesupport_identifier)
Load the type support library for the given type.
RCLCPP_PUBLIC const rosidl_message_type_support_t * get_message_typesupport_handle(const std::string &type, const std::string &typesupport_identifier, rcpputils::SharedLibrary &library)
Extracts the message type support handle from the library.
RCLCPP_PUBLIC const rosidl_service_type_support_t * get_service_typesupport_handle(const std::string &type, const std::string &typesupport_identifier, rcpputils::SharedLibrary &library)
Extracts the service type support handle from the library.
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_name(const rcl_node_t *node)
Return the name of the node.
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_namespace(const rcl_node_t *node)
Return the namespace of the node.
Options available for a rcl_client_t.
A convenient GenericClient::Future and request id pair.
A convenient GenericClient::SharedFuture and request id pair.
#define RCL_RET_SERVICE_NAME_INVALID
Service name (same as topic name) does not pass validation.
#define RCL_RET_OK
Success return code.
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.