mirror of
https://github.com/qicosmos/rest_rpc.git
synced 2026-08-29 08:34:47 +08:00
string_view no copy and no serialize
This commit is contained in:
@@ -6,8 +6,10 @@
|
|||||||
#include "logger.hpp"
|
#include "logger.hpp"
|
||||||
#include "meta_util.hpp"
|
#include "meta_util.hpp"
|
||||||
#include "rest_rpc_protocol.hpp"
|
#include "rest_rpc_protocol.hpp"
|
||||||
|
#include "string_resize.hpp"
|
||||||
#include "traits.h"
|
#include "traits.h"
|
||||||
#include "use_asio.hpp"
|
#include "use_asio.hpp"
|
||||||
|
#include "util.hpp"
|
||||||
#include <asio/experimental/awaitable_operators.hpp>
|
#include <asio/experimental/awaitable_operators.hpp>
|
||||||
#include <asio/steady_timer.hpp>
|
#include <asio/steady_timer.hpp>
|
||||||
using namespace asio::experimental::awaitable_operators;
|
using namespace asio::experimental::awaitable_operators;
|
||||||
@@ -18,6 +20,10 @@ template <typename R> struct call_result {
|
|||||||
R value;
|
R value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <> struct call_result<void> {
|
||||||
|
rpc_errc ec;
|
||||||
|
};
|
||||||
|
|
||||||
class client {
|
class client {
|
||||||
public:
|
public:
|
||||||
client() : socket_(get_global_executor()) {}
|
client() : socket_(get_global_executor()) {}
|
||||||
@@ -121,7 +127,9 @@ private:
|
|||||||
std::vector<asio::const_buffer> buffers;
|
std::vector<asio::const_buffer> buffers;
|
||||||
buffers.reserve(2);
|
buffers.reserve(2);
|
||||||
buffers.push_back(asio::buffer(&header, sizeof(rest_rpc_header)));
|
buffers.push_back(asio::buffer(&header, sizeof(rest_rpc_header)));
|
||||||
|
if constexpr (sizeof...(Args) > 0) {
|
||||||
buffers.push_back(asio::buffer(buf.data(), buf.size()));
|
buffers.push_back(asio::buffer(buf.data(), buf.size()));
|
||||||
|
}
|
||||||
|
|
||||||
using R = typename function_traits<decltype(func)>::return_type;
|
using R = typename function_traits<decltype(func)>::return_type;
|
||||||
call_result<R> result{};
|
call_result<R> result{};
|
||||||
@@ -150,14 +158,19 @@ private:
|
|||||||
|
|
||||||
detail::resize(body_, resp_header.body_len);
|
detail::resize(body_, resp_header.body_len);
|
||||||
std::tie(ec, size) = co_await asio::async_read(
|
std::tie(ec, size) = co_await asio::async_read(
|
||||||
socket_, asio::buffer(body_), asio::as_tuple(asio::use_awaitable));
|
socket_, asio::buffer(body_.data(), body_.size()),
|
||||||
|
asio::as_tuple(asio::use_awaitable));
|
||||||
if (ec) {
|
if (ec) {
|
||||||
REST_LOG_WARNING << "read body error: " << ec.message();
|
REST_LOG_WARNING << "read body error: " << ec.message();
|
||||||
result.ec = rpc_errc::read_error;
|
result.ec = rpc_errc::read_error;
|
||||||
co_return result;
|
co_return result;
|
||||||
}
|
}
|
||||||
result.ec = (rpc_errc)body_[0];
|
result.ec = (rpc_errc)body_[0];
|
||||||
result.value = codec.unpack<R>(body_.data() + 1, resp_header.body_len - 1);
|
if constexpr (!std::is_void_v<R>) {
|
||||||
|
result.value = codec.unpack<R>(
|
||||||
|
std::string_view(body_.data() + 1, resp_header.body_len - 1));
|
||||||
|
}
|
||||||
|
|
||||||
co_return result;
|
co_return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,20 +1,37 @@
|
|||||||
#ifndef REST_RPC_CODEC_H_
|
#ifndef REST_RPC_CODEC_H_
|
||||||
#define REST_RPC_CODEC_H_
|
#define REST_RPC_CODEC_H_
|
||||||
|
|
||||||
|
#include "traits.h"
|
||||||
|
#include <charconv>
|
||||||
#include <msgpack.hpp>
|
#include <msgpack.hpp>
|
||||||
|
|
||||||
namespace rest_rpc {
|
namespace rest_rpc {
|
||||||
namespace rpc_service {
|
namespace rpc_service {
|
||||||
|
|
||||||
|
template <typename Arg> auto pack_one(Arg &&arg) {
|
||||||
|
if constexpr (util::CharArrayRef<Arg> || util::CharArray<Arg> ||
|
||||||
|
util::string<Arg>) {
|
||||||
|
return std::string_view(std::forward<Arg>(arg));
|
||||||
|
} else {
|
||||||
|
return std::to_string(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
using buffer_type = msgpack::sbuffer;
|
using buffer_type = msgpack::sbuffer;
|
||||||
struct msgpack_codec {
|
struct msgpack_codec {
|
||||||
const static size_t init_size = 2 * 1024;
|
const static size_t init_size = 2 * 1024;
|
||||||
|
|
||||||
template <typename... Args> static buffer_type pack_args(Args &&...args) {
|
template <typename... Args> static auto pack_args(Args &&...args) {
|
||||||
|
if constexpr (sizeof...(Args) == 0) {
|
||||||
|
return std::string_view{};
|
||||||
|
} else if constexpr (sizeof...(Args) == 1 && util::is_basic_v<Args...>) {
|
||||||
|
return pack_one(std::forward<Args>(args)...);
|
||||||
|
} else {
|
||||||
buffer_type buffer(init_size);
|
buffer_type buffer(init_size);
|
||||||
msgpack::pack(buffer, std::forward_as_tuple(std::forward<Args>(args)...));
|
msgpack::pack(buffer, std::forward_as_tuple(std::forward<Args>(args)...));
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <typename Arg> static std::string pack_to_string(Arg &arg) {
|
template <typename Arg> static std::string pack_to_string(Arg &arg) {
|
||||||
buffer_type buffer(init_size);
|
buffer_type buffer(init_size);
|
||||||
@@ -46,6 +63,23 @@ struct msgpack_codec {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T> T unpack(std::string_view data) {
|
||||||
|
if constexpr (std::is_fundamental_v<T>) {
|
||||||
|
T t;
|
||||||
|
auto r = std::from_chars(data.data(), data.data() + data.size(), t);
|
||||||
|
if (r.ec != std::errc()) {
|
||||||
|
throw std::invalid_argument("unpack failed: Args not match!");
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
} else if constexpr (std::is_same_v<std::string, T>) {
|
||||||
|
return std::string(data);
|
||||||
|
} else if constexpr (std::is_same_v<std::string_view, T>) {
|
||||||
|
return data;
|
||||||
|
} else {
|
||||||
|
return unpack<T>(data.data(), data.size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
msgpack::unpacked msg_;
|
msgpack::unpacked msg_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -79,7 +79,8 @@ auto apply_helper(F &&f, Tuple &&tp, nonstd::index_sequence<Idx...>)
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename F, typename Tuple>
|
template <typename F, typename Tuple>
|
||||||
auto apply(F &&f, Tuple &&tp) -> decltype(apply_helper(
|
auto apply(F &&f, Tuple &&tp)
|
||||||
|
-> decltype(apply_helper(
|
||||||
std::forward<F>(f), std::forward<Tuple>(tp),
|
std::forward<F>(f), std::forward<Tuple>(tp),
|
||||||
make_index_sequence<std::tuple_size<decay_t<Tuple>>::value>{})) {
|
make_index_sequence<std::tuple_size<decay_t<Tuple>>::value>{})) {
|
||||||
return apply_helper(
|
return apply_helper(
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ struct function_traits<Ret(Arg, Args...)> {
|
|||||||
public:
|
public:
|
||||||
enum { arity = sizeof...(Args) + 1 };
|
enum { arity = sizeof...(Args) + 1 };
|
||||||
typedef Ret function_type(Arg, Args...);
|
typedef Ret function_type(Arg, Args...);
|
||||||
typedef Ret return_type;
|
typedef std::remove_cvref_t<Ret> return_type;
|
||||||
using stl_function_type = std::function<function_type>;
|
using stl_function_type = std::function<function_type>;
|
||||||
typedef Ret (*pointer)(Arg, Args...);
|
typedef Ret (*pointer)(Arg, Args...);
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ template <typename Ret> struct function_traits<Ret()> {
|
|||||||
public:
|
public:
|
||||||
enum { arity = 0 };
|
enum { arity = 0 };
|
||||||
typedef Ret function_type();
|
typedef Ret function_type();
|
||||||
typedef Ret return_type;
|
typedef std::remove_cvref_t<Ret> return_type;
|
||||||
using stl_function_type = std::function<function_type>;
|
using stl_function_type = std::function<function_type>;
|
||||||
typedef Ret (*pointer)();
|
typedef Ret (*pointer)();
|
||||||
|
|
||||||
@@ -123,7 +123,9 @@ 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 <typename T> struct remove_first {
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
template <class First, class... Second>
|
template <class First, class... Second>
|
||||||
struct remove_first<std::tuple<First, Second...>> {
|
struct remove_first<std::tuple<First, Second...>> {
|
||||||
|
|||||||
@@ -387,7 +387,9 @@ using std::tr1::add_const;
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
template <class T> struct add_const { typedef const T type; };
|
template <class T> struct add_const {
|
||||||
|
typedef const T type;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // any_HAVE_ADD_CONST
|
#endif // any_HAVE_ADD_CONST
|
||||||
|
|
||||||
@@ -401,8 +403,12 @@ using std::tr1::remove_reference;
|
|||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
template <class T> struct remove_reference { typedef T type; };
|
template <class T> struct remove_reference {
|
||||||
template <class T> struct remove_reference<T &> { typedef T type; };
|
typedef T type;
|
||||||
|
};
|
||||||
|
template <class T> struct remove_reference<T &> {
|
||||||
|
typedef T type;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // any_HAVE_REMOVE_REFERENCE
|
#endif // any_HAVE_REMOVE_REFERENCE
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,14 @@
|
|||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
inline uint64_t htonll(uint64_t value) {
|
||||||
|
return ((uint64_t)htonl(value & 0xFFFFFFFF) << 32) | htonl(value >> 32);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline uint64_t ntohll(uint64_t value) {
|
||||||
|
return ((uint64_t)ntohl(value & 0xFFFFFFFF) << 32) | ntohl(value >> 32);
|
||||||
|
}
|
||||||
|
|
||||||
namespace rest_rpc {
|
namespace rest_rpc {
|
||||||
inline constexpr uint8_t REST_MAGIC_NUM = 39;
|
inline constexpr uint8_t REST_MAGIC_NUM = 39;
|
||||||
struct rest_rpc_header {
|
struct rest_rpc_header {
|
||||||
|
|||||||
@@ -32,24 +32,29 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
detail::resize(body_, header.body_len);
|
detail::resize(body_, header.body_len);
|
||||||
|
|
||||||
|
if (header.body_len > 0) {
|
||||||
std::tie(ec, size) = co_await asio::async_read(
|
std::tie(ec, size) = co_await asio::async_read(
|
||||||
socket_, asio::buffer(body_), asio::as_tuple(asio::use_awaitable));
|
socket_, asio::buffer(body_), asio::as_tuple(asio::use_awaitable));
|
||||||
if (ec) {
|
if (ec) {
|
||||||
REST_LOG_WARNING << "read body error: " << ec.message();
|
REST_LOG_WARNING << "read body error: " << ec.message();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// route
|
// route
|
||||||
auto result = router_.route(header.function_id, body_);
|
auto result = router_.route(header.function_id, body_);
|
||||||
rest_rpc_header resp_header{};
|
rest_rpc_header resp_header{};
|
||||||
resp_header.magic = 39;
|
resp_header.magic = 39;
|
||||||
resp_header.body_len = result.result.size() + 1;
|
resp_header.body_len = result.size() + 1;
|
||||||
prepare_for_send(resp_header);
|
prepare_for_send(resp_header);
|
||||||
std::vector<asio::const_buffer> buffers;
|
std::vector<asio::const_buffer> buffers;
|
||||||
buffers.reserve(3);
|
buffers.reserve(3);
|
||||||
buffers.push_back(asio::buffer(&resp_header, sizeof(rest_rpc_header)));
|
buffers.push_back(asio::buffer(&resp_header, sizeof(rest_rpc_header)));
|
||||||
buffers.push_back(asio::buffer(&result.ec, 1));
|
buffers.push_back(asio::buffer(&result.ec, 1));
|
||||||
buffers.push_back(asio::buffer(result.result));
|
if (!result.empty())
|
||||||
|
buffers.push_back(asio::buffer(result.data()));
|
||||||
|
|
||||||
std::tie(ec, size) = co_await asio::async_write(
|
std::tie(ec, size) = co_await asio::async_write(
|
||||||
socket_, buffers, asio::as_tuple(asio::use_awaitable));
|
socket_, buffers, asio::as_tuple(asio::use_awaitable));
|
||||||
if (ec) {
|
if (ec) {
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "codec.h"
|
#include "codec.h"
|
||||||
#include "error_code.h"
|
#include "error_code.h"
|
||||||
#include "function_name.h"
|
|
||||||
#include "md5.hpp"
|
|
||||||
#include "meta_util.hpp"
|
#include "meta_util.hpp"
|
||||||
|
#include "util.hpp"
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
@@ -13,13 +13,12 @@ namespace rest_rpc {
|
|||||||
struct rpc_result {
|
struct rpc_result {
|
||||||
rpc_errc ec = rpc_errc::ok;
|
rpc_errc ec = rpc_errc::ok;
|
||||||
std::string result;
|
std::string result;
|
||||||
};
|
std::string_view view;
|
||||||
|
bool empty() { return result.empty() && view.empty(); }
|
||||||
|
size_t size() { return result.empty() ? view.size() : result.size(); }
|
||||||
|
|
||||||
template <auto func> constexpr uint32_t get_key() {
|
std::string_view data() { return result.empty() ? view : result; }
|
||||||
constexpr auto name = get_func_name<func>();
|
};
|
||||||
constexpr uint32_t key = MD5::MD5Hash32(name.data(), name.length());
|
|
||||||
return key;
|
|
||||||
}
|
|
||||||
|
|
||||||
class rpc_router {
|
class rpc_router {
|
||||||
public:
|
public:
|
||||||
@@ -57,30 +56,28 @@ public:
|
|||||||
|
|
||||||
rpc_result route(uint32_t key, std::string_view data) {
|
rpc_result route(uint32_t key, std::string_view data) {
|
||||||
rpc_result route_result{};
|
rpc_result route_result{};
|
||||||
std::string result;
|
|
||||||
try {
|
try {
|
||||||
rpc_service::msgpack_codec codec;
|
rpc_service::msgpack_codec codec;
|
||||||
auto it = map_invokers_.find(key);
|
auto it = map_invokers_.find(key);
|
||||||
if (it == map_invokers_.end()) {
|
if (it == map_invokers_.end()) {
|
||||||
result = "unknown function: " + get_name_by_key(key);
|
route_result.result = "unknown function: " + get_name_by_key(key);
|
||||||
route_result.ec = rpc_errc::no_such_function;
|
route_result.ec = rpc_errc::no_such_function;
|
||||||
} else {
|
} else {
|
||||||
it->second(data, route_result.ec, result);
|
it->second(data, route_result);
|
||||||
route_result.ec = rpc_errc::ok;
|
route_result.ec = rpc_errc::ok;
|
||||||
}
|
}
|
||||||
} catch (const std::exception &ex) {
|
} catch (const std::exception &ex) {
|
||||||
rpc_service::msgpack_codec codec;
|
rpc_service::msgpack_codec codec;
|
||||||
result = std::string("exception occur when call").append(ex.what());
|
route_result.result =
|
||||||
|
std::string("exception occur when call").append(ex.what());
|
||||||
route_result.ec = rpc_errc::function_exception;
|
route_result.ec = rpc_errc::function_exception;
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
rpc_service::msgpack_codec codec;
|
rpc_service::msgpack_codec codec;
|
||||||
result = std::string("unknown exception occur when call ")
|
route_result.result = std::string("unknown exception occur when call ")
|
||||||
.append(get_name_by_key(key));
|
.append(get_name_by_key(key));
|
||||||
route_result.ec = rpc_errc::function_unknown_exception;
|
route_result.ec = rpc_errc::function_unknown_exception;
|
||||||
}
|
}
|
||||||
|
|
||||||
route_result.result = std::move(result);
|
|
||||||
|
|
||||||
return route_result;
|
return route_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,38 +100,86 @@ private:
|
|||||||
template <typename Function>
|
template <typename Function>
|
||||||
void register_nonmember_func(uint32_t key, Function f) {
|
void register_nonmember_func(uint32_t key, Function f) {
|
||||||
this->map_invokers_[key] = [f = std::move(f)](std::string_view str,
|
this->map_invokers_[key] = [f = std::move(f)](std::string_view str,
|
||||||
rpc_errc &ec,
|
rpc_result &ret) mutable {
|
||||||
std::string &result) mutable {
|
|
||||||
using args_tuple = typename function_traits<Function>::tuple_type;
|
using args_tuple = typename function_traits<Function>::tuple_type;
|
||||||
using R = typename function_traits<Function>::return_type;
|
using R = typename function_traits<Function>::return_type;
|
||||||
rpc_service::msgpack_codec codec;
|
|
||||||
try {
|
try {
|
||||||
auto tp = codec.unpack<args_tuple>(str.data(), str.size());
|
if constexpr (std::tuple_size_v<args_tuple> == 0) {
|
||||||
|
if constexpr (std::is_void_v<R>) {
|
||||||
|
f();
|
||||||
|
} else {
|
||||||
|
auto r = f();
|
||||||
|
ret.result = rpc_service::msgpack_codec::pack_to_string(r);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
rpc_service::msgpack_codec codec;
|
||||||
|
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>) {
|
||||||
|
if constexpr (std::is_void_v<R>) {
|
||||||
|
f(codec.unpack<first_t>(str));
|
||||||
|
} else {
|
||||||
|
if constexpr (std::is_same_v<std::string_view, R>) {
|
||||||
|
ret.view = rpc_service::msgpack_codec::pack_args(
|
||||||
|
f(codec.unpack<first_t>(str)));
|
||||||
|
} else {
|
||||||
|
ret.result = rpc_service::msgpack_codec::pack_args(
|
||||||
|
f(codec.unpack<first_t>(str)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto tp = codec.unpack<args_tuple>(str);
|
||||||
if constexpr (std::is_void_v<R>) {
|
if constexpr (std::is_void_v<R>) {
|
||||||
std::apply(f, tp);
|
std::apply(f, tp);
|
||||||
} else {
|
} else {
|
||||||
auto r = std::apply(f, tp);
|
auto r = std::apply(f, tp);
|
||||||
result = rpc_service::msgpack_codec::pack_to_string(r);
|
ret.result = rpc_service::msgpack_codec::pack_to_string(r);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (std::invalid_argument &e) {
|
} catch (std::invalid_argument &e) {
|
||||||
ec = rpc_errc::invalid_argument;
|
ret.ec = rpc_errc::invalid_argument;
|
||||||
result = e.what();
|
ret.result = e.what();
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
ec = rpc_errc::function_exception;
|
ret.ec = rpc_errc::function_exception;
|
||||||
result = e.what();
|
ret.result = e.what();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Function, typename Self>
|
template <typename Function, typename Self>
|
||||||
void register_member_func(uint32_t key, const Function &f, Self *self) {
|
void register_member_func(uint32_t key, const Function &f, Self *self) {
|
||||||
this->map_invokers_[key] = [f, self](std::string_view str, rpc_errc &ec,
|
this->map_invokers_[key] = [f, self](std::string_view str,
|
||||||
std::string &result) {
|
rpc_result &ret) {
|
||||||
using args_tuple = typename function_traits<Function>::tuple_type;
|
using args_tuple = typename function_traits<Function>::tuple_type;
|
||||||
using R = typename function_traits<Function>::return_type;
|
using R = typename function_traits<Function>::return_type;
|
||||||
rpc_service::msgpack_codec codec;
|
rpc_service::msgpack_codec codec;
|
||||||
try {
|
try {
|
||||||
auto tp = codec.unpack<args_tuple>(str.data(), str.size());
|
if constexpr (std::tuple_size_v<args_tuple> == 0) {
|
||||||
|
if constexpr (std::is_void_v<R>) {
|
||||||
|
(*self.*f)();
|
||||||
|
} else {
|
||||||
|
auto r = (*self.*f)();
|
||||||
|
ret.result = rpc_service::msgpack_codec::pack_to_string(r);
|
||||||
|
}
|
||||||
|
} 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>) {
|
||||||
|
if constexpr (std::is_void_v<R>) {
|
||||||
|
(*self.*f)(codec.unpack<first_t>(str));
|
||||||
|
} else {
|
||||||
|
if constexpr (std::is_same_v<std::string_view, R>) {
|
||||||
|
ret.view = rpc_service::msgpack_codec::pack_args(
|
||||||
|
(*self.*f)(codec.unpack<first_t>(str)));
|
||||||
|
} else {
|
||||||
|
ret.result = rpc_service::msgpack_codec::pack_args(
|
||||||
|
(*self.*f)(codec.unpack<first_t>(str)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
auto tp = codec.unpack<args_tuple>(str);
|
||||||
|
|
||||||
if constexpr (std::is_void_v<R>) {
|
if constexpr (std::is_void_v<R>) {
|
||||||
std::apply(
|
std::apply(
|
||||||
@@ -148,20 +193,23 @@ private:
|
|||||||
return (*self.*f)(std::forward<decltype(args)>(args)...);
|
return (*self.*f)(std::forward<decltype(args)>(args)...);
|
||||||
},
|
},
|
||||||
tp);
|
tp);
|
||||||
result = rpc_service::msgpack_codec::pack_to_string(r);
|
ret.result = rpc_service::msgpack_codec::pack_to_string(r);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} catch (std::invalid_argument &e) {
|
} catch (std::invalid_argument &e) {
|
||||||
ec = rpc_errc::invalid_argument;
|
ret.ec = rpc_errc::invalid_argument;
|
||||||
result = e.what();
|
ret.result = e.what();
|
||||||
} catch (const std::exception &e) {
|
} catch (const std::exception &e) {
|
||||||
ec = rpc_errc::function_exception;
|
ret.ec = rpc_errc::function_exception;
|
||||||
result = e.what();
|
ret.result = e.what();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unordered_map<uint32_t, std::function<void(std::string_view, rpc_errc &,
|
std::unordered_map<uint32_t,
|
||||||
std::string &)>>
|
std::function<void(std::string_view, rpc_result &)>>
|
||||||
map_invokers_;
|
map_invokers_;
|
||||||
std::unordered_map<uint32_t, std::string> key2func_name_;
|
std::unordered_map<uint32_t, std::string> key2func_name_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -145,7 +145,9 @@ struct is_invocable
|
|||||||
template <typename F, typename... Args>
|
template <typename F, typename... Args>
|
||||||
inline constexpr bool is_invocable_v = is_invocable<F, Args...>::value;
|
inline constexpr bool is_invocable_v = is_invocable<F, Args...>::value;
|
||||||
|
|
||||||
template <typename T> struct remove_first { using type = T; };
|
template <typename T> struct remove_first {
|
||||||
|
using type = T;
|
||||||
|
};
|
||||||
|
|
||||||
template <class First, class... Second>
|
template <class First, class... Second>
|
||||||
struct remove_first<std::tuple<First, Second...>> {
|
struct remove_first<std::tuple<First, Second...>> {
|
||||||
@@ -171,4 +173,44 @@ struct is_specialization<Ref<Args...>, Ref> : std::true_type {};
|
|||||||
|
|
||||||
template <typename Test, template <typename...> class Ref>
|
template <typename Test, template <typename...> class Ref>
|
||||||
inline constexpr bool is_specialization_v = is_specialization<Test, Ref>::value;
|
inline constexpr bool is_specialization_v = is_specialization<Test, Ref>::value;
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
concept container = requires(Type container) {
|
||||||
|
typename std::remove_cvref_t<Type>::value_type;
|
||||||
|
container.size();
|
||||||
|
container.begin();
|
||||||
|
container.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
constexpr bool is_char_t =
|
||||||
|
std::is_same_v<Type, signed char> || std::is_same_v<Type, char> ||
|
||||||
|
std::is_same_v<Type, unsigned char> || std::is_same_v<Type, wchar_t> ||
|
||||||
|
std::is_same_v<Type, char16_t> || std::is_same_v<Type, char32_t>
|
||||||
|
#ifdef __cpp_lib_char8_t
|
||||||
|
|| std::is_same_v<Type, char8_t>
|
||||||
|
#endif
|
||||||
|
;
|
||||||
|
|
||||||
|
template <typename Type>
|
||||||
|
concept string = container<Type> && requires(Type container) {
|
||||||
|
requires is_char_t<typename std::remove_cvref_t<Type>::value_type>;
|
||||||
|
container.length();
|
||||||
|
container.data();
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept CharArrayRef = requires {
|
||||||
|
requires std::is_array_v<std::remove_reference_t<T>> &&
|
||||||
|
std::same_as<std::remove_extent_t<std::remove_cvref_t<T>>, char>;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
concept CharArray =
|
||||||
|
std::is_array_v<std::remove_reference_t<T>> &&
|
||||||
|
std::same_as<std::remove_extent_t<std::remove_cvref_t<T>>, char>;
|
||||||
|
|
||||||
|
template <typename T, typename...>
|
||||||
|
inline constexpr bool is_basic_v =
|
||||||
|
std::is_fundamental_v<T> || string<T> || CharArray<T> || CharArrayRef<T>;
|
||||||
} // namespace rest_rpc::util
|
} // namespace rest_rpc::util
|
||||||
|
|||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "function_name.h"
|
||||||
|
#include "md5.hpp"
|
||||||
|
|
||||||
|
namespace rest_rpc {
|
||||||
|
template <auto func> constexpr uint32_t get_key() {
|
||||||
|
constexpr auto name = get_func_name<func>();
|
||||||
|
constexpr uint32_t key = MD5::MD5Hash32(name.data(), name.length());
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
} // namespace rest_rpc
|
||||||
@@ -12,21 +12,48 @@ struct dummy {
|
|||||||
int add(int a, int b) { return a + b; }
|
int add(int a, int b) { return a + b; }
|
||||||
|
|
||||||
void foo(std::string str) { std::cout << str << "\n"; }
|
void foo(std::string str) { std::cout << str << "\n"; }
|
||||||
|
|
||||||
|
std::string echo(std::string val) { return val; }
|
||||||
|
|
||||||
|
int round1(int i) { return i; }
|
||||||
};
|
};
|
||||||
|
|
||||||
int add(int a, int b) { return a + b; }
|
int add(int a, int b) { return a + b; }
|
||||||
|
|
||||||
void foo(std::string str) { std::cout << str << "\n"; }
|
void foo(std::string str) { std::cout << str << "\n"; }
|
||||||
|
|
||||||
|
int round1(int i) { return i; }
|
||||||
|
|
||||||
|
std::string_view echo_sv(std::string_view str) { return str; }
|
||||||
|
|
||||||
|
std::string echo(std::string str) { return str; }
|
||||||
|
|
||||||
|
void no_arg() { std::cout << "no args\n"; }
|
||||||
|
|
||||||
TEST_CASE("test router") {
|
TEST_CASE("test router") {
|
||||||
rpc_router router;
|
rpc_router router;
|
||||||
router.register_handler<add>();
|
router.register_handler<add>();
|
||||||
router.register_handler<foo>();
|
router.register_handler<foo>();
|
||||||
|
router.register_handler<round1>();
|
||||||
|
router.register_handler<echo>();
|
||||||
|
|
||||||
dummy d{};
|
dummy d{};
|
||||||
router.register_handler<&dummy::add>(&d);
|
router.register_handler<&dummy::add>(&d);
|
||||||
router.register_handler<&dummy::foo>(&d);
|
router.register_handler<&dummy::foo>(&d);
|
||||||
|
router.register_handler<&dummy::round1>(&d);
|
||||||
|
router.register_handler<&dummy::echo>(&d);
|
||||||
rpc_service::msgpack_codec codec;
|
rpc_service::msgpack_codec codec;
|
||||||
|
{
|
||||||
|
auto s = codec.pack_args(1);
|
||||||
|
auto s1 = codec.pack_args("test");
|
||||||
|
auto r = router.route(get_key<round1>(), s);
|
||||||
|
auto r1 = router.route(get_key<echo>(), s1);
|
||||||
|
|
||||||
|
auto r2 = router.route(get_key<&dummy::round1>(), s);
|
||||||
|
auto r3 = router.route(get_key<&dummy::echo>(), s1);
|
||||||
|
std::cout << "\n";
|
||||||
|
}
|
||||||
|
|
||||||
auto args = codec.pack_args(1, 2);
|
auto args = codec.pack_args(1, 2);
|
||||||
std::string_view str(args.data(), args.size());
|
std::string_view str(args.data(), args.size());
|
||||||
|
|
||||||
@@ -54,9 +81,23 @@ TEST_CASE("test server start") {
|
|||||||
rest_rpc_server server("127.0.0.1:9005");
|
rest_rpc_server server("127.0.0.1:9005");
|
||||||
server.register_handler<add>();
|
server.register_handler<add>();
|
||||||
server.register_handler<foo>();
|
server.register_handler<foo>();
|
||||||
|
server.register_handler<no_arg>();
|
||||||
|
server.register_handler<echo>();
|
||||||
|
server.register_handler<echo_sv>();
|
||||||
|
server.register_handler<round1>();
|
||||||
auto ec = server.async_start();
|
auto ec = server.async_start();
|
||||||
CHECK(!ec);
|
CHECK(!ec);
|
||||||
client cl;
|
client cl;
|
||||||
|
|
||||||
|
static_assert(util::CharArrayRef<char const(&)[5]>);
|
||||||
|
static_assert(util::CharArray<const char[5]>);
|
||||||
|
rpc_service::msgpack_codec::pack_args();
|
||||||
|
rpc_service::msgpack_codec::pack_args(1, 2);
|
||||||
|
auto s1 = rpc_service::msgpack_codec::pack_args("test");
|
||||||
|
auto s2 = rpc_service::msgpack_codec::pack_args(std::string_view("test2"));
|
||||||
|
auto s3 = rpc_service::msgpack_codec::pack_args(std::string("test2"));
|
||||||
|
auto s5 = rpc_service::msgpack_codec::pack_args(123);
|
||||||
|
|
||||||
// auto future = asio::co_spawn(cl.get_executor(),
|
// auto future = asio::co_spawn(cl.get_executor(),
|
||||||
// cl.connect("127.0.0.1:9005"), asio::use_future); auto conn_ec =
|
// cl.connect("127.0.0.1:9005"), asio::use_future); auto conn_ec =
|
||||||
// future.get();
|
// future.get();
|
||||||
@@ -72,8 +113,23 @@ TEST_CASE("test server start") {
|
|||||||
|
|
||||||
// auto future1 = asio::co_spawn(cl.get_executor(), cl.call<add>(1, 2),
|
// auto future1 = asio::co_spawn(cl.get_executor(), cl.call<add>(1, 2),
|
||||||
// asio::use_future); auto result = future1.get();
|
// asio::use_future); auto result = future1.get();
|
||||||
|
{
|
||||||
|
// auto result = sync_wait(cl.get_executor(),
|
||||||
|
// cl.call_for<no_arg>(std::chrono::minutes(2)));
|
||||||
|
// CHECK(result.ec==rpc_errc::ok);
|
||||||
|
auto result =
|
||||||
|
sync_wait(cl.get_executor(),
|
||||||
|
cl.call_for<echo_sv>(std::chrono::minutes(2), "test"));
|
||||||
|
CHECK(result.ec == rpc_errc::ok);
|
||||||
|
auto result1 = sync_wait(
|
||||||
|
cl.get_executor(), cl.call_for<echo>(std::chrono::minutes(2), "test"));
|
||||||
|
CHECK(result1.ec == rpc_errc::ok);
|
||||||
|
auto result2 = sync_wait(cl.get_executor(), cl.call<round1>(1));
|
||||||
|
CHECK(result2.ec == rpc_errc::ok);
|
||||||
|
}
|
||||||
|
|
||||||
auto result = sync_wait(cl.get_executor(), cl.call<add>(1, 2));
|
auto result = sync_wait(cl.get_executor(), cl.call<add>(1, 2));
|
||||||
|
CHECK(result.ec == rpc_errc::ok);
|
||||||
|
|
||||||
ec = server.async_start();
|
ec = server.async_start();
|
||||||
CHECK(!ec);
|
CHECK(!ec);
|
||||||
|
|||||||
Reference in New Issue
Block a user