5 #ifndef PACKIO_MSGPACK_RPC_RPC_H
6 #define PACKIO_MSGPACK_RPC_RPC_H
11 #include "../internal/config.h"
12 #include "../internal/log.h"
13 #include "../internal/rpc.h"
16 namespace msgpack_rpc {
19 template <
typename... Args>
20 constexpr
bool positional_args_v = (!is_arg_v<Args> && ...);
22 enum class msgpack_rpc_type { request = 0, response = 1, notification = 2 };
24 using id_type = uint32_t;
25 using native_type = ::msgpack::object;
34 std::unique_ptr<::msgpack::zone>
zone;
43 std::unique_ptr<::msgpack::zone>
zone;
51 std::optional<request> get_request()
57 auto object = std::move(*parsed_);
59 return parse_request(std::move(
object));
62 std::optional<response> get_response()
68 auto object = std::move(*parsed_);
70 return parse_response(std::move(
object));
75 return unpacker_->buffer();
78 std::size_t buffer_capacity()
const {
return unpacker_->buffer_capacity(); }
80 void buffer_consumed(std::size_t bytes)
82 unpacker_->buffer_consumed(bytes);
85 void reserve_buffer(std::size_t bytes) { unpacker_->reserve_buffer(bytes); }
88 void try_parse_object()
93 ::msgpack::object_handle object;
94 if (unpacker_->next(
object)) {
95 parsed_ = std::move(
object);
99 static std::optional<response> parse_response(::msgpack::object_handle&& res)
101 if (res->type != ::msgpack::type::ARRAY) {
102 PACKIO_ERROR(
"unexpected message type: {}", res->type);
105 if (res->via.array.size != 4) {
106 PACKIO_ERROR(
"unexpected message size: {}", res->via.array.size);
109 int type = res->via.array.ptr[0].as<
int>();
110 if (type !=
static_cast<int>(msgpack_rpc_type::response)) {
111 PACKIO_ERROR(
"unexpected type: {}", type);
115 std::optional<response> parsed{std::in_place};
116 parsed->zone = std::move(res.zone());
117 const auto& array = res->via.array.ptr;
119 parsed->id = array[1].as<id_type>();
120 if (array[2].type != ::msgpack::type::NIL) {
121 parsed->error = array[2];
124 parsed->result = array[3];
129 static std::optional<request> parse_request(::msgpack::object_handle&& req)
131 if (req->type != ::msgpack::type::ARRAY || req->via.array.size < 3) {
132 PACKIO_ERROR(
"unexpected message type: {}", req->type);
136 std::optional<request> parsed{std::in_place};
137 parsed->zone = std::move(req.zone());
138 const auto& array = req->via.array.ptr;
139 auto array_size = req->via.array.size;
144 msgpack_rpc_type type =
static_cast<msgpack_rpc_type
>(
145 array[idx++].as<
int>());
147 std::size_t expected_size;
149 case msgpack_rpc_type::request:
150 parsed->id = array[idx++].as<id_type>();
152 parsed->type = call_type::request;
154 case msgpack_rpc_type::notification:
156 parsed->type = call_type::notification;
159 PACKIO_ERROR(
"unexpected type: {}", type);
163 if (array_size != expected_size) {
164 PACKIO_ERROR(
"unexpected message size: {}", array_size);
168 parsed->method = array[idx++].as<std::string>();
169 parsed->args = array[idx++];
173 catch (::msgpack::type_error& exc) {
174 PACKIO_ERROR(
"unexpected message content: {}", exc.what());
180 std::optional<::msgpack::object_handle> parsed_;
181 std::unique_ptr<::msgpack::unpacker> unpacker_;
204 static std::string format_id(
const id_type&
id)
206 return std::to_string(
id);
209 template <
typename... Args>
210 static auto serialize_notification(std::string_view method, Args&&... args)
211 -> std::enable_if_t<internal::positional_args_v<Args...>, ::msgpack::sbuffer>
213 ::msgpack::sbuffer buffer;
216 std::forward_as_tuple(
217 static_cast<int>(internal::msgpack_rpc_type::notification),
219 std::forward_as_tuple(std::forward<Args>(args)...)));
223 template <
typename... Args>
224 static auto serialize_notification(std::string_view, Args&&...)
225 -> std::enable_if_t<!internal::positional_args_v<Args...>, ::msgpack::sbuffer>
228 internal::positional_args_v<Args...>,
229 "msgpack-RPC does not support named arguments");
232 template <
typename... Args>
233 static auto serialize_request(
id_type id, std::string_view method, Args&&... args)
234 -> std::enable_if_t<internal::positional_args_v<Args...>, ::msgpack::sbuffer>
236 ::msgpack::sbuffer buffer;
239 std::forward_as_tuple(
240 static_cast<int>(internal::msgpack_rpc_type::request),
243 std::forward_as_tuple(std::forward<Args>(args)...)));
247 template <
typename... Args>
248 static auto serialize_request(
id_type, std::string_view, Args&&...)
249 -> std::enable_if_t<!internal::positional_args_v<Args...>, ::msgpack::sbuffer>
252 internal::positional_args_v<Args...>,
253 "msgpack-RPC does not support named arguments");
256 static ::msgpack::sbuffer serialize_response(
id_type id)
258 return serialize_response(
id, ::msgpack::object{});
261 template <
typename T>
262 static ::msgpack::sbuffer serialize_response(
id_type id, T&& value)
264 ::msgpack::sbuffer buffer;
267 std::forward_as_tuple(
268 static_cast<int>(internal::msgpack_rpc_type::response),
271 std::forward<T>(value)));
275 template <
typename T>
276 static ::msgpack::sbuffer serialize_error_response(
id_type id, T&& value)
278 ::msgpack::sbuffer buffer;
281 std::forward_as_tuple(
282 static_cast<int>(internal::msgpack_rpc_type::response),
284 std::forward<T>(value),
285 ::msgpack::object{}));
289 static net::const_buffer buffer(const ::msgpack::sbuffer& buf)
291 return net::const_buffer(buf.data(), buf.size());
294 template <
typename T,
typename NamesContainer>
295 static std::optional<T> extract_args(
296 const ::msgpack::object& args,
297 const NamesContainer&)
299 if (args.type != ::msgpack::type::ARRAY) {
300 PACKIO_ERROR(
"arguments is not an array");
304 if (args.via.array.size != std::tuple_size_v<T>) {
313 catch (::msgpack::type_error&) {
322 #endif // PACKIO_MSGPACK_RPC_RPC_H