8#include <mrs_lib/coro/cancellation.hpp>
9#include <mrs_lib/coro/event.hpp>
21 template <
class ServiceType>
23 : impl_(std::make_shared<
Impl>(node, address, qos, node->create_callback_group(rclcpp::CallbackGroupType::MutuallyExclusive)))
27 template <
class ServiceType>
32 template <
class ServiceType>
34 const rclcpp::CallbackGroup::SharedPtr& callback_group)
35 : impl_(std::make_shared<
Impl>(node, address, qos, callback_group))
39 template <
class ServiceType>
41 const rclcpp::CallbackGroup::SharedPtr& callback_group)
50 template <
class ServiceType>
51 std::optional<std::shared_ptr<typename ServiceType::Response>>
56 RCLCPP_ERROR(rclcpp::get_logger(
"ServiceClientHandler"),
"Not initialized, cannot use callSync()!");
59 return impl_->callSync(request);
66 template <
class ServiceType>
67 std::optional<std::shared_future<std::shared_ptr<typename ServiceType::Response>>>
72 RCLCPP_ERROR(rclcpp::get_logger(
"ServiceClientHandler"),
"Not initialized, cannot use callAsync()!");
75 return impl_->callAsync(request);
80 template <
class ServiceType>
86 RCLCPP_ERROR(rclcpp::get_logger(
"ServiceClientHandler"),
"Not initialized, cannot use callAwaitable()!");
87 co_return std::nullopt;
90 co_return co_await impl_->callAwaitable(request);
95 template <
class ServiceType>
100 RCLCPP_ERROR(rclcpp::get_logger(
"ServiceClientHandler"),
"Not initialized, cannot use getServiceName()!");
103 return impl_->getServiceName();
110 template <
class ServiceType>
111 template <
typename RepT,
typename RatioT>
116 RCLCPP_ERROR(rclcpp::get_logger(
"ServiceClientHandler"),
"Not initialized, cannot use waitForService()!");
119 return impl_->waitForService(timeout);
125 template <
class ServiceType>
130 RCLCPP_ERROR(rclcpp::get_logger(
"ServiceClientHandler"),
"Not initialized, cannot use isServiceReady()!");
133 return impl_->isServiceReady();
138 template <
class ServiceType>
143 RCLCPP_ERROR(rclcpp::get_logger(
"ServiceClientHandler"),
"Not initialized, cannot use prunePendingRequests()!");
146 return impl_->prunePendingRequests();
159 template <
class ServiceType>
172 Impl(rclcpp::Node::SharedPtr& node,
const std::string& address,
const rclcpp::QoS& qos,
const rclcpp::CallbackGroup::SharedPtr& callback_group)
173 : callback_group_(callback_group), service_client_(node->create_client<ServiceType>(address, qos, callback_group))
175 RCLCPP_INFO_STREAM(node->get_logger(),
"Created client '" << address <<
"' -> '" << service_client_->get_service_name() <<
"'");
185 std::optional<std::shared_ptr<typename ServiceType::Response>>
callSync(
const std::shared_ptr<typename ServiceType::Request>& request)
188 if (!service_client_->service_is_ready())
192 const auto future_msg = service_client_->async_send_request(request).future.share();
196 if (!future_msg.valid())
200 return future_msg.get();
210 std::optional<std::shared_future<std::shared_ptr<typename ServiceType::Response>>>
callAsync(
const std::shared_ptr<typename ServiceType::Request>& request)
213 if (!service_client_->service_is_ready())
216 const auto future = service_client_->async_send_request(request).future.share();
228 using Response = ServiceType::Response;
229 using Client = rclcpp::Client<ServiceType>;
230 using SharedFutureAndRequestId = Client::SharedFutureAndRequestId;
231 using StopTokenBehavior = coro::internal::LowLevelEventAwaitable::StopTokenBehavior;
236 bool cancelled =
false;
238 std::optional<SharedFutureAndRequestId> future_and_id{};
241 if (!service_client_->service_is_ready())
243 co_return std::nullopt;
246 auto [event, awaitable] = coro::make_event();
248 std::shared_ptr<StateData> state_data = std::make_shared<StateData>();
250 auto register_waker = [&event, client = service_client_, request, state_data]() {
251 std::lock_guard lock(state_data->mutex);
252 if (state_data->cancelled)
257 auto shared_event = std::make_shared<coro::Event>(std::move(event));
258 state_data->future_and_id =
259 client->async_send_request(request, [shared_event](std::shared_future<std::shared_ptr<Response>>) { shared_event->try_trigger(); });
262 auto low_level_awaitable = coro::internal::get_low_level_event_awaitable(std::move(awaitable));
269 std::stop_callback remove_request_if_canceled(
co_await coro::get_task_stop_token(), [state_data, client_weak = std::weak_ptr(service_client_)]() {
270 std::lock_guard lock(state_data->mutex);
271 state_data->cancelled =
true;
272 std::shared_ptr<Client> client = client_weak.lock();
273 if (client ==
nullptr || !state_data->future_and_id.has_value())
277 client->remove_pending_request(state_data->future_and_id.value());
280 co_await std::move(low_level_awaitable).get_awaitable(StopTokenBehavior::ignore, register_waker);
284 std::lock_guard lock(state_data->mutex);
285 if (!state_data->future_and_id.has_value())
287 co_return std::nullopt;
290 auto future = state_data->future_and_id.value().future;
291 if (future.wait_for(std::chrono::nanoseconds(0)) == std::future_status::timeout)
293 co_return std::nullopt;
296 co_return std::shared_ptr<Response>(future.get());
307 return service_client_->get_service_name();
317 template <
typename RepT =
int64_t,
typename RatioT = std::milli>
320 return service_client_->wait_for_service(timeout);
330 return service_client_->service_is_ready();
340 return service_client_->prune_pending_requests();
344 rclcpp::CallbackGroup::SharedPtr callback_group_;
345 typename rclcpp::Client<ServiceType>::SharedPtr service_client_;
implementation of the service client handler
Definition service_client_handler.hpp:161
size_t prunePendingRequests() const
Clean all pending requests.
Definition service_client_handler.hpp:338
std::optional< std::shared_future< std::shared_ptr< typename ServiceType::Response > > > callAsync(const std::shared_ptr< typename ServiceType::Request > &request)
asynchronous service call
Definition service_client_handler.hpp:210
std::optional< std::shared_ptr< typename ServiceType::Response > > callSync(const std::shared_ptr< typename ServiceType::Request > &request)
"classic" synchronous service call
Definition service_client_handler.hpp:185
Impl(rclcpp::Node::SharedPtr &node, const std::string &address, const rclcpp::QoS &qos, const rclcpp::CallbackGroup::SharedPtr &callback_group)
constructor
Definition service_client_handler.hpp:172
std::string getServiceName() const
Returns the name of the service this client connects to.
Definition service_client_handler.hpp:305
bool waitForService(std::chrono::duration< RepT, RatioT > timeout)
Waits for the service to be available.
Definition service_client_handler.hpp:318
bool isServiceReady() const
Checks if the service is available.
Definition service_client_handler.hpp:328
user wrapper of the service client handler implementation
Definition service_client_handler.h:26
ServiceClientHandler()
Default constructor to avoid having to use pointers.
Definition service_client_handler.hpp:28
std::optional< std::shared_ptr< typename ServiceType::Response > > callSync(const std::shared_ptr< typename ServiceType::Request > &request)
Synchronous (blocking) call of the service.
Definition service_client_handler.hpp:52
std::string getServiceName() const
Returns the name of the service this client connects to.
Definition service_client_handler.hpp:96
bool waitForService(std::chrono::duration< RepT, RatioT > timeout=std::chrono::seconds(1))
Waits for the service to be available.
Definition service_client_handler.hpp:112
std::optional< std::shared_future< std::shared_ptr< typename ServiceType::Response > > > callAsync(const std::shared_ptr< typename ServiceType::Request > &request)
Asynchronous (non-blocking) call of the service.
Definition service_client_handler.hpp:68
size_t prunePendingRequests()
Clean all pending requests.
Definition service_client_handler.hpp:139
bool isServiceReady() const
Checks if the service is available.
Definition service_client_handler.hpp:126
Task< std::optional< std::shared_ptr< typename ServiceType::Response > > > callAwaitable(std::shared_ptr< typename ServiceType::Request > request)
Awaitable call of the service.
Definition service_client_handler.hpp:82
Task type for creating coroutines.
Definition task.hpp:268
All mrs_lib functions, classes, variables and definitions are contained in this namespace.
Definition attitude_converter.h:24
Defines ServiceClientHandler and related convenience classes for upgrading the ROS service client.