safe call

This commit is contained in:
qicosmos
2025-09-02 09:59:47 +08:00
parent 85f07e20ec
commit 165108e1c8
3 changed files with 64 additions and 15 deletions
+25 -3
View File
@@ -197,6 +197,11 @@ struct dummy1 {
MSGPACK_DEFINE(id, str); MSGPACK_DEFINE(id, str);
}; };
std::string echo(rpc_conn conn, const std::string &src);
struct dummy {
int add(rpc_conn conn, int a, int b);
};
void test_echo() { void test_echo() {
rpc_client client("127.0.0.1", 9000); rpc_client client("127.0.0.1", 9000);
bool r = client.connect(); bool r = client.connect();
@@ -212,10 +217,27 @@ void test_echo() {
} }
{ {
auto result = client.call<std::string>("echo", "test"); // safe call, same with `client.call<std::string>("echo", "test")`
auto result = client.call<echo>("test");
std::cout << result << std::endl; std::cout << result << std::endl;
} }
{
// safe call member function
auto result = client.call<&dummy::add>(1, 2);
std::cout << result << std::endl;
}
{
client.async_call(
"echo",
[](const asio::error_code &ec, string_view data) {
auto str = as<std::string>(data);
std::cout << "echo " << str << '\n';
},
"test");
}
{ {
auto result = client.call<std::string>("delay_echo", "test"); auto result = client.call<std::string>("delay_echo", "test");
std::cout << result << std::endl; std::cout << result << std::endl;
@@ -637,8 +659,8 @@ void benchmark_test() {
int main() { int main() {
// benchmark_test(); // benchmark_test();
test_connect(); // test_connect();
test_callback(); // test_callback();
test_echo(); test_echo();
test_sync_client(); test_sync_client();
test_async_client(); test_async_client();
+15 -2
View File
@@ -66,11 +66,15 @@ struct function_traits<std::function<Ret(Args...)>>
template <typename ReturnType, typename ClassType, typename... Args> template <typename ReturnType, typename ClassType, typename... Args>
struct function_traits<ReturnType (ClassType::*)(Args...)> struct function_traits<ReturnType (ClassType::*)(Args...)>
: function_traits<ReturnType(Args...)> {}; : function_traits<ReturnType(Args...)> {
using class_type = ClassType;
};
template <typename ReturnType, typename ClassType, typename... Args> template <typename ReturnType, typename ClassType, typename... Args>
struct function_traits<ReturnType (ClassType::*)(Args...) const> struct function_traits<ReturnType (ClassType::*)(Args...) const>
: function_traits<ReturnType(Args...)> {}; : function_traits<ReturnType(Args...)> {
using class_type = ClassType;
};
template <typename Callable> template <typename Callable>
struct function_traits : function_traits<decltype(&Callable::operator())> {}; struct function_traits : function_traits<decltype(&Callable::operator())> {};
@@ -114,6 +118,15 @@ using nth_type_of = nonstd::tuple_element_t<N, std::tuple<Args...>>;
template <typename... Args> template <typename... Args>
using last_type_of = nth_type_of<sizeof...(Args) - 1, Args...>; using last_type_of = nth_type_of<sizeof...(Args) - 1, Args...>;
template <typename T> struct remove_first { using type = T; };
template <class First, class... Second>
struct remove_first<std::tuple<First, Second...>> {
using type = std::tuple<Second...>;
};
template <typename T> using remove_first_t = typename remove_first<T>::type;
} // namespace rest_rpc } // namespace rest_rpc
#endif // REST_RPC_META_UTIL_HPP #endif // REST_RPC_META_UTIL_HPP
+24 -10
View File
@@ -1,6 +1,7 @@
#pragma once #pragma once
#include "client_util.hpp" #include "client_util.hpp"
#include "const_vars.h" #include "const_vars.h"
#include "function_name.h"
#include "md5.hpp" #include "md5.hpp"
#include "meta_util.hpp" #include "meta_util.hpp"
#include "use_asio.hpp" #include "use_asio.hpp"
@@ -216,7 +217,7 @@ public:
// sync call // sync call
template <size_t TIMEOUT, typename T = void, typename... Args> template <size_t TIMEOUT, typename T = void, typename... Args>
typename std::enable_if<std::is_void<T>::value>::type typename std::enable_if<std::is_void<T>::value>::type
call(const std::string &rpc_name, Args &&...args) { call(std::string_view rpc_name, Args &&...args) {
auto future_result = auto future_result =
async_call<FUTURE>(rpc_name, std::forward<Args>(args)...); async_call<FUTURE>(rpc_name, std::forward<Args>(args)...);
auto status = future_result.wait_for(std::chrono::milliseconds(TIMEOUT)); auto status = future_result.wait_for(std::chrono::milliseconds(TIMEOUT));
@@ -230,13 +231,13 @@ public:
template <typename T = void, typename... Args> template <typename T = void, typename... Args>
typename std::enable_if<std::is_void<T>::value>::type typename std::enable_if<std::is_void<T>::value>::type
call(const std::string &rpc_name, Args &&...args) { call(std::string_view rpc_name, Args &&...args) {
call<DEFAULT_TIMEOUT, T>(rpc_name, std::forward<Args>(args)...); call<DEFAULT_TIMEOUT, T>(rpc_name, std::forward<Args>(args)...);
} }
template <size_t TIMEOUT, typename T, typename... Args> template <size_t TIMEOUT, typename T, typename... Args>
typename std::enable_if<!std::is_void<T>::value, T>::type typename std::enable_if<!std::is_void<T>::value, T>::type
call(const std::string &rpc_name, Args &&...args) { call(std::string_view rpc_name, Args &&...args) {
auto future_result = auto future_result =
async_call<FUTURE>(rpc_name, std::forward<Args>(args)...); async_call<FUTURE>(rpc_name, std::forward<Args>(args)...);
auto status = future_result.wait_for(std::chrono::milliseconds(TIMEOUT)); auto status = future_result.wait_for(std::chrono::milliseconds(TIMEOUT));
@@ -250,12 +251,23 @@ public:
template <typename T, typename... Args> template <typename T, typename... Args>
typename std::enable_if<!std::is_void<T>::value, T>::type typename std::enable_if<!std::is_void<T>::value, T>::type
call(const std::string &rpc_name, Args &&...args) { call(std::string_view rpc_name, Args &&...args) {
return call<DEFAULT_TIMEOUT, T>(rpc_name, std::forward<Args>(args)...); return call<DEFAULT_TIMEOUT, T>(rpc_name, std::forward<Args>(args)...);
} }
template <auto func, typename... Args> auto call(Args &&...args) {
using args_tuple = typename function_traits<decltype(func)>::tuple_type;
static_assert(std::is_constructible_v<remove_first_t<args_tuple>, Args...>,
"called rpc function and arguments are not match");
constexpr auto rpc_name = get_func_name<func>();
using R = typename function_traits<decltype(func)>::return_type;
return call<R>(rpc_name, std::forward<Args>(args)...);
}
template <CallModel model, typename... Args> template <CallModel model, typename... Args>
future_result<req_result> async_call(const std::string &rpc_name, future_result<req_result> async_call(std::string_view rpc_name,
Args &&...args) { Args &&...args) {
auto p = std::make_shared<std::promise<req_result>>(); auto p = std::make_shared<std::promise<req_result>>();
std::future<req_result> future = p->get_future(); std::future<req_result> future = p->get_future();
@@ -271,7 +283,7 @@ public:
rpc_service::msgpack_codec codec; rpc_service::msgpack_codec codec;
auto ret = codec.pack_args(std::forward<Args>(args)...); auto ret = codec.pack_args(std::forward<Args>(args)...);
write(fu_id, request_type::req_res, std::move(ret), write(fu_id, request_type::req_res, std::move(ret),
MD5::MD5Hash32(rpc_name.data())); MD5::MD5Hash32(rpc_name.data(), rpc_name.length()));
return future_result<req_result>{fu_id, std::move(future)}; return future_result<req_result>{fu_id, std::move(future)};
} }
@@ -292,12 +304,13 @@ public:
sbuffer.write(encoded_func_name_and_args.data(), sbuffer.write(encoded_func_name_and_args.data(),
encoded_func_name_and_args.size()); encoded_func_name_and_args.size());
write(fu_id, request_type::req_res, std::move(sbuffer), write(fu_id, request_type::req_res, std::move(sbuffer),
MD5::MD5Hash32(encoded_func_name_and_args.data())); MD5::MD5Hash32(encoded_func_name_and_args.data(),
encoded_func_name_and_args.length()));
return fu_id; return fu_id;
} }
template <size_t TIMEOUT = DEFAULT_TIMEOUT, typename... Args> template <size_t TIMEOUT = DEFAULT_TIMEOUT, typename... Args>
void async_call(const std::string &rpc_name, void async_call(std::string_view rpc_name,
std::function<void(asio::error_code, string_view)> cb, std::function<void(asio::error_code, string_view)> cb,
Args &&...args) { Args &&...args) {
if (!has_connected_) { if (!has_connected_) {
@@ -321,7 +334,7 @@ public:
rpc_service::msgpack_codec codec; rpc_service::msgpack_codec codec;
auto ret = codec.pack_args(std::forward<Args>(args)...); auto ret = codec.pack_args(std::forward<Args>(args)...);
write(cb_id, request_type::req_res, std::move(ret), write(cb_id, request_type::req_res, std::move(ret),
MD5::MD5Hash32(rpc_name.data())); MD5::MD5Hash32(rpc_name.data(), rpc_name.length()));
} }
void stop() { void stop() {
@@ -580,7 +593,8 @@ private:
void send_subscribe(const std::string &key, const std::string &token) { void send_subscribe(const std::string &key, const std::string &token) {
rpc_service::msgpack_codec codec; rpc_service::msgpack_codec codec;
auto ret = codec.pack_args(key, token); auto ret = codec.pack_args(key, token);
write(0, request_type::sub_pub, std::move(ret), MD5::MD5Hash32(key.data())); write(0, request_type::sub_pub, std::move(ret),
MD5::MD5Hash32(key.data(), key.length()));
} }
void resend_subscribe() { void resend_subscribe() {