5 #ifndef PACKIO_MSGPACK_RPC_RPC_H 
    6 #define PACKIO_MSGPACK_RPC_RPC_H 
   10 #include <msgpack.hpp> 
   13 #include "../args_specs.h" 
   14 #include "../internal/config.h" 
   15 #include "../internal/expected.h" 
   16 #include "../internal/log.h" 
   17 #include "../internal/rpc.h" 
   20 namespace msgpack_rpc {
 
   23 template <
typename... Args>
 
   24 constexpr 
bool positional_args_v = (!is_arg_v<Args> && ...);
 
   26 enum class msgpack_rpc_type { request = 0, response = 1, notification = 2 };
 
   28 using id_type = uint32_t;
 
   29 using native_type = ::msgpack::object;
 
   30 using packio::internal::expected;
 
   31 using packio::internal::unexpected;
 
   40     std::unique_ptr<::msgpack::zone> 
zone; 
 
   49     std::unique_ptr<::msgpack::zone> 
zone; 
 
   57     expected<request, std::string> get_request()
 
   61             return unexpected{
"no request parsed"};
 
   63         auto object = std::move(*parsed_);
 
   65         return parse_request(std::move(
object));
 
   68     expected<response, std::string> get_response()
 
   72             return unexpected{
"no response parsed"};
 
   74         auto object = std::move(*parsed_);
 
   76         return parse_response(std::move(
object));
 
   81         return unpacker_->buffer();
 
   84     std::size_t buffer_capacity()
 const { 
return unpacker_->buffer_capacity(); }
 
   86     void buffer_consumed(std::size_t bytes)
 
   88         unpacker_->buffer_consumed(bytes);
 
   91     void reserve_buffer(std::size_t bytes) { unpacker_->reserve_buffer(bytes); }
 
   94     void try_parse_object()
 
   99         ::msgpack::object_handle object;
 
  100         if (unpacker_->next(
object)) {
 
  101             parsed_ = std::move(
object);
 
  105     static expected<response, std::string> parse_response(
 
  106         ::msgpack::object_handle&& res)
 
  108         if (res->type != ::msgpack::type::ARRAY) {
 
  110                 "unexpected message type: " + std::to_string(res->type)};
 
  112         if (res->via.array.size != 4) {
 
  114                 "unexpected message size: " + std::to_string(res->via.array.size)};
 
  116         int type = res->via.array.ptr[0].as<
int>();
 
  117         if (type != 
static_cast<int>(msgpack_rpc_type::response)) {
 
  118             return unexpected{
"unexpected type: " + std::to_string(type)};
 
  122         parsed.
zone = std::move(res.zone());
 
  123         const auto& array = res->via.array.ptr;
 
  125         parsed.id = array[1].as<id_type>();
 
  126         if (array[2].type != ::msgpack::type::NIL) {
 
  127             parsed.error = array[2];
 
  130             parsed.result = array[3];
 
  132         return {std::move(parsed)};
 
  135     static expected<request, std::string> parse_request(::msgpack::object_handle&& req)
 
  137         if (req->type != ::msgpack::type::ARRAY || req->via.array.size < 3) {
 
  139                 "unexpected message type: " + std::to_string(req->type)};
 
  143         parsed.
zone = std::move(req.zone());
 
  144         const auto& array = req->via.array.ptr;
 
  145         auto array_size = req->via.array.size;
 
  150             msgpack_rpc_type type = 
static_cast<msgpack_rpc_type
>(
 
  151                 array[idx++].as<
int>());
 
  153             std::size_t expected_size;
 
  155             case msgpack_rpc_type::request:
 
  156                 parsed.id = array[idx++].as<id_type>();
 
  158                 parsed.type = call_type::request;
 
  160             case msgpack_rpc_type::notification:
 
  162                 parsed.type = call_type::notification;
 
  166                     "unexpected type: " + std::to_string(
static_cast<int>(type))};
 
  169             if (array_size != expected_size) {
 
  171                     "unexpected message size: " + std::to_string(array_size)};
 
  174             parsed.method = array[idx++].as<std::string>();
 
  175             parsed.args = array[idx++];
 
  177             return {std::move(parsed)};
 
  179         catch (::msgpack::type_error& exc) {
 
  181                 std::string{
"unexpected message content: "} + exc.what()};
 
  185     std::optional<::msgpack::object_handle> parsed_;
 
  186     std::unique_ptr<::msgpack::unpacker> unpacker_;
 
  209     static std::string format_id(
const id_type& 
id)
 
  211         return std::to_string(
id);
 
  214     template <
typename... Args>
 
  215     static auto serialize_notification(std::string_view method, Args&&... args)
 
  216         -> std::enable_if_t<internal::positional_args_v<Args...>, ::msgpack::sbuffer>
 
  218         ::msgpack::sbuffer buffer;
 
  221             std::forward_as_tuple(
 
  222                 static_cast<int>(internal::msgpack_rpc_type::notification),
 
  224                 std::forward_as_tuple(std::forward<Args>(args)...)));
 
  228     template <
typename... Args>
 
  229     static auto serialize_notification(std::string_view, Args&&...)
 
  230         -> std::enable_if_t<!internal::positional_args_v<Args...>, ::msgpack::sbuffer>
 
  233             internal::positional_args_v<Args...>,
 
  234             "msgpack-RPC does not support named arguments");
 
  237     template <
typename... Args>
 
  238     static auto serialize_request(
id_type id, std::string_view method, Args&&... args)
 
  239         -> std::enable_if_t<internal::positional_args_v<Args...>, ::msgpack::sbuffer>
 
  241         ::msgpack::sbuffer buffer;
 
  244             std::forward_as_tuple(
 
  245                 static_cast<int>(internal::msgpack_rpc_type::request),
 
  248                 std::forward_as_tuple(std::forward<Args>(args)...)));
 
  252     template <
