rpc_protocol.hpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  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_PROTOCOL_HPP__
  11. #define __ASIO2_RPC_PROTOCOL_HPP__
  12. #if defined(_MSC_VER) && (_MSC_VER >= 1200)
  13. #pragma once
  14. #endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
  15. #include <string>
  16. #include <string_view>
  17. #include <asio2/base/detail/util.hpp>
  18. #include <asio2/rpc/detail/rpc_serialization.hpp>
  19. namespace asio2::detail
  20. {
  21. struct use_tcp {};
  22. struct use_websocket {};
  23. /*
  24. * request : message type + request id + function name + parameters value...
  25. * response : message type + request id + function name + error code + result value
  26. *
  27. * message type : q - request, p - response
  28. *
  29. * if result type is void, then result type will wrapped to std::int8_t
  30. */
  31. static constexpr char rpc_type_req = 'q';
  32. static constexpr char rpc_type_rep = 'p';
  33. class rpc_header
  34. {
  35. public:
  36. using id_type = std::uint64_t;
  37. rpc_header() noexcept {}
  38. rpc_header(char type, id_type id, std::string_view name)
  39. : type_(type), id_(id), name_(name) {}
  40. ~rpc_header() = default;
  41. rpc_header(const rpc_header& r) : type_(r.type_), id_(r.id_), name_(r.name_) {}
  42. rpc_header(rpc_header&& r) noexcept : type_(r.type_), id_(r.id_), name_(std::move(r.name_)) {}
  43. inline rpc_header& operator=(const rpc_header& r)
  44. {
  45. type_ = r.type_;
  46. id_ = r.id_;
  47. name_ = r.name_;
  48. return (*this);
  49. }
  50. inline rpc_header& operator=(rpc_header&& r) noexcept
  51. {
  52. type_ = r.type_;
  53. id_ = r.id_;
  54. name_ = std::move(r.name_);
  55. return (*this);
  56. }
  57. //template <class Archive>
  58. //inline void serialize(Archive & ar)
  59. //{
  60. // ar(type_, id_, name_);
  61. //}
  62. template <class Archive>
  63. void save(Archive & ar) const
  64. {
  65. ar(type_, id_, name_);
  66. }
  67. template <class Archive>
  68. void load(Archive & ar)
  69. {
  70. ar(type_, id_, name_);
  71. }
  72. inline char type() const noexcept { return this->type_; }
  73. inline id_type id () const noexcept { return this->id_; }
  74. inline const std::string& name() const noexcept { return this->name_; }
  75. inline char get_type() const noexcept { return this->type_; }
  76. inline id_type get_id () const noexcept { return this->id_; }
  77. inline const std::string& get_name() const noexcept { return this->name_; }
  78. inline bool is_request () const noexcept { return this->type_ == rpc_type_req; }
  79. inline bool is_response() const noexcept { return this->type_ == rpc_type_rep; }
  80. inline rpc_header& type(char type ) noexcept { this->type_ = type; return (*this); }
  81. inline rpc_header& id (id_type id ) noexcept { this->id_ = id ; return (*this); }
  82. inline rpc_header& name(std::string_view name) { this->name_ = name; return (*this); }
  83. inline rpc_header& set_type(char type ) noexcept { this->type_ = type; return (*this); }
  84. inline rpc_header& set_id (id_type id ) noexcept { this->id_ = id ; return (*this); }
  85. inline rpc_header& set_name(std::string_view name) { this->name_ = name; return (*this); }
  86. protected:
  87. char type_;
  88. id_type id_ = 0;
  89. std::string name_;
  90. };
  91. template<class ...Args>
  92. class rpc_request : public rpc_header
  93. {
  94. protected:
  95. template<class T>
  96. struct value_t
  97. {
  98. using type = T;
  99. };
  100. template<class... Ts>
  101. struct value_t<std::basic_string_view<Ts...>>
  102. {
  103. using type = typename std::basic_string_view<Ts...>::value_type;
  104. };
  105. template<class T>
  106. struct result_t
  107. {
  108. // if the parameters of rpc calling is raw pointer like char* , must convert it to std::string
  109. // if the parameters of rpc calling is std::string_view , must convert it to std::string
  110. // if the parameters of rpc calling is reference like std::string& , must remove it's
  111. // reference to std::string
  112. using ncvr_type = std::remove_cv_t<std::remove_reference_t<T>>;
  113. using char_type = std::remove_cv_t<std::remove_reference_t<
  114. std::remove_all_extents_t<std::remove_pointer_t<ncvr_type>>>>;
  115. using type = std::conditional_t<
  116. (std::is_pointer_v<ncvr_type> || std::is_array_v<ncvr_type>) && (
  117. std::is_same_v<char_type, std::string::value_type> ||
  118. std::is_same_v<char_type, std::wstring::value_type> ||
  119. std::is_same_v<char_type, std::u16string::value_type> ||
  120. std::is_same_v<char_type, std::u32string::value_type>)
  121. , std::basic_string<char_type>
  122. , std::conditional_t<is_template_instance_of_v<std::basic_string_view, ncvr_type>
  123. , std::basic_string<typename value_t<ncvr_type>::type>
  124. , ncvr_type>>;
  125. };
  126. public:
  127. rpc_request() noexcept : rpc_header() { this->type_ = rpc_type_req; }
  128. // can't use tp_(std::forward_as_tuple(std::forward<Args>(args)...))
  129. // if use tp_(std::forward_as_tuple(std::forward<Args>(args)...)),
  130. // when the args is nlohmann::json and under gcc 9.4.0, the json::object
  131. // maybe changed to json::array, like this:
  132. // {"name":"hello","age":10} will changed to [{"name":"hello","age":10}]
  133. // i don't why?
  134. rpc_request(std::string_view name, Args&&... args)
  135. : rpc_header(rpc_type_req, 0, name), tp_(std::forward<Args>(args)...) {}
  136. rpc_request(id_type id, std::string_view name, Args&&... args)
  137. : rpc_header(rpc_type_req, id, name), tp_(std::forward<Args>(args)...) {}
  138. ~rpc_request() = default;
  139. rpc_request(const rpc_request& r) : rpc_header(r), tp_(r.tp_) {}
  140. rpc_request(rpc_request&& r) noexcept : rpc_header(std::move(r)), tp_(std::move(r.tp_)) {}
  141. inline rpc_request& operator=(const rpc_request& r)
  142. {
  143. static_cast<rpc_header&>(*this) = r;
  144. tp_ = r.tp_;
  145. return (*this);
  146. }
  147. inline rpc_request& operator=(rpc_request&& r) noexcept
  148. {
  149. static_cast<rpc_header&>(*this) = std::move(r);
  150. tp_ = std::move(r.tp_);
  151. return (*this);
  152. }
  153. //template <class Archive>
  154. //void serialize(Archive & ar)
  155. //{
  156. // ar(cereal::base_class<rpc_header>(this));
  157. // detail::for_each_tuple(tp_, [&ar](auto& elem) mutable
  158. // {
  159. // ar(elem);
  160. // });
  161. //}
  162. template <class Archive>
  163. void save(Archive & ar) const
  164. {
  165. ar(cereal::base_class<rpc_header>(this));
  166. detail::for_each_tuple(tp_, [&ar](const auto& elem) mutable
  167. {
  168. ar << elem;
  169. });
  170. }
  171. template <class Archive>
  172. void load(Archive & ar)
  173. {
  174. ar(cereal::base_class<rpc_header>(this));
  175. detail::for_each_tuple(tp_, [&ar](auto& elem) mutable
  176. {
  177. ar >> elem;
  178. });
  179. }
  180. protected:
  181. std::tuple<typename result_t<Args>::type...> tp_;
  182. };
  183. template<class T>
  184. class rpc_response : public rpc_header
  185. {
  186. public:
  187. rpc_response() noexcept : rpc_header() { this->type_ = rpc_type_rep; }
  188. rpc_response(id_type id, std::string_view name) : rpc_header(rpc_type_rep, id, name) {}
  189. rpc_response(id_type id, std::string_view name, const error_code& ec, T&& ret)
  190. : rpc_header(rpc_type_rep, id, name), ec_(ec), ret_(std::forward<T>(ret)) {}
  191. ~rpc_response() = default;
  192. rpc_response(const rpc_response& r)
  193. : rpc_header(r), ec_(r.ec_), ret_(r.ret_) {}
  194. rpc_response(rpc_response&& r) noexcept
  195. : rpc_header(std::move(r)), ec_(std::move(r.ec_)), ret_(std::move(r.ret_)) {}
  196. inline rpc_response& operator=(const rpc_response& r)
  197. {
  198. static_cast<rpc_header&>(*this) = r;
  199. ec_ = r.ec_;
  200. ret_ = r.ret_;
  201. return (*this);
  202. }
  203. inline rpc_response& operator=(rpc_response&& r) noexcept
  204. {
  205. static_cast<rpc_header&>(*this) = std::move(r);
  206. ec_ = std::move(r.ec_);
  207. ret_ = std::move(r.ret_);
  208. return (*this);
  209. }
  210. //template <class Archive>
  211. //void serialize(Archive & ar)
  212. //{
  213. // ar(cereal::base_class<rpc_header>(this));
  214. // ar(ec_.value());
  215. // ar(ret_);
  216. //}
  217. template <class Archive>
  218. void save(Archive & ar) const
  219. {
  220. ar << cereal::base_class<rpc_header>(this);
  221. ar << ec_.value();
  222. ar << ret_;
  223. }
  224. template <class Archive>
  225. void load(Archive & ar)
  226. {
  227. ar >> cereal::base_class<rpc_header>(this);
  228. ar >> ec_.value();
  229. ar >> ret_;
  230. }
  231. protected:
  232. error_code ec_;
  233. T ret_;
  234. };
  235. }
  236. #endif // !__ASIO2_RPC_PROTOCOL_HPP__