router.h 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #ifndef REST_RPC_ROUTER_H_
  2. #define REST_RPC_ROUTER_H_
  3. #include <functional>
  4. #include "use_asio.hpp"
  5. #include "codec.h"
  6. #include "meta_util.hpp"
  7. namespace rest_rpc {
  8. enum class ExecMode { sync, async };
  9. const constexpr ExecMode Async = ExecMode::async;
  10. namespace rpc_service {
  11. class connection;
  12. class router : asio::noncopyable {
  13. public:
  14. static router& get() {
  15. static router instance;
  16. return instance;
  17. }
  18. template<ExecMode model, typename Function>
  19. void register_handler(std::string const& name, Function f) {
  20. return register_nonmember_func<model>(name, std::move(f));
  21. }
  22. template<ExecMode model, typename Function, typename Self>
  23. void register_handler(std::string const& name, const Function& f, Self* self) {
  24. return register_member_func<model>(name, f, self);
  25. }
  26. void remove_handler(std::string const& name) { this->map_invokers_.erase(name); }
  27. template<typename T>
  28. void route(const char* data, std::size_t size, std::weak_ptr<T> conn) {
  29. auto conn_sp = conn.lock();
  30. if (!conn_sp) {
  31. return;
  32. }
  33. auto req_id = conn_sp->request_id();
  34. std::string result;
  35. try {
  36. msgpack_codec codec;
  37. auto p = codec.unpack<std::tuple<std::string>>(data, size);
  38. auto& func_name = std::get<0>(p);
  39. auto it = map_invokers_.find(func_name);
  40. if (it == map_invokers_.end()) {
  41. result = codec.pack_args_str(result_code::FAIL, "unknown function: " + func_name);
  42. conn_sp->response(req_id, std::move(result));
  43. return;
  44. }
  45. ExecMode model;
  46. it->second(conn, data, size, result, model);
  47. if (model == ExecMode::sync) {
  48. if (result.size() >= MAX_BUF_LEN) {
  49. result = codec.pack_args_str(result_code::FAIL, "the response result is out of range: more than 10M " + func_name);
  50. }
  51. conn_sp->response(req_id, std::move(result));
  52. }
  53. }
  54. catch (const std::exception & ex) {
  55. msgpack_codec codec;
  56. result = codec.pack_args_str(result_code::FAIL, ex.what());
  57. conn_sp->response(req_id, std::move(result));
  58. }
  59. }
  60. router() = default;
  61. private:
  62. router(const router&) = delete;
  63. router(router&&) = delete;
  64. template<typename F, size_t... I, typename Arg, typename... Args>
  65. static typename std::result_of<F(std::weak_ptr<connection>, Args...)>::type call_helper(
  66. const F & f, const std::index_sequence<I...>&, std::tuple<Arg, Args...> tup, std::weak_ptr<connection> ptr) {
  67. return f(ptr, std::move(std::get<I + 1>(tup))...);
  68. }
  69. template<typename F, typename Arg, typename... Args>
  70. static
  71. typename std::enable_if<std::is_void<typename std::result_of<F(std::weak_ptr<connection>, Args...)>::type>::value>::type
  72. call(const F & f, std::weak_ptr<connection> ptr, std::string & result, std::tuple<Arg, Args...> tp) {
  73. call_helper(f, std::make_index_sequence<sizeof...(Args)>{}, std::move(tp), ptr);
  74. result = msgpack_codec::pack_args_str(result_code::OK);
  75. }
  76. template<typename F, typename Arg, typename... Args>
  77. static
  78. typename std::enable_if<!std::is_void<typename std::result_of<F(std::weak_ptr<connection>, Args...)>::type>::value>::type
  79. call(const F & f, std::weak_ptr<connection> ptr, std::string & result, std::tuple<Arg, Args...> tp) {
  80. auto r = call_helper(f, std::make_index_sequence<sizeof...(Args)>{}, std::move(tp), ptr);
  81. msgpack_codec codec;
  82. result = msgpack_codec::pack_args_str(result_code::OK, r);
  83. }
  84. template<typename F, typename Self, size_t... Indexes, typename Arg, typename... Args>
  85. static typename std::result_of<F(Self, std::weak_ptr<connection>, Args...)>::type call_member_helper(
  86. const F & f, Self * self, const std::index_sequence<Indexes...>&,
  87. std::tuple<Arg, Args...> tup, std::weak_ptr<connection> ptr = std::shared_ptr<connection>{ nullptr }) {
  88. return (*self.*f)(ptr, std::move(std::get<Indexes + 1>(tup))...);
  89. }
  90. template<typename F, typename Self, typename Arg, typename... Args>
  91. static typename std::enable_if<
  92. std::is_void<typename std::result_of<F(Self, std::weak_ptr<connection>, Args...)>::type>::value>::type
  93. call_member(const F & f, Self * self, std::weak_ptr<connection> ptr, std::string & result,
  94. std::tuple<Arg, Args...> tp) {
  95. call_member_helper(f, self, typename std::make_index_sequence<sizeof...(Args)>{}, std::move(tp), ptr);
  96. result = msgpack_codec::pack_args_str(result_code::OK);
  97. }
  98. template<typename F, typename Self, typename Arg, typename... Args>
  99. static typename std::enable_if<
  100. !std::is_void<typename std::result_of<F(Self, std::weak_ptr<connection>, Args...)>::type>::value>::type
  101. call_member(const F & f, Self * self, std::weak_ptr<connection> ptr, std::string & result,
  102. std::tuple<Arg, Args...> tp) {
  103. auto r =
  104. call_member_helper(f, self, typename std::make_index_sequence<sizeof...(Args)>{}, std::move(tp), ptr);
  105. result = msgpack_codec::pack_args_str(result_code::OK, r);
  106. }
  107. template<typename Function, ExecMode mode = ExecMode::sync>
  108. struct invoker {
  109. template<ExecMode model>
  110. static inline void apply(const Function& func, std::weak_ptr<connection> conn, const char* data, size_t size,
  111. std::string& result, ExecMode& exe_model) {
  112. using args_tuple = typename function_traits<Function>::args_tuple_2nd;
  113. exe_model = ExecMode::sync;
  114. msgpack_codec codec;
  115. try {
  116. auto tp = codec.unpack<args_tuple>(data, size);
  117. call(func, conn, result, std::move(tp));
  118. exe_model = model;
  119. }
  120. catch (std::invalid_argument & e) {
  121. result = codec.pack_args_str(result_code::FAIL, e.what());
  122. }
  123. catch (const std::exception & e) {
  124. result = codec.pack_args_str(result_code::FAIL, e.what());
  125. }
  126. }
  127. template<ExecMode model, typename Self>
  128. static inline void apply_member(const Function& func, Self* self, std::weak_ptr<connection> conn,
  129. const char* data, size_t size, std::string& result,
  130. ExecMode& exe_model) {
  131. using args_tuple = typename function_traits<Function>::args_tuple_2nd;
  132. exe_model = ExecMode::sync;
  133. msgpack_codec codec;
  134. try {
  135. auto tp = codec.unpack<args_tuple>(data, size);
  136. call_member(func, self, conn, result, std::move(tp));
  137. exe_model = model;
  138. }
  139. catch (std::invalid_argument & e) {
  140. result = codec.pack_args_str(result_code::FAIL, e.what());
  141. }
  142. catch (const std::exception & e) {
  143. result = codec.pack_args_str(result_code::FAIL, e.what());
  144. }
  145. }
  146. };
  147. template<ExecMode model, typename Function>
  148. void register_nonmember_func(std::string const& name, Function f) {
  149. this->map_invokers_[name] = { std::bind(&invoker<Function>::template apply<model>, std::move(f), std::placeholders::_1,
  150. std::placeholders::_2, std::placeholders::_3,
  151. std::placeholders::_4, std::placeholders::_5) };
  152. }
  153. template<ExecMode model, typename Function, typename Self>
  154. void register_member_func(const std::string& name, const Function& f, Self* self) {
  155. this->map_invokers_[name] = { std::bind(&invoker<Function>::template apply_member<model, Self>,
  156. f, self, std::placeholders::_1, std::placeholders::_2,
  157. std::placeholders::_3, std::placeholders::_4,
  158. std::placeholders::_5) };
  159. }
  160. std::unordered_map<std::string,
  161. std::function<void(std::weak_ptr<connection>, const char*, size_t, std::string&, ExecMode& model)>>
  162. map_invokers_;
  163. };
  164. } // namespace rpc_service
  165. } // namespace rest_rpc
  166. #endif // REST_RPC_ROUTER_H_