typename... Args>
 
  253     static auto serialize_request(
id_type, std::string_view, Args&&...)
 
  254         -> std::enable_if_t<!internal::positional_args_v<Args...>, ::msgpack::sbuffer>
 
  257             internal::positional_args_v<Args...>,
 
  258             "msgpack-RPC does not support named arguments");
 
  261     static ::msgpack::sbuffer serialize_response(
id_type id)
 
  263         return serialize_response(
id, ::msgpack::object{});
 
  266     template <
typename T>
 
  267     static ::msgpack::sbuffer serialize_response(
id_type id, T&& value)
 
  269         ::msgpack::sbuffer buffer;
 
  272             std::forward_as_tuple(
 
  273                 static_cast<int>(internal::msgpack_rpc_type::response),
 
  276                 std::forward<T>(value)));
 
  280     template <
typename T>
 
  281     static ::msgpack::sbuffer serialize_error_response(
id_type id, T&& value)
 
  283         ::msgpack::sbuffer buffer;
 
  286             std::forward_as_tuple(
 
  287                 static_cast<int>(internal::msgpack_rpc_type::response),
 
  289                 std::forward<T>(value),
 
  290                 ::msgpack::object{}));
 
  294     static net::const_buffer buffer(const ::msgpack::sbuffer& buf)
 
  296         return net::const_buffer(buf.data(), buf.size());
 
  299     template <
typename T, 
typename F>
 
  300     static internal::expected<T, std::string> extract_args(
 
  301         const ::msgpack::object& args,
 
  302         const args_specs<F>& specs)
 
  305             if (args.type != ::msgpack::type::ARRAY) {
 
  306                 throw std::runtime_error{
"arguments is not an array"};
 
  308             return convert_positional_args<T>(args.via.array, specs);
 
  310         catch (
const std::exception& exc) {
 
  311             return internal::unexpected{
 
  312                 std::string{
"cannot convert arguments: "} + exc.what()};
 
  317     template <
typename T, 
typename F>
 
  318     static constexpr T convert_positional_args(
 
  319         const ::msgpack::object_array& array,
 
  320         const args_specs<F>& specs)
 
  322         return convert_positional_args<T>(
 
  323             array, specs, std::make_index_sequence<args_specs<F>::size()>());
 
  326     template <
typename T, 
typename F, std::size_t... Idxs>
 
  327     static constexpr T convert_positional_args(
 
  328         const ::msgpack::object_array& array,
 
  329         const args_specs<F>& specs,
 
  330         std::index_sequence<Idxs...>)
 
  332         if (!specs.options().allow_extra_arguments
 
  333             && array.size > std::tuple_size_v<T>) {
 
  334             throw std::runtime_error{
"too many arguments"};
 
  337             if (Idxs < array.size) {
 
  339                     return array.ptr[Idxs].as<std::tuple_element_t<Idxs, T>>();
 
  341                 catch (const ::msgpack::type_error&) {
 
  342                     throw std::runtime_error{
 
  343                         "invalid type for argument " 
  344                         + specs.template get<Idxs>().name()};
 
  347             if (
const auto& value = specs.template get<Idxs>().default_value()) {
 
  350             throw std::runtime_error{
 
  351                 "no value for argument " + specs.template get<Idxs>().name()};
 
The incremental parser for msgpack-RPC objects.
Definition: rpc.h:53
 
The msgpack RPC protocol implementation.
Definition: rpc.h:192
 
internal::native_type native_type
The native type of the serialization library.
Definition: rpc.h:198
 
internal::id_type id_type
Type of the call ID.
Definition: rpc.h:195
 
The packio namespace.
Definition: arg.h:14
 
The object representing a client request.
Definition: rpc.h:34
 
std::unique_ptr<::msgpack::zone > zone
Msgpack zone storing the args.
Definition: rpc.h:40
 
The object representing the response to a call.
Definition: rpc.h:44
 
std::unique_ptr<::msgpack::zone > zone
Msgpack zone storing error and result.
Definition: rpc.h:49