ROS 2 rclcpp + rcl - kilted  kilted
ROS 2 C++ Client Library with ROS Client Library
generic_client.hpp
1 // Copyright 2023 Sony Group Corporation.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef RCLCPP__GENERIC_CLIENT_HPP_
16 #define RCLCPP__GENERIC_CLIENT_HPP_
17 
18 #include <map>
19 #include <memory>
20 #include <future>
21 #include <string>
22 #include <tuple>
23 #include <vector>
24 #include <utility>
25 
26 #include "rcl/client.h"
27 
28 #include "rclcpp/client.hpp"
29 #include "rclcpp/visibility_control.hpp"
30 #include "rcpputils/shared_library.hpp"
31 
32 #include "rosidl_typesupport_introspection_cpp/message_introspection.hpp"
33 
34 namespace rclcpp
35 {
36 class GenericClient : public ClientBase
37 {
38 public:
39  using Request = void *; // Deserialized data pointer of request message
40  using Response = void *; // Deserialized data pointer of response message
41 
42  using SharedResponse = std::shared_ptr<void>;
43 
44  using Promise = std::promise<SharedResponse>;
45  using SharedPromise = std::shared_ptr<Promise>;
46 
47  using Future = std::future<SharedResponse>;
48  using SharedFuture = std::shared_future<SharedResponse>;
49 
50  using CallbackType = std::function<void (SharedFuture)>;
51 
52  RCLCPP_SMART_PTR_DEFINITIONS(GenericClient)
53 
54 
63  : detail::FutureAndRequestId<Future>
64  {
66 
68  SharedFuture share() noexcept {return this->future.share();}
69 
71  FutureAndRequestId(FutureAndRequestId && other) noexcept = default;
73  FutureAndRequestId(const FutureAndRequestId & other) = delete;
75  FutureAndRequestId & operator=(FutureAndRequestId && other) noexcept = default;
77  FutureAndRequestId & operator=(const FutureAndRequestId & other) = delete;
79  ~FutureAndRequestId() = default;
80  };
81 
83 
91  : detail::FutureAndRequestId<std::shared_future<SharedResponse>>
92  {
94  };
95 
98  rclcpp::node_interfaces::NodeGraphInterface::SharedPtr node_graph,
99  const std::string & service_name,
100  const std::string & service_type,
101  rcl_client_options_t & client_options);
102 
103  RCLCPP_PUBLIC
104  SharedResponse
105  create_response() override;
106 
107  RCLCPP_PUBLIC
108  std::shared_ptr<rmw_request_id_t>
109  create_request_header() override;
110 
111  RCLCPP_PUBLIC
112  void
113  handle_response(
114  std::shared_ptr<rmw_request_id_t> request_header,
115  std::shared_ptr<void> response) override;
116 
118 
145  RCLCPP_PUBLIC
147  async_send_request(const Request request);
148 
150 
165  template<
166  typename CallbackT,
167  typename std::enable_if<
169  CallbackT,
170  CallbackType
171  >::value
172  >::type * = nullptr
173  >
175  async_send_request(const Request request, CallbackT && cb)
176  {
177  Promise promise;
178  auto shared_future = promise.get_future().share();
179  auto req_id = async_send_request_impl(
180  request,
181  std::make_tuple(
182  CallbackType{std::forward<CallbackT>(cb)},
183  shared_future,
184  std::move(promise)));
185  return SharedFutureAndRequestId{std::move(shared_future), req_id};
186  }
187 
189 
195  template<typename AllocatorT = std::allocator<int64_t>>
196  size_t
198  std::chrono::time_point<std::chrono::system_clock> time_point,
199  std::vector<int64_t, AllocatorT> * pruned_requests = nullptr)
200  {
201  return detail::prune_requests_older_than_impl(
202  pending_requests_,
203  pending_requests_mutex_,
204  time_point,
205  pruned_requests);
206  }
207 
209 
212  RCLCPP_PUBLIC
213  size_t
215 
217 
227  RCLCPP_PUBLIC
228  bool
230  int64_t request_id);
231 
233 
238  RCLCPP_PUBLIC
239  bool
241  const FutureAndRequestId & future);
242 
244 
249  RCLCPP_PUBLIC
250  bool
252  const SharedFutureAndRequestId & future);
253 
255 
267  RCLCPP_PUBLIC
268  bool
269  take_response(Response response_out, rmw_request_id_t & request_header_out)
270  {
271  return this->take_type_erased_response(response_out, request_header_out);
272  }
273 
274 protected:
275  using CallbackTypeValueVariant = std::tuple<CallbackType, SharedFuture, Promise>;
276  using CallbackInfoVariant = std::variant<
277  std::promise<SharedResponse>,
278  CallbackTypeValueVariant>; // Use variant for extension
279 
280  RCLCPP_PUBLIC
281  int64_t
282  async_send_request_impl(
283  const Request request,
284  CallbackInfoVariant value);
285 
286  std::optional<CallbackInfoVariant>
287  get_and_erase_pending_request(
288  int64_t request_number);
289 
290  RCLCPP_DISABLE_COPY(GenericClient)
291 
292  std::map<int64_t, std::pair<
293  std::chrono::time_point<std::chrono::system_clock>,
294  CallbackInfoVariant>> pending_requests_;
295  std::mutex pending_requests_mutex_;
296 
297 private:
298  std::shared_ptr<rcpputils::SharedLibrary> ts_lib_;
299  const rosidl_typesupport_introspection_cpp::MessageMembers * response_members_;
300 };
301 } // namespace rclcpp
302 
303 #endif // RCLCPP__GENERIC_CLIENT_HPP_
RCLCPP_PUBLIC bool take_type_erased_response(void *response_out, rmw_request_id_t &request_header_out)
Take the next response for this client as a type erased pointer.
Definition: client.cpp:71
RCLCPP_PUBLIC size_t prune_pending_requests()
Clean all pending requests.
RCLCPP_PUBLIC FutureAndRequestId async_send_request(const Request request)
Send a request to the service server.
RCLCPP_PUBLIC bool remove_pending_request(int64_t request_id)
Cleanup a pending request.
RCLCPP_PUBLIC bool take_response(Response response_out, rmw_request_id_t &request_header_out)
Take the next response for this client.
SharedFutureAndRequestId async_send_request(const Request request, CallbackT &&cb)
Send a request to the service server and schedule a callback in the executor.
size_t prune_requests_older_than(std::chrono::time_point< std::chrono::system_clock > time_point, std::vector< int64_t, AllocatorT > *pruned_requests=nullptr)
Clean all pending requests older than a time_point.
Pure virtual interface class for the NodeBase part of the Node API.
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
Options available for a rcl_client_t.
Definition: client.h:50
A convenient GenericClient::Future and request id pair.
FutureAndRequestId(FutureAndRequestId &&other) noexcept=default
Move constructor.
FutureAndRequestId(const FutureAndRequestId &other)=delete
Deleted copy constructor, each instance is a unique owner of the future.
FutureAndRequestId & operator=(const FutureAndRequestId &other)=delete
Deleted copy assignment, each instance is a unique owner of the future.
SharedFuture share() noexcept
See std::future::share().
FutureAndRequestId & operator=(FutureAndRequestId &&other) noexcept=default
Move assignment.
A convenient GenericClient::SharedFuture and request id pair.