rpc_client.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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_RPC_CLIENT_HPP__
  11. #define __ASIO2_RPC_CLIENT_HPP__
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. #pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #if __has_include(<cereal/cereal.hpp>)
  16. #include <asio2/base/detail/push_options.hpp>
  17. #include <asio2/config.hpp>
  18. #include <asio2/udp/udp_client.hpp>
  19. #include <asio2/tcp/tcp_client.hpp>
  20. #include <asio2/tcp/tcps_client.hpp>
  21. #include <asio2/http/ws_client.hpp>
  22. #include <asio2/http/wss_client.hpp>
  23. #include <asio2/rpc/detail/rpc_protocol.hpp>
  24. #include <asio2/rpc/detail/rpc_invoker.hpp>
  25. #include <asio2/rpc/impl/rpc_recv_op.hpp>
  26. #include <asio2/rpc/impl/rpc_call_cp.hpp>
  27. namespace asio2::detail
  28. {
  29. ASIO2_CLASS_FORWARD_DECLARE_BASE;
  30. ASIO2_CLASS_FORWARD_DECLARE_UDP_BASE;
  31. ASIO2_CLASS_FORWARD_DECLARE_UDP_CLIENT;
  32. ASIO2_CLASS_FORWARD_DECLARE_TCP_BASE;
  33. ASIO2_CLASS_FORWARD_DECLARE_TCP_CLIENT;
  34. template<class derived_t, class executor_t>
  35. class rpc_client_impl_t
  36. : public executor_t
  37. , public rpc_invoker_t<derived_t, typename executor_t::args_type>
  38. , public rpc_call_cp <derived_t, typename executor_t::args_type>
  39. , public rpc_recv_op <derived_t, typename executor_t::args_type>
  40. , protected id_maker <typename rpc_header::id_type>
  41. {
  42. ASIO2_CLASS_FRIEND_DECLARE_BASE;
  43. ASIO2_CLASS_FRIEND_DECLARE_UDP_BASE;
  44. ASIO2_CLASS_FRIEND_DECLARE_UDP_CLIENT;
  45. ASIO2_CLASS_FRIEND_DECLARE_TCP_BASE;
  46. ASIO2_CLASS_FRIEND_DECLARE_TCP_CLIENT;
  47. public:
  48. using super = executor_t;
  49. using self = rpc_client_impl_t<derived_t, executor_t>;
  50. using executor_type = executor_t;
  51. using args_type = typename executor_t::args_type;
  52. static constexpr asio2::net_protocol net_protocol = args_type::net_protocol;
  53. protected:
  54. using super::send;
  55. using super::async_send;
  56. public:
  57. /**
  58. * @brief constructor
  59. */
  60. template<class ...Args>
  61. explicit rpc_client_impl_t(
  62. Args&&... args
  63. )
  64. : super(std::forward<Args>(args)...)
  65. , rpc_invoker_t<derived_t, typename executor_t::args_type>()
  66. , rpc_call_cp <derived_t, typename executor_t::args_type>(this->serializer_, this->deserializer_)
  67. , rpc_recv_op <derived_t, typename executor_t::args_type>()
  68. , id_maker <typename rpc_header::id_type>()
  69. {
  70. }
  71. /**
  72. * @brief destructor
  73. */
  74. ~rpc_client_impl_t()
  75. {
  76. this->stop();
  77. }
  78. /**
  79. * @brief start the client, blocking connect to server
  80. * @param host - A string identifying a location. May be a descriptive name or
  81. * a numeric address string.
  82. * @param port - A string identifying the requested service. This may be a
  83. * descriptive name or a numeric string corresponding to a port number.
  84. */
  85. template<typename String, typename StrOrInt, typename... Args>
  86. bool start(String&& host, StrOrInt&& port, Args&&... args)
  87. {
  88. if constexpr (is_websocket_client<executor_t>::value)
  89. {
  90. return executor_t::template start(
  91. std::forward<String>(host), std::forward<StrOrInt>(port),
  92. std::forward<Args>(args)...);
  93. }
  94. else if constexpr (net_protocol == asio2::net_protocol::udp)
  95. {
  96. return executor_t::template start(
  97. std::forward<String>(host), std::forward<StrOrInt>(port),
  98. asio2::use_kcp, std::forward<Args>(args)...);
  99. }
  100. else
  101. {
  102. return executor_t::template start(
  103. std::forward<String>(host), std::forward<StrOrInt>(port),
  104. asio2::use_dgram, std::forward<Args>(args)...);
  105. }
  106. }
  107. /**
  108. * @brief start the client, asynchronous connect to server
  109. * @param host - A string identifying a location. May be a descriptive name or
  110. * a numeric address string.
  111. * @param port - A string identifying the requested service. This may be a
  112. * descriptive name or a numeric string corresponding to a port number.
  113. */
  114. template<typename String, typename StrOrInt, typename... Args>
  115. bool async_start(String&& host, StrOrInt&& port, Args&&... args)
  116. {
  117. //static_assert(net_protocol != asio2::net_protocol::udp, "net_protocol::udp not supported");
  118. if constexpr (is_websocket_client<executor_t>::value)
  119. {
  120. return executor_t::template async_start(
  121. std::forward<String>(host), std::forward<StrOrInt>(port),
  122. std::forward<Args>(args)...);
  123. }
  124. else if constexpr (net_protocol == asio2::net_protocol::udp)
  125. {
  126. return executor_t::template start(
  127. std::forward<String>(host), std::forward<StrOrInt>(port),
  128. asio2::use_kcp, std::forward<Args>(args)...);
  129. }
  130. else
  131. {
  132. return executor_t::template async_start(
  133. std::forward<String>(host), std::forward<StrOrInt>(port),
  134. asio2::use_dgram, std::forward<Args>(args)...);
  135. }
  136. }
  137. protected:
  138. template<typename C, typename Socket>
  139. inline void _ws_start(std::shared_ptr<derived_t>& this_ptr, std::shared_ptr<ecs_t<C>>& ecs, Socket& socket)
  140. {
  141. super::_ws_start(this_ptr, ecs, socket);
  142. this->derived().ws_stream().binary(true);
  143. }
  144. template<typename DeferEvent>
  145. inline void _handle_disconnect(const error_code& ec, std::shared_ptr<derived_t> this_ptr, DeferEvent chain)
  146. {
  147. while (!this->reqs_.empty())
  148. {
  149. auto& fn = this->reqs_.begin()->second;
  150. fn(rpc::make_error_code(rpc::error::operation_aborted), std::string_view{});
  151. }
  152. super::_handle_disconnect(ec, std::move(this_ptr), std::move(chain));
  153. }
  154. template<typename C>
  155. inline void _fire_recv(
  156. std::shared_ptr<derived_t>& this_ptr, std::shared_ptr<ecs_t<C>>& ecs, std::string_view data)
  157. {
  158. data = detail::call_data_filter_before_recv(this->derived(), data);
  159. this->listener_.notify(event_type::recv, data);
  160. this->derived()._rpc_handle_recv(this_ptr, ecs, data);
  161. }
  162. protected:
  163. detail::rpc_serializer serializer_;
  164. detail::rpc_deserializer deserializer_;
  165. detail::rpc_header header_;
  166. };
  167. }
  168. namespace asio2
  169. {
  170. namespace detail
  171. {
  172. template<asio2::net_protocol np> struct template_args_rpc_client;
  173. template<>
  174. struct template_args_rpc_client<asio2::net_protocol::udp> : public template_args_udp_client
  175. {
  176. static constexpr asio2::net_protocol net_protocol = asio2::net_protocol::udp;
  177. static constexpr bool rdc_call_cp_enabled = false;
  178. static constexpr std::size_t function_storage_size = 72;
  179. };
  180. template<>
  181. struct template_args_rpc_client<asio2::net_protocol::tcp> : public template_args_tcp_client
  182. {
  183. static constexpr asio2::net_protocol net_protocol = asio2::net_protocol::tcp;
  184. static constexpr bool rdc_call_cp_enabled = false;
  185. static constexpr std::size_t function_storage_size = 72;
  186. };
  187. template<>
  188. struct template_args_rpc_client<asio2::net_protocol::ws> : public template_args_ws_client
  189. {
  190. static constexpr asio2::net_protocol net_protocol = asio2::net_protocol::ws;
  191. static constexpr bool rdc_call_cp_enabled = false;
  192. static constexpr std::size_t function_storage_size = 72;
  193. };
  194. }
  195. using rpc_client_args_udp = detail::template_args_rpc_client<asio2::net_protocol::udp>;
  196. using rpc_client_args_tcp = detail::template_args_rpc_client<asio2::net_protocol::tcp>;
  197. using rpc_client_args_ws = detail::template_args_rpc_client<asio2::net_protocol::ws >;
  198. template<class derived_t, class executor_t>
  199. using rpc_client_impl_t = detail::rpc_client_impl_t<derived_t, executor_t>;
  200. template<class derived_t, asio2::net_protocol np> class rpc_client_t;
  201. template<class derived_t>
  202. class rpc_client_t<derived_t, asio2::net_protocol::udp> : public detail::rpc_client_impl_t<derived_t,
  203. detail::udp_client_impl_t<derived_t, detail::template_args_rpc_client<asio2::net_protocol::udp>>>
  204. {
  205. public:
  206. using detail::rpc_client_impl_t<derived_t, detail::udp_client_impl_t
  207. <derived_t, detail::template_args_rpc_client<asio2::net_protocol::udp>>>::rpc_client_impl_t;
  208. };
  209. template<class derived_t>
  210. class rpc_client_t<derived_t, asio2::net_protocol::tcp> : public detail::rpc_client_impl_t<derived_t,
  211. detail::tcp_client_impl_t<derived_t, detail::template_args_rpc_client<asio2::net_protocol::tcp>>>
  212. {
  213. public:
  214. using detail::rpc_client_impl_t<derived_t, detail::tcp_client_impl_t
  215. <derived_t, detail::template_args_rpc_client<asio2::net_protocol::tcp>>>::rpc_client_impl_t;
  216. };
  217. template<class derived_t>
  218. class rpc_client_t<derived_t, asio2::net_protocol::ws> : public detail::rpc_client_impl_t<derived_t,
  219. detail::ws_client_impl_t<derived_t, detail::template_args_rpc_client<asio2::net_protocol::ws>>>
  220. {
  221. public:
  222. using detail::rpc_client_impl_t<derived_t, detail::ws_client_impl_t<derived_t,
  223. detail::template_args_rpc_client<asio2::net_protocol::ws>>>::rpc_client_impl_t;
  224. };
  225. template<asio2::net_protocol np>
  226. class rpc_client_use : public rpc_client_t<rpc_client_use<np>, np>
  227. {
  228. public:
  229. using rpc_client_t<rpc_client_use<np>, np>::rpc_client_t;
  230. };
  231. using rpc_tcp_client = rpc_client_use<asio2::net_protocol::tcp>;
  232. using rpc_ws_client = rpc_client_use<asio2::net_protocol::ws>;
  233. using rpc_kcp_client = rpc_client_use<asio2::net_protocol::udp>;
  234. #if !defined(ASIO2_USE_WEBSOCKET_RPC)
  235. /// Using tcp dgram mode as the underlying communication support
  236. using rpc_client = rpc_client_use<asio2::net_protocol::tcp>;
  237. #else
  238. /// Using websocket as the underlying communication support
  239. using rpc_client = rpc_client_use<asio2::net_protocol::ws>;
  240. #endif
  241. }
  242. #if defined(ASIO2_INCLUDE_RATE_LIMIT)
  243. #include <asio2/tcp/tcp_stream.hpp>
  244. namespace asio2
  245. {
  246. struct rpc_rate_client_args_tcp : public rpc_client_args_tcp
  247. {
  248. using socket_t = asio2::tcp_stream<asio2::simple_rate_policy>;
  249. };
  250. struct rpc_rate_client_args_ws : public rpc_client_args_ws
  251. {
  252. using socket_t = asio2::tcp_stream<asio2::simple_rate_policy>;
  253. using stream_t = websocket::stream<socket_t&>;
  254. };
  255. template<class derived_t, asio2::net_protocol np> class rpc_rate_client_t;
  256. template<class derived_t>
  257. class rpc_rate_client_t<derived_t, asio2::net_protocol::tcp> : public detail::rpc_client_impl_t<derived_t,
  258. detail::tcp_client_impl_t<derived_t, rpc_rate_client_args_tcp>>
  259. {
  260. public:
  261. using detail::rpc_client_impl_t<derived_t,
  262. detail::tcp_client_impl_t<derived_t, rpc_rate_client_args_tcp>>::rpc_client_impl_t;
  263. };
  264. template<class derived_t>
  265. class rpc_rate_client_t<derived_t, asio2::net_protocol::ws> : public detail::rpc_client_impl_t<derived_t,
  266. detail::ws_client_impl_t<derived_t, rpc_rate_client_args_ws>>
  267. {
  268. public:
  269. using detail::rpc_client_impl_t<derived_t,
  270. detail::ws_client_impl_t<derived_t, rpc_rate_client_args_ws>>::rpc_client_impl_t;
  271. };
  272. template<asio2::net_protocol np>
  273. class rpc_rate_client_use : public rpc_rate_client_t<rpc_rate_client_use<np>, np>
  274. {
  275. public:
  276. using rpc_rate_client_t<rpc_rate_client_use<np>, np>::rpc_rate_client_t;
  277. };
  278. #if !defined(ASIO2_USE_WEBSOCKET_RPC)
  279. /// Using tcp dgram mode as the underlying communication support
  280. using rpc_rate_client = rpc_rate_client_use<asio2::net_protocol::tcp>;
  281. #else
  282. /// Using websocket as the underlying communication support
  283. using rpc_rate_client = rpc_rate_client_use<asio2::net_protocol::ws>;
  284. #endif
  285. }
  286. #endif
  287. #include <asio2/base/detail/pop_options.hpp>
  288. #endif
  289. #endif // !__ASIO2_RPC_CLIENT_HPP__