rdc_call_cp.hpp 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. /*
  2. * Copyright (c) 2017-2023 zhllxt
  3. *
  4. * author : zhllxt
  5. * email : 37792738@qq.com
  6. *
  7. * Distributed under the Boost Software License, Version 1.0. (See accompanying
  8. * file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  9. */
  10. #ifndef __ASIO2_RDC_CALL_COMPONENT_HPP__
  11. #define __ASIO2_RDC_CALL_COMPONENT_HPP__
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. #pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <cstdint>
  16. #include <memory>
  17. #include <chrono>
  18. #include <functional>
  19. #include <atomic>
  20. #include <string>
  21. #include <string_view>
  22. #include <queue>
  23. #include <any>
  24. #include <future>
  25. #include <tuple>
  26. #include <type_traits>
  27. #include <asio2/base/error.hpp>
  28. #include <asio2/base/define.hpp>
  29. #include <asio2/base/detail/util.hpp>
  30. #include <asio2/base/detail/function_traits.hpp>
  31. #include <asio2/base/impl/condition_event_cp.hpp>
  32. #include <asio2/component/rdc/rdc_invoker.hpp>
  33. #include <asio2/component/rdc/rdc_option.hpp>
  34. namespace asio2::detail
  35. {
  36. ASIO2_CLASS_FORWARD_DECLARE_BASE;
  37. template<class derived_t, class args_t>
  38. class rdc_call_cp_impl
  39. {
  40. ASIO2_CLASS_FRIEND_DECLARE_BASE;
  41. public:
  42. using send_data_t = typename args_t::send_data_t;
  43. using recv_data_t = typename args_t::recv_data_t;
  44. using callback_type = std::function<void(const error_code&, send_data_t, recv_data_t)>;
  45. /**
  46. * @brief constructor
  47. */
  48. rdc_call_cp_impl() noexcept = default;
  49. /**
  50. * @brief destructor
  51. */
  52. ~rdc_call_cp_impl() noexcept = default;
  53. protected:
  54. template<class derive_t, class arg_t>
  55. struct sync_call_op
  56. {
  57. using send_data_t = typename arg_t::send_data_t;
  58. using recv_data_t = typename arg_t::recv_data_t;
  59. template<class return_t>
  60. inline static void convert_recv_data_to_result(std::shared_ptr<return_t>& result, recv_data_t data)
  61. {
  62. if constexpr (std::is_reference_v<recv_data_t> &&
  63. has_equal_operator<return_t, std::remove_reference_t<recv_data_t>>::value)
  64. {
  65. *result = std::move(data);
  66. }
  67. else
  68. {
  69. if constexpr (has_stream_operator<return_t, recv_data_t>::value)
  70. {
  71. *result << data;
  72. }
  73. else if constexpr (has_equal_operator<return_t, recv_data_t>::value)
  74. {
  75. *result = data;
  76. }
  77. else
  78. {
  79. ::new (result.get()) return_t(data);
  80. }
  81. }
  82. }
  83. template<class return_t, class Rep, class Period, class DataT>
  84. inline static return_t exec(derive_t& derive, std::chrono::duration<Rep, Period> timeout, DataT&& data)
  85. {
  86. static_assert(!std::is_void_v<return_t>);
  87. static_assert(!std::is_reference_v<return_t> && !std::is_pointer_v<return_t>);
  88. static_assert(!is_template_instance_of_v<std::basic_string_view, return_t>);
  89. // should't read the ecs in other thread which is not the io_context thread.
  90. //if (!derive.ecs_->get_rdc())
  91. //{
  92. // ASIO2_ASSERT(false && "This function is only available in rdc mode");
  93. //}
  94. if (!derive.is_started())
  95. {
  96. set_last_error(asio::error::not_connected);
  97. // [20210818] don't throw an error, you can use get_last_error() to check
  98. // is there any exception.
  99. return return_t{};
  100. }
  101. std::shared_ptr<return_t> result = std::make_shared<return_t>();
  102. std::shared_ptr<std::promise<error_code>> promise = std::make_shared<std::promise<error_code>>();
  103. std::future<error_code> future = promise->get_future();
  104. auto invoker = [&derive, result, pm = std::move(promise)]
  105. (const error_code& ec, send_data_t s, recv_data_t r) mutable
  106. {
  107. ASIO2_ASSERT(derive.io_->running_in_this_thread());
  108. detail::ignore_unused(derive, s);
  109. if (!ec)
  110. {
  111. convert_recv_data_to_result(result, r);
  112. }
  113. pm->set_value(ec);
  114. };
  115. // All pending sending events will be cancelled after enter the callback below.
  116. asio::post(derive.io_->context(), make_allocator(derive.wallocator(),
  117. [&derive, p = derive.selfptr(), timeout,
  118. invoker = std::move(invoker), data = std::forward<DataT>(data)]
  119. () mutable
  120. {
  121. derive._rdc_send(std::move(p), std::move(data), std::move(timeout), std::move(invoker));
  122. }));
  123. // Whether we run on the io_context thread
  124. if (!derive.io_->running_in_this_thread())
  125. {
  126. std::future_status status = future.wait_for(timeout);
  127. if (status == std::future_status::ready)
  128. {
  129. set_last_error(future.get());
  130. }
  131. else
  132. {
  133. set_last_error(asio::error::timed_out);
  134. }
  135. }
  136. else
  137. {
  138. // If invoke synchronization rdc call function in communication thread,
  139. // it will degenerates into async_call and the return value is empty.
  140. set_last_error(asio::error::in_progress);
  141. }
  142. return std::move(*result);
  143. }
  144. };
  145. template<class derive_t, class arg_t>
  146. struct async_call_op
  147. {
  148. using send_data_t = typename arg_t::send_data_t;
  149. using recv_data_t = typename arg_t::recv_data_t;
  150. template<class DataT, class Rep, class Period, class Invoker>
  151. inline static void exec(derive_t& derive, DataT&& data,
  152. std::chrono::duration<Rep, Period> timeout, Invoker&& invoker)
  153. {
  154. // should't read the ecs in other thread which is not the io_context thread.
  155. //if (!derive.ecs_->get_rdc())
  156. //{
  157. // ASIO2_ASSERT(false && "This function is only available in rdc mode");
  158. //}
  159. if (!derive.is_started())
  160. {
  161. set_last_error(asio::error::in_progress);
  162. derive.post_event([&derive, p = derive.selfptr(), timeout,
  163. invoker = std::forward<Invoker>(invoker), data = std::forward<DataT>(data)]
  164. (event_queue_guard<derived_t> g) mutable
  165. {
  166. detail::ignore_unused(g);
  167. derive._rdc_send(std::move(p), std::move(data), std::move(timeout), std::move(invoker));
  168. });
  169. return;
  170. }
  171. clear_last_error();
  172. // All pending sending events will be cancelled after enter the callback below.
  173. asio::post(derive.io_->context(), make_allocator(derive.wallocator(),
  174. [&derive, p = derive.selfptr(), timeout,
  175. invoker = std::forward<Invoker>(invoker), data = std::forward<DataT>(data)]
  176. () mutable
  177. {
  178. derive._rdc_send(std::move(p), std::move(data), std::move(timeout), std::move(invoker));
  179. }));
  180. }
  181. };
  182. template<class derive_t, class arg_t>
  183. class sync_caller
  184. {
  185. template <class, class> friend class rdc_call_cp_impl;
  186. using send_data_t = typename arg_t::send_data_t;
  187. using recv_data_t = typename arg_t::recv_data_t;
  188. protected:
  189. sync_caller(derive_t& d) : derive(d), tm_(d.get_default_timeout()) {}
  190. sync_caller(sync_caller&& o) : derive(o.derive), tm_(std::move(o.tm_)) {}
  191. sync_caller(const sync_caller&) = delete;
  192. sync_caller& operator=(sync_caller&&) = delete;
  193. sync_caller& operator=(const sync_caller&) = delete;
  194. public:
  195. ~sync_caller() = default;
  196. /**
  197. * @brief set the timeout for remote data call component (means rdc)
  198. */
  199. template<class Rep, class Period>
  200. inline sync_caller& set_timeout(std::chrono::duration<Rep, Period> timeout)
  201. {
  202. this->tm_ = std::move(timeout);
  203. return (*this);
  204. }
  205. /**
  206. * @brief set the timeout for remote data call component (means rdc), same as set_timeout
  207. */
  208. template<class Rep, class Period>
  209. inline sync_caller& timeout(std::chrono::duration<Rep, Period> timeout)
  210. {
  211. return this->set_timeout(std::move(timeout));
  212. }
  213. template<class return_t, class DataT>
  214. inline return_t call(DataT&& data)
  215. {
  216. return sync_call_op<derive_t, arg_t>::template exec<return_t>(
  217. derive, tm_, std::forward<DataT>(data));
  218. }
  219. protected:
  220. derive_t& derive;
  221. asio::steady_timer::duration tm_;
  222. };
  223. template<class derive_t, class arg_t>
  224. class async_caller
  225. {
  226. template <class, class> friend class rdc_call_cp_impl;
  227. using send_data_t = typename arg_t::send_data_t;
  228. using recv_data_t = typename arg_t::recv_data_t;
  229. protected:
  230. async_caller(derive_t& d) : derive(d), tm_(d.get_default_timeout()) {}
  231. async_caller(async_caller&& o) : derive(o.derive),
  232. tm_(std::move(o.tm_)), cb_(std::move(o.cb_)), fn_(std::move(o.fn_)) {}
  233. async_caller(const async_caller&) = delete;
  234. async_caller& operator=(async_caller&&) = delete;
  235. async_caller& operator=(const async_caller&) = delete;
  236. using defer_fn = std::function<void(asio::steady_timer::duration, callback_type)>;
  237. public:
  238. ~async_caller()
  239. {
  240. if (this->fn_)
  241. {
  242. (this->fn_)(std::move(this->tm_), std::move(this->cb_));
  243. }
  244. }
  245. /**
  246. * @brief set the timeout for remote data call component (means rdc)
  247. */
  248. template<class Rep, class Period>
  249. inline async_caller& set_timeout(std::chrono::duration<Rep, Period> timeout)
  250. {
  251. this->tm_ = timeout;
  252. return (*this);
  253. }
  254. /**
  255. * @brief set the timeout for remote data call component (means rdc), same as set_timeout
  256. */
  257. template<class Rep, class Period>
  258. inline async_caller& timeout(std::chrono::duration<Rep, Period> timeout)
  259. {
  260. return this->set_timeout(std::move(timeout));
  261. }
  262. template<class Callback>
  263. inline async_caller& response(Callback&& cb)
  264. {
  265. this->cb_ = rdc_make_callback_t<send_data_t, recv_data_t>::bind(std::forward<Callback>(cb));
  266. return (*this);
  267. }
  268. template<class DataT>
  269. inline async_caller& async_call(DataT&& data)
  270. {
  271. derive_t& deriv = derive;
  272. this->fn_ = [&deriv, data = std::forward<DataT>(data)]
  273. (asio::steady_timer::duration timeout, callback_type cb) mutable
  274. {
  275. async_call_op<derive_t, arg_t>::exec(deriv, std::move(data), std::move(timeout), std::move(cb));
  276. };
  277. return (*this);
  278. }
  279. protected:
  280. derive_t& derive;
  281. asio::steady_timer::duration tm_;
  282. callback_type cb_;
  283. defer_fn fn_;
  284. };
  285. template<class derive_t, class arg_t>
  286. class base_caller
  287. {
  288. template <class, class> friend class rdc_call_cp_impl;
  289. using send_data_t = typename arg_t::send_data_t;
  290. using recv_data_t = typename arg_t::recv_data_t;
  291. protected:
  292. base_caller(derive_t& d) : derive(d), tm_(d.get_default_timeout()) {}
  293. base_caller(base_caller&& o) : derive(o.derive), tm_(std::move(o.tm_)) {}
  294. base_caller& operator=(base_caller&&) = delete;
  295. base_caller(const base_caller&) = delete;
  296. base_caller& operator=(const base_caller&) = delete;
  297. public:
  298. ~base_caller() = default;
  299. /**
  300. * @brief set the timeout for remote data call component (means rdc)
  301. */
  302. template<class Rep, class Period>
  303. inline base_caller& set_timeout(std::chrono::duration<Rep, Period> timeout)
  304. {
  305. this->tm_ = std::move(timeout);
  306. return (*this);
  307. }
  308. /**
  309. * @brief set the timeout for remote data call component (means rdc), same as set_timeout
  310. */
  311. template<class Rep, class Period>
  312. inline base_caller& timeout(std::chrono::duration<Rep, Period> timeout)
  313. {
  314. return this->set_timeout(std::move(timeout));
  315. }
  316. template<class Callback>
  317. inline async_caller<derive_t, arg_t> response(Callback&& cb)
  318. {
  319. async_caller<derive_t, arg_t> caller{ derive };
  320. caller.set_timeout(std::move(this->tm_));
  321. caller.response(std::forward<Callback>(cb));
  322. return caller; // "caller" is local variable has RVO optimization, should't use std::move()
  323. }
  324. template<class return_t, class DataT>
  325. inline return_t call(DataT&& data)
  326. {
  327. return sync_call_op<derive_t, arg_t>::template exec<return_t>(
  328. derive, this->tm_, std::forward<DataT>(data));
  329. }
  330. template<class DataT>
  331. inline async_caller<derive_t, arg_t> async_call(DataT&& data)
  332. {
  333. async_caller<derive_t, arg_t> caller{ derive };
  334. caller.set_timeout(std::move(this->tm_));
  335. caller.async_call(std::forward<DataT>(data));
  336. return caller; // "caller" is local variable has RVO optimization, should't use std::move()
  337. }
  338. protected:
  339. derive_t& derive;
  340. asio::steady_timer::duration tm_;
  341. };
  342. public:
  343. /**
  344. * @brief Send data and synchronize waiting for a response or until the timeout period is reached
  345. */
  346. template<class return_t, class DataT>
  347. inline return_t call(DataT&& data)
  348. {
  349. derived_t& derive = static_cast<derived_t&>(*this);
  350. return sync_call_op<derived_t, args_t>::template exec<return_t>(
  351. derive, derive.get_default_timeout(), std::forward<DataT>(data));
  352. }
  353. /**
  354. * @brief Send data and synchronize waiting for a response or until the timeout period is reached
  355. */
  356. template<class return_t, class DataT, class Rep, class Period>
  357. inline return_t call(DataT&& data, std::chrono::duration<Rep, Period> timeout)
  358. {
  359. derived_t& derive = static_cast<derived_t&>(*this);
  360. return sync_call_op<derived_t, args_t>::template exec<return_t>(
  361. derive, timeout, std::forward<DataT>(data));
  362. }
  363. /**
  364. * @brief Send data and asynchronous waiting for a response or until the timeout period is reached
  365. * Callback signature : void(DataType data)
  366. */
  367. template<class DataT, class Callback>
  368. inline typename std::enable_if_t<is_callable_v<Callback>, void>
  369. async_call(DataT&& data, Callback&& cb)
  370. {
  371. derived_t& derive = static_cast<derived_t&>(*this);
  372. async_call_op<derived_t, args_t>::exec(derive, std::forward<DataT>(data), derive.get_default_timeout(),
  373. rdc_make_callback_t<send_data_t, recv_data_t>::bind(std::forward<Callback>(cb)));
  374. }
  375. /**
  376. * @brief Send data and asynchronous waiting for a response or until the timeout period is reached
  377. * Callback signature : void(DataType data)
  378. */
  379. template<class DataT, class Callback, class Rep, class Period>
  380. inline typename std::enable_if_t<is_callable_v<Callback>, void>
  381. async_call(DataT&& data, Callback&& cb, std::chrono::duration<Rep, Period> timeout)
  382. {
  383. derived_t& derive = static_cast<derived_t&>(*this);
  384. async_call_op<derived_t, args_t>::exec(derive, std::forward<DataT>(data), timeout,
  385. rdc_make_callback_t<send_data_t, recv_data_t>::bind(std::forward<Callback>(cb)));
  386. }
  387. /**
  388. * @brief Send data and asynchronous waiting for a response or until the timeout period is reached
  389. */
  390. template<class DataT>
  391. inline async_caller<derived_t, args_t> async_call(DataT&& data)
  392. {
  393. async_caller<derived_t, args_t> caller{ static_cast<derived_t&>(*this) };
  394. caller.async_call(std::forward<DataT>(data));
  395. return caller; // "caller" is local variable has RVO optimization, should't use std::move()
  396. }
  397. /**
  398. * @brief set the timeout for remote data call component (means rdc)
  399. */
  400. template<class Rep, class Period>
  401. inline base_caller<derived_t, args_t> set_timeout(std::chrono::duration<Rep, Period> timeout)
  402. {
  403. base_caller<derived_t, args_t> caller{ static_cast<derived_t&>(*this) };
  404. caller.set_timeout(timeout);
  405. return caller; // "caller" is local variable has RVO optimization, should't use std::move()
  406. }
  407. /**
  408. * @brief set the timeout for remote data call component (means rdc), same as set_timeout
  409. */
  410. template<class Rep, class Period>
  411. inline base_caller<derived_t, args_t> timeout(std::chrono::duration<Rep, Period> timeout)
  412. {
  413. return this->set_timeout(std::move(timeout));
  414. }
  415. /**
  416. * @brief bind a response callback function for remote data call component (means rdc)
  417. */
  418. template<class Callback>
  419. inline async_caller<derived_t, args_t> response(Callback&& cb)
  420. {
  421. async_caller<derived_t, args_t> caller{ static_cast<derived_t&>(*this) };
  422. caller.response(std::forward<Callback>(cb));
  423. return caller; // "caller" is local variable has RVO optimization, should't use std::move()
  424. }
  425. protected:
  426. template<typename C>
  427. inline void _rdc_init(std::shared_ptr<ecs_t<C>>& ecs)
  428. {
  429. detail::ignore_unused(ecs);
  430. }
  431. template<typename C>
  432. inline void _rdc_start(std::shared_ptr<derived_t>& this_ptr, std::shared_ptr<ecs_t<C>>& ecs)
  433. {
  434. detail::ignore_unused(this_ptr, ecs);
  435. if constexpr (ecs_helper::has_rdc<C>())
  436. {
  437. ASIO2_ASSERT(ecs->get_component().rdc_option(std::in_place)->invoker().reqs().empty());
  438. }
  439. else
  440. {
  441. std::ignore = true;
  442. }
  443. }
  444. inline void _rdc_stop()
  445. {
  446. derived_t& derive = static_cast<derived_t&>(*this);
  447. ASIO2_ASSERT(derive.io_->running_in_this_thread());
  448. // this callback maybe executed after the session stop, and the session
  449. // stop will destroy the ecs, so we need check whether the ecs is valid.
  450. if (!derive.ecs_)
  451. return;
  452. asio2::rdc::option_base* prdc = derive.ecs_->get_rdc();
  453. // maybe not rdc mode, so must check whether the rdc is valid.
  454. if (!prdc)
  455. return;
  456. // if stoped, execute all callbacks in the requests, otherwise if some
  457. // call or async_call 's timeout is too long, then the application will
  458. // can't exit before all timeout timer is reached.
  459. prdc->foreach_and_clear([&derive](void*, void* val) mutable
  460. {
  461. std::tuple<std::shared_ptr<asio::steady_timer>, callback_type>& tp =
  462. *((std::tuple<std::shared_ptr<asio::steady_timer>, callback_type>*)val);
  463. auto& [timer, invoker] = tp;
  464. detail::cancel_timer(*timer);
  465. derive._rdc_invoke_with_none(asio::error::operation_aborted, invoker);
  466. });
  467. }
  468. template<class DataT>
  469. void _rdc_send(
  470. std::shared_ptr<derived_t> this_ptr, DataT&& data,
  471. std::chrono::steady_clock::duration timeout, callback_type invoker)
  472. {
  473. derived_t& derive = static_cast<derived_t&>(*this);
  474. ASIO2_ASSERT(derive.io_->running_in_this_thread());
  475. auto persisted_data = derive._data_persistence(std::forward<DataT>(data));
  476. send_data_t sent_typed_data = derive._rdc_convert_to_send_data(persisted_data);
  477. if (!derive.ecs_)
  478. {
  479. derive._rdc_invoke_with_send(asio::error::operation_aborted, invoker, sent_typed_data);
  480. return;
  481. }
  482. // if ecs is valid, the rdc must be valid.
  483. asio2::rdc::option_base* prdc = derive.ecs_->get_rdc();
  484. // maybe not rdc mode, so must check whether the rdc is valid.
  485. if (!prdc)
  486. {
  487. ASIO2_ASSERT(false && "This function is only available in rdc mode");
  488. derive._rdc_invoke_with_send(asio::error::operation_not_supported, invoker, sent_typed_data);
  489. return;
  490. }
  491. std::any rdc_id = prdc->call_parser(true, (void*)std::addressof(sent_typed_data));
  492. std::shared_ptr<asio::steady_timer> timer =
  493. std::make_shared<asio::steady_timer>(derive.io_->context());
  494. std::tuple tp(timer, std::move(invoker));
  495. prdc->emplace_request(rdc_id, (void*)std::addressof(tp));
  496. auto ex = [&derive, rdc_id = std::move(rdc_id), prdc]() mutable
  497. {
  498. ASIO2_ASSERT(derive.io_->running_in_this_thread());
  499. prdc->execute_and_erase(rdc_id, [&derive](void* val) mutable
  500. {
  501. std::tuple<std::shared_ptr<asio::steady_timer>, callback_type>& tp =
  502. *((std::tuple<std::shared_ptr<asio::steady_timer>, callback_type>*)val);
  503. auto& [tmer, cb] = tp;
  504. detail::cancel_timer(*tmer);
  505. derive._rdc_invoke_with_none(asio::error::timed_out, cb);
  506. });
  507. };
  508. timer->expires_after(timeout);
  509. timer->async_wait([this_ptr, ex](const error_code& ec) mutable
  510. {
  511. if (ec == asio::error::operation_aborted)
  512. return;
  513. ex();
  514. });
  515. derive.push_event(
  516. [&derive, p = std::move(this_ptr),
  517. life_id = derive.life_id(), ex = std::move(ex), data = std::move(persisted_data)]
  518. (event_queue_guard<derived_t> g) mutable
  519. {
  520. if (life_id != derive.life_id())
  521. {
  522. set_last_error(asio::error::operation_aborted);
  523. ex();
  524. return;
  525. }
  526. derive._do_send(data, [&ex, g = std::move(g)](const error_code& ec, std::size_t) mutable
  527. {
  528. detail::ignore_unused(g);
  529. if (ec)
  530. {
  531. ex();
  532. }
  533. });
  534. });
  535. }
  536. template<typename C>
  537. inline void _do_rdc_handle_recv(
  538. std::shared_ptr<derived_t>& this_ptr, std::shared_ptr<ecs_t<C>>& ecs, recv_data_t data)
  539. {
  540. detail::ignore_unused(this_ptr);
  541. derived_t& derive = static_cast<derived_t&>(*this);
  542. auto _rdc = ecs->get_component().rdc_option(std::in_place);
  543. if (_rdc->invoker().reqs().empty())
  544. return;
  545. auto rdc_id = (_rdc->get_recv_parser())(data);
  546. ASIO2_ASSERT(derive.io_->running_in_this_thread());
  547. auto iter = _rdc->invoker().find(rdc_id);
  548. if (iter != _rdc->invoker().end())
  549. {
  550. auto&[timer, invoker] = iter->second;
  551. detail::cancel_timer(*timer);
  552. derive._rdc_invoke_with_recv(error_code{}, invoker, data);
  553. _rdc->invoker().erase(iter);
  554. }
  555. }
  556. template<typename C>
  557. inline void _rdc_handle_recv(
  558. std::shared_ptr<derived_t>& this_ptr, std::shared_ptr<ecs_t<C>>& ecs, recv_data_t data)
  559. {
  560. if constexpr (ecs_helper::has_rdc<C>())
  561. {
  562. derived_t& derive = static_cast<derived_t&>(*this);
  563. derive._do_rdc_handle_recv(this_ptr, ecs, data);
  564. }
  565. else
  566. {
  567. detail::ignore_unused(this_ptr, ecs, data);
  568. }
  569. }
  570. };
  571. template<class args_t>
  572. struct is_rdc_call_cp_enabled
  573. {
  574. template<class, class = void>
  575. struct has_member_enabled : std::false_type {};
  576. template<class T>
  577. struct has_member_enabled<T, std::void_t<decltype(T::rdc_call_cp_enabled)>> : std::true_type {};
  578. static constexpr bool value()
  579. {
  580. if constexpr (has_member_enabled<args_t>::value)
  581. {
  582. return args_t::rdc_call_cp_enabled;
  583. }
  584. else
  585. {
  586. return true;
  587. }
  588. }
  589. };
  590. template<class derived_t, class args_t, bool Enable = is_rdc_call_cp_enabled<args_t>::value()>
  591. class rdc_call_cp_bridge;
  592. template<class derived_t, class args_t>
  593. class rdc_call_cp_bridge<derived_t, args_t, true> : public rdc_call_cp_impl<derived_t, args_t> {};
  594. template<class derived_t, class args_t>
  595. class rdc_call_cp_bridge<derived_t, args_t, false>
  596. {
  597. protected:
  598. // just placeholders
  599. template<typename... Args> inline void _rdc_init (Args const& ...) {}
  600. template<typename... Args> inline void _rdc_start (Args const& ...) {}
  601. template<typename... Args> inline void _rdc_stop (Args const& ...) {}
  602. template<typename... Args> inline void _rdc_handle_recv(Args const& ...) {}
  603. };
  604. template<class derived_t, class args_t>
  605. class rdc_call_cp : public rdc_call_cp_bridge<derived_t, args_t> {};
  606. }
  607. #endif // !__ASIO2_RDC_CALL_COMPONENT_HPP__