diff --git a/src/msgpack_rpc.c b/src/msgpack_rpc.c new file mode 100644 index 0000000000..5e36830132 --- /dev/null +++ b/src/msgpack_rpc.c @@ -0,0 +1,156 @@ +#include + +#include "msgpack_rpc.h" +#include "vim.h" +#include "memory.h" + + +bool msgpack_rpc_call(msgpack_object *req, msgpack_packer *res) +{ + // Validate the basic structure of the msgpack-rpc payload + if (req->type != MSGPACK_OBJECT_ARRAY) { + return msgpack_rpc_error(req, res, "Request is not an array"); + } + + if (req->via.array.size != 4) { + char error_msg[256]; + snprintf(error_msg, + sizeof(error_msg), + "Request array size is %u, it should be 4", + req->via.array.size); + return msgpack_rpc_error(req, res, error_msg); + } + + if (req->via.array.ptr[0].type != MSGPACK_OBJECT_POSITIVE_INTEGER) { + return msgpack_rpc_error(req, res, "Message type must be an integer"); + } + + if (req->via.array.ptr[0].via.u64 != 0) { + return msgpack_rpc_error(req, res, "Message type must be 0"); + } + + if (req->via.array.ptr[1].type != MSGPACK_OBJECT_POSITIVE_INTEGER) { + return msgpack_rpc_error(req, res, "Id must be a positive integer"); + } + + if (req->via.array.ptr[2].type != MSGPACK_OBJECT_POSITIVE_INTEGER) { + return msgpack_rpc_error(req, res, "Method id must be a positive integer"); + } + + if (req->via.array.ptr[3].type != MSGPACK_OBJECT_ARRAY) { + return msgpack_rpc_error(req, res, "Paremeters must be an array"); + } + + // dispatch the message + return msgpack_rpc_dispatch(req, res); +} + +void msgpack_rpc_response(msgpack_object *req, msgpack_packer *res) +{ + // Array of size 4 + msgpack_pack_array(res, 4); + // Response type is 1 + msgpack_pack_int(res, 1); + // Msgid is the same as the request + msgpack_pack_int(res, req->via.array.ptr[1].via.u64); +} + +void msgpack_rpc_success(msgpack_object *req, msgpack_packer *res) +{ + msgpack_rpc_response(req, res); + // Nil error + msgpack_pack_nil(res); +} + +bool msgpack_rpc_error(msgpack_object *req, msgpack_packer *res, char *msg) +{ + size_t len = strlen(msg); + + msgpack_rpc_response(req, res); + msgpack_pack_raw(res, len); + msgpack_pack_raw_body(res, msg, len); + // Nil result + msgpack_pack_nil(res); + + return false; +} + +char **msgpack_rpc_array_argument(msgpack_object *obj) +{ + uint32_t i; + char **rv = xmalloc(obj->via.array.size + 1); + + for (i = 0; i < obj->via.array.size; i++) { + rv[i] = msgpack_rpc_raw_argument(obj->via.array.ptr + i); + } + + rv[i] = NULL; + + return rv; +} + +char *msgpack_rpc_raw_argument(msgpack_object *obj) +{ + char *rv = xmalloc(obj->via.raw.size + 1); + memcpy(rv, obj->via.raw.ptr, obj->via.raw.size); + rv[obj->via.raw.size] = NUL; + + return rv; +} + +uint32_t msgpack_rpc_integer_argument(msgpack_object *obj) +{ + return obj->via.u64; +} + +bool msgpack_rpc_array_result(char **result, + msgpack_object *req, + msgpack_packer *res) +{ + char **ptr; + uint32_t array_size; + + // Count number of items in the array + for (ptr = result; *ptr != NULL; ptr++) continue; + + msgpack_rpc_success(req, res); + // Subtract 1 to exclude the NULL slot + array_size = ptr - result - 1; + msgpack_pack_array(res, array_size); + + // push each string to the array + for (ptr = result; *ptr != NULL; ptr++) { + size_t raw_size = strlen(*ptr); + msgpack_pack_raw(res, raw_size); + msgpack_pack_raw_body(res, *ptr, raw_size); + } + + return true; +} + +bool msgpack_rpc_raw_result(char *result, + msgpack_object *req, + msgpack_packer *res) +{ + size_t raw_size = strlen(result); + msgpack_rpc_success(req, res); + msgpack_pack_raw(res, raw_size); + msgpack_pack_raw_body(res, result, raw_size); + return true; +} + +bool msgpack_rpc_integer_result(uint32_t result, + msgpack_object *req, + msgpack_packer *res) +{ + msgpack_rpc_success(req, res); + msgpack_pack_int(res, result); + return true; +} + +bool msgpack_rpc_void_result(msgpack_object *req, msgpack_packer *res) +{ + msgpack_rpc_success(req, res); + msgpack_pack_nil(res); + return true; +} diff --git a/src/msgpack_rpc.h b/src/msgpack_rpc.h new file mode 100644 index 0000000000..f713e5eeb5 --- /dev/null +++ b/src/msgpack_rpc.h @@ -0,0 +1,30 @@ +#ifndef NEOVIM_MSGPACK_RPC_H +#define NEOVIM_MSGPACK_RPC_H + +#include +#include + +#include + +bool msgpack_rpc_call(msgpack_object *req, msgpack_packer *res); +bool msgpack_rpc_dispatch(msgpack_object *req, msgpack_packer *res); +void msgpack_rpc_response(msgpack_object *req, msgpack_packer *res); +void msgpack_rpc_success(msgpack_object *req, msgpack_packer *res); +bool msgpack_rpc_error(msgpack_object *req, msgpack_packer *res, char *msg); +char **msgpack_rpc_array_argument(msgpack_object *obj); +char *msgpack_rpc_raw_argument(msgpack_object *obj); +uint32_t msgpack_rpc_integer_argument(msgpack_object *obj); +bool msgpack_rpc_array_result(char **result, + msgpack_object *req, + msgpack_packer *res); +bool msgpack_rpc_raw_result(char *result, + msgpack_object *req, + msgpack_packer *res); +bool msgpack_rpc_integer_result(uint32_t result, + msgpack_object *req, + msgpack_packer *res); +bool msgpack_rpc_void_result(msgpack_object *req, msgpack_packer *res); + + +#endif // NEOVIM_MSGPACK_RPC_H +