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