aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/msgpack_rpc
diff options
context:
space:
mode:
authorbfredl <bjorn.linse@gmail.com>2023-08-26 13:39:31 +0200
committerGitHub <noreply@github.com>2023-08-26 13:39:31 +0200
commit965ed579fe3ab9ded0e5ab20b54a5a8607188dac (patch)
treef399c58853201cbe319a61a076862a00184548ba /src/nvim/msgpack_rpc
parent362df0f7938a0e6147ecf886655a0689430d426d (diff)
parentb641fc38749a2a52e40fa7eca6c7c41b1d9b031c (diff)
downloadrneovim-965ed579fe3ab9ded0e5ab20b54a5a8607188dac.tar.gz
rneovim-965ed579fe3ab9ded0e5ab20b54a5a8607188dac.tar.bz2
rneovim-965ed579fe3ab9ded0e5ab20b54a5a8607188dac.zip
Merge pull request #24399 from lambdalisue/fix-messagepack-rpc
feat(msgpack_rpc): add a new `msgpack-rpc` client type to fix behavior with MessagePack-RPC compliant clients
Diffstat (limited to 'src/nvim/msgpack_rpc')
-rw-r--r--src/nvim/msgpack_rpc/channel.c47
-rw-r--r--src/nvim/msgpack_rpc/channel_defs.h11
2 files changed, 51 insertions, 7 deletions
diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c
index 1772b0497b..095e392092 100644
--- a/src/nvim/msgpack_rpc/channel.c
+++ b/src/nvim/msgpack_rpc/channel.c
@@ -306,6 +306,17 @@ end:
channel_decref(channel);
}
+static ChannelCallFrame *find_call_frame(RpcState *rpc, uint32_t request_id)
+{
+ for (size_t i = 0; i < kv_size(rpc->call_stack); i++) {
+ ChannelCallFrame *frame = kv_Z(rpc->call_stack, i);
+ if (frame->request_id == request_id) {
+ return frame;
+ }
+ }
+ return NULL;
+}
+
static void parse_msgpack(Channel *channel)
{
Unpacker *p = channel->rpc.unpacker;
@@ -321,13 +332,15 @@ static void parse_msgpack(Channel *channel)
}
arena_mem_free(arena_finish(&p->arena));
} else if (p->type == kMessageTypeResponse) {
- ChannelCallFrame *frame = kv_last(channel->rpc.call_stack);
- if (p->request_id != frame->request_id) {
+ ChannelCallFrame *frame = channel->rpc.client_type == kClientTypeMsgpackRpc
+ ? find_call_frame(&channel->rpc, p->request_id)
+ : kv_last(channel->rpc.call_stack);
+ if (frame == NULL || p->request_id != frame->request_id) {
char buf[256];
snprintf(buf, sizeof(buf),
- "ch %" PRIu64 " returned a response with an unknown request "
- "id. Ensure the client is properly synchronized",
- channel->id);
+ "ch %" PRIu64 " (type=%" PRIu32 ") returned a response with an unknown request "
+ "id %" PRIu32 ". Ensure the client is properly synchronized",
+ channel->id, (unsigned)channel->rpc.client_type, p->request_id);
chan_close_with_error(channel, buf, LOGLVL_ERR);
}
frame->returned = true;
@@ -691,6 +704,25 @@ void rpc_set_client_info(uint64_t id, Dictionary info)
api_free_dictionary(chan->rpc.info);
chan->rpc.info = info;
+
+ // Parse "type" on "info" and set "client_type"
+ const char *type = get_client_info(chan, "type");
+ if (type == NULL || strequal(type, "remote")) {
+ chan->rpc.client_type = kClientTypeRemote;
+ } else if (strequal(type, "msgpack-rpc")) {
+ chan->rpc.client_type = kClientTypeMsgpackRpc;
+ } else if (strequal(type, "ui")) {
+ chan->rpc.client_type = kClientTypeUi;
+ } else if (strequal(type, "embedder")) {
+ chan->rpc.client_type = kClientTypeEmbedder;
+ } else if (strequal(type, "host")) {
+ chan->rpc.client_type = kClientTypeHost;
+ } else if (strequal(type, "plugin")) {
+ chan->rpc.client_type = kClientTypePlugin;
+ } else {
+ chan->rpc.client_type = kClientTypeUnknown;
+ }
+
channel_info_changed(chan, false);
}
@@ -699,14 +731,15 @@ Dictionary rpc_client_info(Channel *chan)
return copy_dictionary(chan->rpc.info, NULL);
}
-const char *rpc_client_name(Channel *chan)
+const char *get_client_info(Channel *chan, const char *key)
+ FUNC_ATTR_NONNULL_ALL
{
if (!chan->is_rpc) {
return NULL;
}
Dictionary info = chan->rpc.info;
for (size_t i = 0; i < info.size; i++) {
- if (strequal("name", info.items[i].key.data)
+ if (strequal(key, info.items[i].key.data)
&& info.items[i].value.type == kObjectTypeString) {
return info.items[i].value.data.string.data;
}
diff --git a/src/nvim/msgpack_rpc/channel_defs.h b/src/nvim/msgpack_rpc/channel_defs.h
index 1b5f0bb298..79aa8c1b13 100644
--- a/src/nvim/msgpack_rpc/channel_defs.h
+++ b/src/nvim/msgpack_rpc/channel_defs.h
@@ -14,6 +14,16 @@
typedef struct Channel Channel;
typedef struct Unpacker Unpacker;
+typedef enum {
+ kClientTypeUnknown = -1,
+ kClientTypeRemote = 0,
+ kClientTypeMsgpackRpc = 5,
+ kClientTypeUi = 1,
+ kClientTypeEmbedder = 2,
+ kClientTypeHost = 3,
+ kClientTypePlugin = 4,
+} ClientType;
+
typedef struct {
uint32_t request_id;
bool returned, errored;
@@ -37,6 +47,7 @@ typedef struct {
uint32_t next_request_id;
kvec_t(ChannelCallFrame *) call_stack;
Dictionary info;
+ ClientType client_type;
} RpcState;
#endif // NVIM_MSGPACK_RPC_CHANNEL_DEFS_H