scenario_simulator_v2 C++ API
service_with_validation.hpp
Go to the documentation of this file.
1 // Copyright 2015 TIER IV, Inc. All rights reserved.
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 CONCEALER__SERVICE_WITH_VALIDATION_HPP_
16 #define CONCEALER__SERVICE_WITH_VALIDATION_HPP_
17 
18 #include <autoware_adapi_v1_msgs/msg/response_status.hpp>
19 #include <chrono>
21 #include <rclcpp/rclcpp.hpp>
22 #include <string>
23 #include <tier4_external_api_msgs/msg/response_status.hpp>
24 #include <tier4_rtc_msgs/srv/auto_mode_with_module.hpp>
25 #include <type_traits>
26 
27 template <typename T, typename = void>
28 struct has_data_member_status : public std::false_type
29 {
30 };
31 
32 template <typename T>
33 struct has_data_member_status<T, std::void_t<decltype(std::declval<T>().status)>>
34 : public std::true_type
35 {
36 };
37 
38 template <typename T>
40 
41 template <typename T, typename = void>
42 struct has_data_member_success : public std::false_type
43 {
44 };
45 
46 template <typename T>
47 struct has_data_member_success<T, std::void_t<decltype(std::declval<T>().success)>>
48 : public std::true_type
49 {
50 };
51 
52 template <typename T>
54 
55 namespace concealer
56 {
57 template <typename T>
59 {
60 public:
62  const std::string & service_name, FieldOperatorApplication & autoware,
63  const std::chrono::nanoseconds validation_interval = std::chrono::seconds(1))
64  : service_name(service_name),
65  logger(autoware.get_logger()),
66  client(autoware.create_client<T>(service_name, rmw_qos_profile_default)),
67  validation_rate(validation_interval)
68  {
69  }
70 
71  class TimeoutError : public common::Error
72  {
73  public:
74  template <typename... Ts>
75  explicit TimeoutError(Ts &&... xs) : common::Error(std::forward<decltype(xs)>(xs)...)
76  {
77  }
78  };
79 
80  auto operator()(const typename T::Request::SharedPtr & request, std::size_t attempts_count = 1)
81  -> void
82  {
83  validateAvailability();
84  for (std::size_t attempt = 0; attempt < attempts_count; ++attempt, validation_rate.sleep()) {
85  if (const auto & service_call_result = callWithTimeoutValidation(request)) {
86  if constexpr (has_data_member_status_v<typename T::Response>) {
87  if constexpr (std::is_same_v<
88  tier4_external_api_msgs::msg::ResponseStatus,
89  decltype(T::Response::status)>) {
90  if (const auto & service_call_status = service_call_result->get()->status;
91  service_call_status.code == tier4_external_api_msgs::msg::ResponseStatus::SUCCESS) {
92  RCLCPP_INFO_STREAM(
93  logger, service_name << " service request has been accepted"
94  << (service_call_status.message.empty()
95  ? "."
96  : " (" + service_call_status.message + ")."));
97  return;
98  } else {
99  RCLCPP_ERROR_STREAM(
100  logger, service_name
101  << " service request was accepted, but ResponseStatus is FAILURE"
102  << (service_call_status.message.empty()
103  ? "."
104  : " (" + service_call_status.message + ")"));
105  }
106  } else if constexpr (std::is_same_v<
107  autoware_adapi_v1_msgs::msg::ResponseStatus,
108  decltype(T::Response::status)>) {
109  if (const auto & service_call_status = service_call_result->get()->status;
110  service_call_status.success) {
111  RCLCPP_INFO_STREAM(
112  logger, service_name << " service request has been accepted"
113  << (service_call_status.message.empty()
114  ? "."
115  : " (" + service_call_status.message + ")."));
116  return;
117  } else {
118  RCLCPP_ERROR_STREAM(
119  logger, service_name
120  << " service request was accepted, but ResponseStatus::success is false "
121  << (service_call_status.message.empty()
122  ? ""
123  : " (" + service_call_status.message + ")"));
124  }
125  } else {
126  RCLCPP_INFO_STREAM(logger, service_name << " service request has been accepted.");
127  return;
128  }
129  } else if constexpr (has_data_member_success_v<typename T::Response>) {
130  if constexpr (std::is_same_v<bool, decltype(T::Response::success)>) {
131  if (service_call_result->get()->success) {
132  RCLCPP_INFO_STREAM(logger, service_name << " service request has been accepted.");
133  return;
134  } else {
135  RCLCPP_ERROR_STREAM(
136  logger, service_name
137  << " service request has been accepted, but Response::success is false.");
138  }
139  } else {
140  RCLCPP_INFO_STREAM(logger, service_name << " service request has been accepted.");
141  return;
142  }
143  } else {
144  RCLCPP_INFO_STREAM(logger, service_name << " service request has been accepted.");
145  return;
146  }
147  }
148  }
149  throw TimeoutError(
150  "Requested the service ", std::quoted(service_name), " ", attempts_count,
151  " times, but was not successful.");
152  }
153 
154 private:
155  auto validateAvailability() -> void
156  {
157  while (!client->service_is_ready()) {
158  RCLCPP_INFO_STREAM(logger, service_name << " service is not ready.");
159  validation_rate.sleep();
160  }
161  }
162 
163  auto callWithTimeoutValidation(const typename T::Request::SharedPtr & request)
164  -> std::optional<typename rclcpp::Client<T>::SharedFuture>
165  {
166  if (auto future = client->async_send_request(request);
167  future.wait_for(validation_rate.period()) == std::future_status::ready) {
168  return future;
169  } else {
170  RCLCPP_ERROR_STREAM(logger, service_name << " service request has timed out.");
171  return std::nullopt;
172  }
173  }
174 
175  const std::string service_name;
176 
177  rclcpp::Logger logger;
178 
179  typename rclcpp::Client<T>::SharedPtr client;
180 
181  rclcpp::WallRate validation_rate;
182 };
183 } // namespace concealer
184 
185 #endif //CONCEALER__SERVICE_WITH_VALIDATION_HPP_
Definition: field_operator_application.hpp:60
Definition: service_with_validation.hpp:72
TimeoutError(Ts &&... xs)
Definition: service_with_validation.hpp:75
Definition: service_with_validation.hpp:59
ServiceWithValidation(const std::string &service_name, FieldOperatorApplication &autoware, const std::chrono::nanoseconds validation_interval=std::chrono::seconds(1))
Definition: service_with_validation.hpp:61
auto operator()(const typename T::Request::SharedPtr &request, std::size_t attempts_count=1) -> void
Definition: service_with_validation.hpp:80
Definition: concatenate.hpp:24
Definition: autoware.hpp:30
void void_t
Definition: void_t.hpp:25
constexpr int SUCCESS
Definition: constants.hpp:22
Definition: cache.hpp:27
Definition: junit5.hpp:25
std::string string
Definition: junit5.hpp:26
constexpr auto has_data_member_status_v
Definition: service_with_validation.hpp:39
constexpr auto has_data_member_success_v
Definition: service_with_validation.hpp:53
Definition: exception.hpp:27
Definition: service_with_validation.hpp:29
Definition: service_with_validation.hpp:43