5 #ifndef PACKIO_MSGPACK_RPC_H
6 #define PACKIO_MSGPACK_RPC_H
11 #include "../internal/config.h"
12 #include "../internal/log.h"
13 #include "../internal/rpc.h"
17 enum class msgpack_rpc_type { request = 0, response = 1, notification = 2 };
19 template <
typename... Args>
20 constexpr
bool positional_args_v = (!is_arg_v<Args> && ...);
24 using buffer_type = ::msgpack::sbuffer;
35 ::msgpack::object args;
37 std::unique_ptr<::msgpack::zone>
zone;
43 ::msgpack::object result;
44 ::msgpack::object error;
46 std::unique_ptr<::msgpack::zone>
zone;
49 class incremental_parser {
52 : unpacker_{std::make_unique<::msgpack::unpacker>()}
56 std::optional<request> get_request()
62 auto object = std::move(*parsed_);
64 return parse_request(std::move(
object));
67 std::optional<response> get_response()
73 auto object = std::move(*parsed_);
75 return parse_response(std::move(
object));
80 return unpacker_->buffer();
83 std::size_t buffer_capacity()
const
85 return unpacker_->buffer_capacity();
88 void buffer_consumed(std::size_t bytes)
90 unpacker_->buffer_consumed(bytes);
93 void reserve_buffer(std::size_t bytes)
95 unpacker_->reserve_buffer(bytes);
99 void try_parse_object()
104 ::msgpack::object_handle object;
105 if (unpacker_->next(
object)) {
106 parsed_ = std::move(
object);
110 std::optional<::msgpack::object_handle> parsed_;
111 std::unique_ptr<::msgpack::unpacker> unpacker_;
114 static std::string format_id(
const id_type&
id)
116 return std::to_string(
id);
119 template <
typename... Args>
120 static auto serialize_notification(std::string_view method, Args&&... args)
121 -> std::enable_if_t<positional_args_v<Args...>, buffer_type>
126 std::forward_as_tuple(
127 static_cast<int>(msgpack_rpc_type::notification),
129 std::forward_as_tuple(std::forward<Args>(args)...)));
133 template <
typename... Args>
134 static auto serialize_notification(std::string_view, Args&&...)
135 -> std::enable_if_t<!positional_args_v<Args...>, buffer_type>
138 positional_args_v<Args...>,
139 "msgpack-RPC does not support named arguments");
142 template <
typename... Args>
143 static auto serialize_request(
id_type id, std::string_view method, Args&&... args)
144 -> std::enable_if_t<positional_args_v<Args...>, buffer_type>
149 std::forward_as_tuple(
150 static_cast<int>(msgpack_rpc_type::request),
153 std::forward_as_tuple(std::forward<Args>(args)...)));
157 template <
typename... Args>
158 static auto serialize_request(
id_type, std::string_view, Args&&...)
159 -> std::enable_if_t<!positional_args_v<Args...>, buffer_type>
162 positional_args_v<Args...>,
163 "msgpack-RPC does not support named arguments");
166 template <
typename... Args>
167 static buffer_type serialize_response(response response)
172 std::forward_as_tuple(
173 static_cast<int>(msgpack_rpc_type::response),
180 static net::const_buffer buffer(
const buffer_type& buf)
182 return net::const_buffer(buf.data(), buf.size());
185 template <
typename T,
typename NamesContainer>
186 static std::optional<T> extract_args(
187 const ::msgpack::object& args,
188 const NamesContainer&)
190 if (args.type != ::msgpack::type::ARRAY) {
191 PACKIO_ERROR(
"arguments is not an array");
195 if (args.via.array.size != std::tuple_size_v<T>) {
204 catch (::msgpack::type_error&) {
209 static response make_response(
id_type id)
211 return make_response(
id, ::msgpack::object{});
214 template <
typename T>
215 static response make_response(
id_type id, T&& value)
219 resp.zone = std::make_unique<::msgpack::zone>();
220 resp.result = ::msgpack::object(std::forward<T>(value), *resp.zone);
224 template <
typename T>
225 static response make_error_response(
id_type id, T&& value)
229 resp.zone = std::make_unique<::msgpack::zone>();
230 resp.error = ::msgpack::object(std::forward<T>(value), *resp.zone);
235 static std::optional<response> parse_response(::msgpack::object_handle&& res)
237 if (res->type != ::msgpack::type::ARRAY) {
238 PACKIO_ERROR(
"unexpected message type: {}", res->type);
241 if (res->via.array.size != 4) {
242 PACKIO_ERROR(
"unexpected message size: {}", res->via.array.size);
245 int type = res->via.array.ptr[0].as<
int>();
246 if (type !=
static_cast<int>(msgpack_rpc_type::response)) {
247 PACKIO_ERROR(
"unexpected type: {}", type);
252 parsed.zone = std::move(res.zone());
253 const auto& array = res->via.array.ptr;
255 parsed.id = array[1].as<
id_type>();
256 if (array[2].type != ::msgpack::type::NIL) {
257 parsed.error = array[2];
260 parsed.result = array[3];
265 static std::optional<request> parse_request(::msgpack::object_handle&& req)
267 if (req->type != ::msgpack::type::ARRAY || req->via.array.size < 3) {
268 PACKIO_ERROR(
"unexpected message type: {}", req->type);
273 parsed.zone = std::move(req.zone());
274 const auto& array = req->via.array.ptr;
275 auto array_size = req->via.array.size;
280 msgpack_rpc_type type =
static_cast<msgpack_rpc_type
>(
281 array[idx++].as<
int>());
283 std::size_t expected_size;
285 case msgpack_rpc_type::request:
286 parsed.id = array[idx++].as<
id_type>();
288 parsed.type = call_type::request;
290 case msgpack_rpc_type::notification:
292 parsed.type = call_type::notification;
295 PACKIO_ERROR(
"unexpected type: {}", type);
299 if (array_size != expected_size) {
300 PACKIO_ERROR(
"unexpected message size: {}", array_size);
304 parsed.method = array[idx++].as<std::string>();
305 parsed.args = array[idx++];
309 catch (::msgpack::type_error& exc) {
310 PACKIO_ERROR(
"unexpected message content: {}", exc.what());
319 #endif // PACKIO_MSGPACK_RPC_H