mirror of
https://github.com/qicosmos/rest_rpc.git
synced 2026-08-29 08:34:47 +08:00
reg coro
This commit is contained in:
@@ -4,7 +4,6 @@
|
||||
namespace rest_rpc {
|
||||
template<typename Coro>
|
||||
inline auto async_start(auto executor, Coro &&coro) {
|
||||
|
||||
using R = typename std::remove_cvref_t<std::invoke_result_t<Coro>>::value_type;
|
||||
static_assert(std::is_void_v<R>);
|
||||
asio::co_spawn(executor, std::forward<Coro>(coro), asio::detached);
|
||||
|
||||
@@ -17,7 +17,8 @@ enum class rpc_errc : std::int8_t {
|
||||
resolve_timeout,
|
||||
connection_timeout,
|
||||
request_timeout,
|
||||
protocol_error
|
||||
protocol_error,
|
||||
has_response,
|
||||
};
|
||||
|
||||
class rpc_error_category : public std::error_category {
|
||||
@@ -54,6 +55,8 @@ public:
|
||||
return "request timeout";
|
||||
case rpc_errc::protocol_error:
|
||||
return "protocol error";
|
||||
case rpc_errc::has_response:
|
||||
return "has response, duplicate response is not allowed";
|
||||
default:
|
||||
return "unknown error";
|
||||
}
|
||||
|
||||
@@ -15,26 +15,28 @@ public:
|
||||
return instance;
|
||||
}
|
||||
|
||||
rpc_context(rpc_context&& o) : conn_(std::move(o.conn_)), delay_(o.delay_) {}
|
||||
rpc_context(const rpc_context& o) = delete;
|
||||
rpc_context(rpc_context &&o) : conn_(std::move(o.conn_)), delay_(o.delay_) {}
|
||||
rpc_context(const rpc_context &o) = delete;
|
||||
|
||||
void set_connection(std::shared_ptr<rpc_connection> conn) { conn_ = conn; }
|
||||
|
||||
bool delay() { return delay_; }
|
||||
|
||||
void set_delay(bool r) { context().delay_ = r; }
|
||||
|
||||
|
||||
auto get_executor();
|
||||
|
||||
template <auto func, typename... Args>
|
||||
asio::awaitable<std::error_code> response(Args &&...args);
|
||||
|
||||
template <auto func, typename... Args> std::error_code sync_response(Args &&...args);
|
||||
template <auto func, typename... Args>
|
||||
std::error_code sync_response(Args &&...args);
|
||||
|
||||
private:
|
||||
rpc_context() = default;
|
||||
std::shared_ptr<rpc_connection> conn_;
|
||||
bool delay_ = false;
|
||||
bool has_response_ = false;
|
||||
};
|
||||
|
||||
class rpc_connection : public std::enable_shared_from_this<rpc_connection> {
|
||||
@@ -80,7 +82,7 @@ public:
|
||||
|
||||
// route
|
||||
rpc_context::context().set_connection(self);
|
||||
auto result = router_.route(header.function_id, body_);
|
||||
auto result = co_await router_.route(header.function_id, body_);
|
||||
bool delay = rpc_context::context().delay();
|
||||
if (delay) {
|
||||
rpc_context::context().set_delay(false);
|
||||
@@ -129,8 +131,14 @@ private:
|
||||
template <auto func, typename... Args>
|
||||
asio::awaitable<std::error_code> rpc_context::response(Args &&...args) {
|
||||
using args_tuple = typename function_traits<decltype(func)>::return_type;
|
||||
static_assert(std::is_constructible_v<args_tuple, Args...>,
|
||||
"rpc function return type and response arguments are not match");
|
||||
static_assert(
|
||||
std::is_constructible_v<args_tuple, Args...>,
|
||||
"rpc function return type and response arguments are not match");
|
||||
if (has_response_) {
|
||||
co_return make_error_code(rpc_errc::has_response);
|
||||
}
|
||||
|
||||
has_response_ = true;
|
||||
rpc_service::msgpack_codec codec;
|
||||
rpc_result result(codec.pack_args(std::forward<Args>(args)...));
|
||||
co_return co_await conn_->response(result);
|
||||
@@ -138,10 +146,9 @@ asio::awaitable<std::error_code> rpc_context::response(Args &&...args) {
|
||||
|
||||
template <auto func, typename... Args>
|
||||
std::error_code rpc_context::sync_response(Args &&...args) {
|
||||
return sync_wait(conn_->get_executor(), response<func>(std::forward<Args>(args)...));
|
||||
return sync_wait(conn_->get_executor(),
|
||||
response<func>(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
auto rpc_context::get_executor() {
|
||||
return conn_->get_executor();
|
||||
}
|
||||
auto rpc_context::get_executor() { return conn_->get_executor(); }
|
||||
} // namespace rest_rpc
|
||||
+133
-103
@@ -10,6 +10,14 @@
|
||||
#include <string_view>
|
||||
|
||||
namespace rest_rpc {
|
||||
template <typename T>
|
||||
constexpr inline bool is_awaitable_v =
|
||||
util::is_specialization_v<std::remove_cvref_t<T>, asio::awaitable>;
|
||||
|
||||
template <typename T>
|
||||
constexpr inline bool is_void_v =
|
||||
std::is_same_v<T, void> || std::is_same_v<T, asio::awaitable<void>>;
|
||||
|
||||
struct rpc_result {
|
||||
rpc_result(std::string str) : result(std::move(str)) {}
|
||||
rpc_result(std::string_view str) : view(str) {}
|
||||
@@ -65,7 +73,7 @@ public:
|
||||
return std::to_string(key);
|
||||
}
|
||||
|
||||
rpc_result route(uint32_t key, std::string_view data) {
|
||||
asio::awaitable<rpc_result> route(uint32_t key, std::string_view data) {
|
||||
rpc_result route_result{};
|
||||
try {
|
||||
rpc_service::msgpack_codec codec;
|
||||
@@ -74,7 +82,7 @@ public:
|
||||
route_result.result = "unknown function: " + get_name_by_key(key);
|
||||
route_result.ec = rpc_errc::no_such_function;
|
||||
} else {
|
||||
it->second(data, route_result);
|
||||
co_await it->second(data, route_result);
|
||||
route_result.ec = rpc_errc::ok;
|
||||
}
|
||||
} catch (const std::exception &ex) {
|
||||
@@ -89,71 +97,39 @@ public:
|
||||
route_result.ec = rpc_errc::function_unknown_exception;
|
||||
}
|
||||
|
||||
return route_result;
|
||||
co_return route_result;
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename Function, typename Self = void>
|
||||
auto register_handler_impl(uint32_t key, std::string_view name,
|
||||
void register_handler_impl(uint32_t key, std::string_view name,
|
||||
const Function &f, Self *self = nullptr) {
|
||||
if (key2func_name_.find(key) != key2func_name_.end()) {
|
||||
throw std::invalid_argument("duplicate registration key !");
|
||||
} else {
|
||||
key2func_name_.emplace(key, name);
|
||||
if constexpr (std::is_void_v<Self>) {
|
||||
return register_nonmember_func(key, f);
|
||||
} else {
|
||||
return register_member_func(key, f, self);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Function>
|
||||
void register_nonmember_func(uint32_t key, Function f) {
|
||||
this->map_invokers_[key] = [this,
|
||||
f = std::move(f)](std::string_view str,
|
||||
rpc_result &ret) mutable {
|
||||
using args_tuple = typename function_traits<Function>::tuple_type;
|
||||
using R = typename function_traits<Function>::return_type;
|
||||
key2func_name_.emplace(key, name);
|
||||
|
||||
try {
|
||||
if constexpr (std::tuple_size_v<args_tuple> == 0) {
|
||||
handle_zero_arg<R>(f, ret);
|
||||
} else {
|
||||
using first_t = std::tuple_element_t<0, args_tuple>;
|
||||
if constexpr (std::tuple_size_v<args_tuple> == 1 &&
|
||||
util::is_basic_v<first_t>) {
|
||||
handle_one_arg<R, first_t>(str, f, ret);
|
||||
} else {
|
||||
handle_more_args<R, args_tuple>(str, f, ret);
|
||||
}
|
||||
}
|
||||
} catch (std::invalid_argument &e) {
|
||||
ret.ec = rpc_errc::invalid_argument;
|
||||
ret.result = e.what();
|
||||
} catch (const std::exception &e) {
|
||||
ret.ec = rpc_errc::function_exception;
|
||||
ret.result = e.what();
|
||||
}
|
||||
};
|
||||
register_func_impl(key, f, self);
|
||||
}
|
||||
|
||||
template <typename Function, typename Self>
|
||||
void register_member_func(uint32_t key, const Function &f, Self *self) {
|
||||
this->map_invokers_[key] = [this, f, self](std::string_view str,
|
||||
rpc_result &ret) {
|
||||
void register_func_impl(uint32_t key, const Function &f, Self *self) {
|
||||
this->map_invokers_[key] =
|
||||
[this, f, self](std::string_view str,
|
||||
rpc_result &ret) -> asio::awaitable<void> {
|
||||
using args_tuple = typename function_traits<Function>::tuple_type;
|
||||
using R = typename function_traits<Function>::return_type;
|
||||
using R = typename util::function_traits<Function>::return_type;
|
||||
try {
|
||||
if constexpr (std::tuple_size_v<args_tuple> == 0) {
|
||||
handle_zero_arg<R>(f, self, ret);
|
||||
co_await handle_zero_arg<R>(f, ret, self);
|
||||
} else {
|
||||
using first_t = std::tuple_element_t<0, args_tuple>;
|
||||
if constexpr (std::tuple_size_v<args_tuple> == 1 &&
|
||||
util::is_basic_v<first_t>) {
|
||||
handle_one_arg<R, first_t>(str, f, self, ret);
|
||||
co_await handle_one_arg<R, first_t>(str, f, ret, self);
|
||||
} else {
|
||||
handle_more_args<R, args_tuple>(str, f, self, ret);
|
||||
co_await handle_more_args<R, args_tuple>(str, f, ret, self);
|
||||
}
|
||||
}
|
||||
} catch (std::invalid_argument &e) {
|
||||
@@ -166,80 +142,134 @@ private:
|
||||
};
|
||||
}
|
||||
|
||||
template <typename R, typename F>
|
||||
void handle_zero_arg(const F &f, rpc_result &ret) {
|
||||
if constexpr (std::is_void_v<R>) {
|
||||
f();
|
||||
} else {
|
||||
ret = rpc_service::msgpack_codec::pack_args(f());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename R, typename F, typename Self>
|
||||
void handle_zero_arg(const F &f, Self *self, rpc_result &ret) {
|
||||
if constexpr (std::is_void_v<R>) {
|
||||
(*self.*f)();
|
||||
asio::awaitable<void> handle_zero_arg(const F &f, rpc_result &ret,
|
||||
Self *self) {
|
||||
if constexpr (is_void_v<R>) {
|
||||
if constexpr (std::is_void_v<Self>) {
|
||||
if constexpr (is_awaitable_v<R>) {
|
||||
co_await f();
|
||||
} else {
|
||||
f();
|
||||
}
|
||||
} else {
|
||||
if constexpr (is_awaitable_v<R>) {
|
||||
co_await (*self.*f)();
|
||||
} else {
|
||||
(*self.*f)();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = rpc_service::msgpack_codec::pack_args((*self.*f)());
|
||||
}
|
||||
}
|
||||
|
||||
template <typename R, typename Arg, typename F>
|
||||
void handle_one_arg(std::string_view str, const F &f, rpc_result &ret) {
|
||||
rpc_service::msgpack_codec codec;
|
||||
if constexpr (std::is_void_v<R>) {
|
||||
f(codec.unpack<Arg>(str));
|
||||
} else {
|
||||
ret = rpc_service::msgpack_codec::pack_args(f(codec.unpack<Arg>(str)));
|
||||
if constexpr (std::is_void_v<Self>) {
|
||||
if constexpr (is_awaitable_v<R>) {
|
||||
ret = rpc_service::msgpack_codec::pack_args(co_await f());
|
||||
} else {
|
||||
ret = rpc_service::msgpack_codec::pack_args(f());
|
||||
}
|
||||
} else {
|
||||
if constexpr (is_awaitable_v<R>) {
|
||||
ret = rpc_service::msgpack_codec::pack_args(co_await (*self.*f)());
|
||||
} else {
|
||||
ret = rpc_service::msgpack_codec::pack_args((*self.*f)());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename R, typename Arg, typename F, typename Self>
|
||||
void handle_one_arg(std::string_view str, const F &f, Self *self,
|
||||
rpc_result &ret) {
|
||||
asio::awaitable<void> handle_one_arg(std::string_view str, const F &f,
|
||||
rpc_result &ret, Self *self) {
|
||||
rpc_service::msgpack_codec codec;
|
||||
if constexpr (std::is_void_v<R>) {
|
||||
(*self.*f)(codec.unpack<Arg>(str));
|
||||
if constexpr (is_void_v<R>) {
|
||||
if constexpr (std::is_void_v<Self>) {
|
||||
if constexpr (is_awaitable_v<R>) {
|
||||
co_await f(codec.unpack<Arg>(str));
|
||||
} else {
|
||||
f(codec.unpack<Arg>(str));
|
||||
}
|
||||
} else {
|
||||
if constexpr (is_awaitable_v<R>) {
|
||||
co_await (*self.*f)(codec.unpack<Arg>(str));
|
||||
} else {
|
||||
(*self.*f)(codec.unpack<Arg>(str));
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = rpc_service::msgpack_codec::pack_args(
|
||||
(*self.*f)(codec.unpack<Arg>(str)));
|
||||
if constexpr (std::is_void_v<Self>) {
|
||||
if constexpr (is_awaitable_v<R>) {
|
||||
ret = rpc_service::msgpack_codec::pack_args(
|
||||
co_await f(codec.unpack<Arg>(str)));
|
||||
} else {
|
||||
ret =
|
||||
rpc_service::msgpack_codec::pack_args(f(codec.unpack<Arg>(str)));
|
||||
}
|
||||
} else {
|
||||
if constexpr (is_awaitable_v<R>) {
|
||||
ret = rpc_service::msgpack_codec::pack_args(
|
||||
co_await (*self.*f)(codec.unpack<Arg>(str)));
|
||||
} else {
|
||||
ret = rpc_service::msgpack_codec::pack_args(
|
||||
(*self.*f)(codec.unpack<Arg>(str)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename R, typename args_tuple, typename F>
|
||||
void handle_more_args(std::string_view str, const F &f, rpc_result &ret) {
|
||||
template <typename R, typename Args, typename F, typename Self>
|
||||
asio::awaitable<void> handle_more_args(std::string_view str, const F &f,
|
||||
rpc_result &ret, Self *self) {
|
||||
rpc_service::msgpack_codec codec;
|
||||
auto tp = codec.unpack<args_tuple>(str);
|
||||
auto tp = codec.unpack<Args>(str);
|
||||
if constexpr (std::is_void_v<R>) {
|
||||
std::apply(f, tp);
|
||||
if constexpr (std::is_void_v<Self>) {
|
||||
if constexpr (is_awaitable_v<R>) {
|
||||
co_await std::apply(f, tp);
|
||||
} else {
|
||||
std::apply(f, tp);
|
||||
}
|
||||
} else {
|
||||
if constexpr (is_awaitable_v<R>) {
|
||||
co_await std::apply(
|
||||
[self, &f](auto &&...args) {
|
||||
return (*self.*f)(std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
tp);
|
||||
} else {
|
||||
std::apply(
|
||||
[self, &f](auto &&...args) {
|
||||
return (*self.*f)(std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
tp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ret = rpc_service::msgpack_codec::pack_args(std::apply(f, tp));
|
||||
if constexpr (std::is_void_v<Self>) {
|
||||
if constexpr (is_awaitable_v<R>) {
|
||||
ret =
|
||||
rpc_service::msgpack_codec::pack_args(co_await std::apply(f, tp));
|
||||
} else {
|
||||
ret = rpc_service::msgpack_codec::pack_args(std::apply(f, tp));
|
||||
}
|
||||
} else {
|
||||
if constexpr (is_awaitable_v<R>) {
|
||||
ret = rpc_service::msgpack_codec::pack_args(co_await std::apply(
|
||||
[self, &f](auto &&...args) {
|
||||
return (*self.*f)(std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
tp));
|
||||
} else {
|
||||
ret = rpc_service::msgpack_codec::pack_args(std::apply(
|
||||
[self, &f](auto &&...args) {
|
||||
return (*self.*f)(std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
tp));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename R, typename args_tuple, typename F, typename Self>
|
||||
void handle_more_args(std::string_view str, const F &f, Self *self,
|
||||
rpc_result &ret) {
|
||||
rpc_service::msgpack_codec codec;
|
||||
auto tp = codec.unpack<args_tuple>(str);
|
||||
|
||||
if constexpr (std::is_void_v<R>) {
|
||||
std::apply(
|
||||
[self, &f](auto &&...args) {
|
||||
return (*self.*f)(std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
tp);
|
||||
} else {
|
||||
ret = rpc_service::msgpack_codec::pack_args(std::apply(
|
||||
[self, &f](auto &&...args) {
|
||||
return (*self.*f)(std::forward<decltype(args)>(args)...);
|
||||
},
|
||||
tp));
|
||||
}
|
||||
}
|
||||
|
||||
std::unordered_map<uint32_t,
|
||||
std::function<void(std::string_view, rpc_result &)>>
|
||||
std::unordered_map<uint32_t, std::function<asio::awaitable<void>(
|
||||
std::string_view, rpc_result &)>>
|
||||
map_invokers_;
|
||||
std::unordered_map<uint32_t, std::string> key2func_name_;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user