rpc_server.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  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_SERVER_HPP__
  11. #define __ASIO2_RPC_SERVER_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_server.hpp>
  19. #include <asio2/tcp/tcp_server.hpp>
  20. #include <asio2/tcp/tcps_server.hpp>
  21. #include <asio2/http/ws_server.hpp>
  22. #include <asio2/http/wss_server.hpp>
  23. #include <asio2/rpc/rpc_session.hpp>
  24. namespace asio2::detail
  25. {
  26. ASIO2_CLASS_FORWARD_DECLARE_BASE;
  27. ASIO2_CLASS_FORWARD_DECLARE_UDP_BASE;
  28. ASIO2_CLASS_FORWARD_DECLARE_UDP_SERVER;
  29. ASIO2_CLASS_FORWARD_DECLARE_TCP_BASE;
  30. ASIO2_CLASS_FORWARD_DECLARE_TCP_SERVER;
  31. template<class derived_t, class executor_t>
  32. class rpc_server_impl_t
  33. : public executor_t
  34. , public rpc_invoker_t<typename executor_t::session_type, typename executor_t::session_type::args_type>
  35. {
  36. friend executor_t;
  37. ASIO2_CLASS_FRIEND_DECLARE_BASE;
  38. ASIO2_CLASS_FRIEND_DECLARE_UDP_BASE;
  39. ASIO2_CLASS_FRIEND_DECLARE_UDP_SERVER;
  40. ASIO2_CLASS_FRIEND_DECLARE_TCP_BASE;
  41. ASIO2_CLASS_FRIEND_DECLARE_TCP_SERVER;
  42. public:
  43. using super = executor_t;
  44. using self = rpc_server_impl_t<derived_t, executor_t>;
  45. using executor_type = executor_t;
  46. using session_type = typename super::session_type;
  47. protected:
  48. using super::async_send;
  49. public:
  50. /**
  51. * @brief constructor
  52. */
  53. template<class ...Args>
  54. explicit rpc_server_impl_t(
  55. Args&&... args
  56. )
  57. : super(std::forward<Args>(args)...)
  58. , rpc_invoker_t<typename executor_t::session_type, typename executor_t::session_type::args_type>()
  59. {
  60. }
  61. /**
  62. * @brief destructor
  63. */
  64. ~rpc_server_impl_t()
  65. {
  66. this->stop();
  67. }
  68. /**
  69. * @brief start the server
  70. * @param host - A string identifying a location. May be a descriptive name or
  71. * a numeric address string.
  72. * @param service - A string identifying the requested service. This may be a
  73. * descriptive name or a numeric string corresponding to a port number.
  74. */
  75. template<typename String, typename StrOrInt, typename... Args>
  76. inline bool start(String&& host, StrOrInt&& service, Args&&... args)
  77. {
  78. if constexpr (is_websocket_server<executor_t>::value)
  79. {
  80. return executor_t::template start(
  81. std::forward<String>(host), std::forward<StrOrInt>(service),
  82. std::forward<Args>(args)...);
  83. }
  84. else if constexpr (session_type::net_protocol == asio2::net_protocol::udp)
  85. {
  86. return executor_t::template start(
  87. std::forward<String>(host), std::forward<StrOrInt>(service),
  88. asio2::use_kcp, std::forward<Args>(args)...);
  89. }
  90. else
  91. {
  92. return executor_t::template start(
  93. std::forward<String>(host), std::forward<StrOrInt>(service),
  94. asio2::use_dgram, std::forward<Args>(args)...);
  95. }
  96. }
  97. public:
  98. /**
  99. * @brief call a rpc function for each session
  100. */
  101. template<class return_t, class Rep, class Period, class ...Args>
  102. inline void call(std::chrono::duration<Rep, Period> timeout, const std::string& name, const Args&... args)
  103. {
  104. this->sessions_.for_each([&](std::shared_ptr<session_type>& session_ptr) mutable
  105. {
  106. session_ptr->template call<return_t>(timeout, name, args...);
  107. });
  108. }
  109. /**
  110. * @brief call a rpc function for each session
  111. */
  112. template<class return_t, class ...Args>
  113. inline void call(const std::string& name, const Args&... args)
  114. {
  115. this->sessions_.for_each([&](std::shared_ptr<session_type>& session_ptr) mutable
  116. {
  117. session_ptr->template call<return_t>(name, args...);
  118. });
  119. }
  120. /**
  121. * @brief asynchronous call a rpc function for each session
  122. * Callback signature : void(return_t result)
  123. * if result type is void, the Callback signature is : void()
  124. * Because the result value type is not specified in the first template parameter,
  125. * so the result value type must be specified in the Callback lambda.
  126. */
  127. template<class Callback, class ...Args>
  128. inline typename std::enable_if_t<is_callable_v<Callback>, void>
  129. async_call(const Callback& fn, const std::string& name, const Args&... args)
  130. {
  131. this->sessions_.quick_for_each([&](std::shared_ptr<session_type>& session_ptr) mutable
  132. {
  133. session_ptr->async_call(fn, name, args...);
  134. });
  135. }
  136. /**
  137. * @brief asynchronous call a rpc function for each session
  138. * Callback signature : void(return_t result)
  139. * if result type is void, the Callback signature is : void()
  140. * Because the result value type is not specified in the first template parameter,
  141. * so the result value type must be specified in the Callback lambda
  142. */
  143. template<class Callback, class Rep, class Period, class ...Args>
  144. inline typename std::enable_if_t<is_callable_v<Callback>, void>
  145. async_call(const Callback& fn, std::chrono::duration<Rep, Period> timeout,
  146. const std::string& name, const Args&... args)
  147. {
  148. this->sessions_.quick_for_each([&](std::shared_ptr<session_type>& session_ptr) mutable
  149. {
  150. session_ptr->async_call(fn, timeout, name, args...);
  151. });
  152. }
  153. /**
  154. * @brief asynchronous call a rpc function for each session
  155. * Callback signature : void(return_t result) the return_t
  156. * is the first template parameter.
  157. * if result type is void, the Callback signature is : void()
  158. */
  159. template<class return_t, class Callback, class ...Args>
  160. inline void async_call(const Callback& fn, const std::string& name, const Args&... args)
  161. {
  162. this->sessions_.quick_for_each([&](std::shared_ptr<session_type>& session_ptr) mutable
  163. {
  164. session_ptr->template async_call<return_t>(fn, name, args...);
  165. });
  166. }
  167. /**
  168. * @brief asynchronous call a rpc function for each session
  169. * Callback signature : void(return_t result) the return_t
  170. * is the first template parameter.
  171. * if result type is void, the Callback signature is : void()
  172. */
  173. template<class return_t, class Callback, class Rep, class Period, class ...Args>
  174. inline void async_call(const Callback& fn, std::chrono::duration<Rep, Period> timeout,
  175. const std::string& name, const Args&... args)
  176. {
  177. this->sessions_.quick_for_each([&](std::shared_ptr<session_type>& session_ptr) mutable
  178. {
  179. session_ptr->template async_call<return_t>(fn, timeout, name, args...);
  180. });
  181. }
  182. /**
  183. * @brief asynchronous call a rpc function for each session
  184. * Don't care whether the call succeeds
  185. */
  186. template<class ...Args>
  187. inline void async_call(const std::string& name, const Args&... args)
  188. {
  189. this->sessions_.quick_for_each([&](std::shared_ptr<session_type>& session_ptr) mutable
  190. {
  191. session_ptr->async_call(name, args...);
  192. });
  193. }
  194. protected:
  195. template<typename... Args>
  196. inline std::shared_ptr<session_type> _make_session(Args&&... args)
  197. {
  198. return super::_make_session(std::forward<Args>(args)..., *this);
  199. }
  200. protected:
  201. };
  202. }
  203. namespace asio2
  204. {
  205. template<class derived_t, class session_t, asio2::net_protocol np = session_t::net_protocol>
  206. class rpc_server_impl_t;
  207. template<class derived_t, class session_t>
  208. class rpc_server_impl_t<derived_t, session_t, asio2::net_protocol::udp>
  209. : public detail::rpc_server_impl_t<derived_t, detail::udp_server_impl_t<derived_t, session_t>>
  210. {
  211. public:
  212. using detail::rpc_server_impl_t<derived_t, detail::udp_server_impl_t<derived_t, session_t>>::
  213. rpc_server_impl_t;
  214. };
  215. template<class derived_t, class session_t>
  216. class rpc_server_impl_t<derived_t, session_t, asio2::net_protocol::tcp>
  217. : public detail::rpc_server_impl_t<derived_t, detail::tcp_server_impl_t<derived_t, session_t>>
  218. {
  219. public:
  220. using detail::rpc_server_impl_t<derived_t, detail::tcp_server_impl_t<derived_t, session_t>>::
  221. rpc_server_impl_t;
  222. };
  223. template<class derived_t, class session_t>
  224. class rpc_server_impl_t<derived_t, session_t, asio2::net_protocol::ws>
  225. : public detail::rpc_server_impl_t<derived_t, detail::ws_server_impl_t<derived_t, session_t>>
  226. {
  227. public:
  228. using detail::rpc_server_impl_t<derived_t, detail::ws_server_impl_t<derived_t, session_t>>::
  229. rpc_server_impl_t;
  230. };
  231. template<class session_t>
  232. class rpc_server_t : public rpc_server_impl_t<rpc_server_t<session_t>, session_t>
  233. {
  234. public:
  235. using rpc_server_impl_t<rpc_server_t<session_t>, session_t>::rpc_server_impl_t;
  236. };
  237. template<asio2::net_protocol np>
  238. class rpc_server_use : public rpc_server_t<rpc_session_use<np>>
  239. {
  240. public:
  241. using rpc_server_t<rpc_session_use<np>>::rpc_server_t;
  242. };
  243. using rpc_tcp_server = rpc_server_use<asio2::net_protocol::tcp>;
  244. using rpc_ws_server = rpc_server_use<asio2::net_protocol::ws>;
  245. using rpc_kcp_server = rpc_server_use<asio2::net_protocol::udp>;
  246. #if !defined(ASIO2_USE_WEBSOCKET_RPC)
  247. /// Using tcp dgram mode as the underlying communication support
  248. using rpc_server = rpc_server_use<asio2::net_protocol::tcp>;
  249. #else
  250. /// Using websocket as the underlying communication support
  251. using rpc_server = rpc_server_use<asio2::net_protocol::ws>;
  252. #endif
  253. }
  254. #if defined(ASIO2_INCLUDE_RATE_LIMIT)
  255. #include <asio2/tcp/tcp_stream.hpp>
  256. namespace asio2
  257. {
  258. template<class derived_t, class session_t, asio2::net_protocol np = session_t::net_protocol>
  259. class rpc_rate_server_impl_t;
  260. template<class derived_t, class session_t>
  261. class rpc_rate_server_impl_t<derived_t, session_t, asio2::net_protocol::tcp>
  262. : public detail::rpc_server_impl_t<derived_t, detail::tcp_server_impl_t<derived_t, session_t>>
  263. {
  264. public:
  265. using detail::rpc_server_impl_t<derived_t, detail::tcp_server_impl_t<derived_t, session_t>>::
  266. rpc_server_impl_t;
  267. };
  268. template<class derived_t, class session_t>
  269. class rpc_rate_server_impl_t<derived_t, session_t, asio2::net_protocol::ws>
  270. : public detail::rpc_server_impl_t<derived_t, detail::ws_server_impl_t<derived_t, session_t>>
  271. {
  272. public:
  273. using detail::rpc_server_impl_t<derived_t, detail::ws_server_impl_t<derived_t, session_t>>::
  274. rpc_server_impl_t;
  275. };
  276. template<class session_t>
  277. class rpc_rate_server_t : public rpc_rate_server_impl_t<rpc_rate_server_t<session_t>, session_t>
  278. {
  279. public:
  280. using rpc_rate_server_impl_t<rpc_rate_server_t<session_t>, session_t>::rpc_rate_server_impl_t;
  281. };
  282. template<asio2::net_protocol np>
  283. class rpc_rate_server_use : public rpc_rate_server_t<rpc_rate_session_use<np>>
  284. {
  285. public:
  286. using rpc_rate_server_t<rpc_rate_session_use<np>>::rpc_rate_server_t;
  287. };
  288. #if !defined(ASIO2_USE_WEBSOCKET_RPC)
  289. /// Using tcp dgram mode as the underlying communication support
  290. using rpc_rate_server = rpc_rate_server_use<asio2::net_protocol::tcp>;
  291. #else
  292. /// Using websocket as the underlying communication support
  293. using rpc_rate_server = rpc_rate_server_use<asio2::net_protocol::ws>;
  294. #endif
  295. }
  296. #endif
  297. #include <asio2/base/detail/pop_options.hpp>
  298. #endif
  299. #endif // !__ASIO2_RPC_SERVER_HPP__