summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgit-hulk <hulk.website@gmail.com>2024-01-27 22:21:54 +0800
committerMichael Grunder <michael.grunder@gmail.com>2024-01-31 12:08:52 -0800
commit5b253d89c7cc9593723334e0a45077bd4008d3db (patch)
tree5538a775daf676538f02829e3d521ab39bc5fa77
parent2706c3e16d57c9babd24bfd83ade2efcdb13a7b8 (diff)
Add support of RESP3 attribute type
Currently, Redis DEBUG PROTOCOL 'attrib' command will return an attribute type, but hiredis doesn't support it yet. So it got the protocol type error: ``` 127.0.0.1:6379> DEBUG PROTOCOL attrib Error: Protocol error, got "|" as reply type byte ``` After apply this PR, it should reply: ``` 127.0.0.1:6379> DEBUG PROTOCOL attrib 1# "key-popularity" 1# 1) "key:123" 2) (integer) 90 ```
-rw-r--r--hiredis.c8
-rw-r--r--read.c7
-rw-r--r--test.c20
3 files changed, 34 insertions, 1 deletions
diff --git a/hiredis.c b/hiredis.c
index 446ceb1..78b2837 100644
--- a/hiredis.c
+++ b/hiredis.c
@@ -102,6 +102,7 @@ void freeReplyObject(void *reply) {
break; /* Nothing to free */
case REDIS_REPLY_ARRAY:
case REDIS_REPLY_MAP:
+ case REDIS_REPLY_ATTR:
case REDIS_REPLY_SET:
case REDIS_REPLY_PUSH:
if (r->element != NULL) {
@@ -160,6 +161,7 @@ static void *createStringObject(const redisReadTask *task, char *str, size_t len
parent = task->parent->obj;
assert(parent->type == REDIS_REPLY_ARRAY ||
parent->type == REDIS_REPLY_MAP ||
+ parent->type == REDIS_REPLY_ATTR ||
parent->type == REDIS_REPLY_SET ||
parent->type == REDIS_REPLY_PUSH);
parent->element[task->idx] = r;
@@ -192,6 +194,7 @@ static void *createArrayObject(const redisReadTask *task, size_t elements) {
parent = task->parent->obj;
assert(parent->type == REDIS_REPLY_ARRAY ||
parent->type == REDIS_REPLY_MAP ||
+ parent->type == REDIS_REPLY_ATTR ||
parent->type == REDIS_REPLY_SET ||
parent->type == REDIS_REPLY_PUSH);
parent->element[task->idx] = r;
@@ -212,6 +215,8 @@ static void *createIntegerObject(const redisReadTask *task, long long value) {
parent = task->parent->obj;
assert(parent->type == REDIS_REPLY_ARRAY ||
parent->type == REDIS_REPLY_MAP ||
+ parent->type == REDIS_REPLY_ATTR ||
+ parent->type == REDIS_REPLY_SET ||
parent->type == REDIS_REPLY_SET ||
parent->type == REDIS_REPLY_PUSH);
parent->element[task->idx] = r;
@@ -249,6 +254,7 @@ static void *createDoubleObject(const redisReadTask *task, double value, char *s
parent = task->parent->obj;
assert(parent->type == REDIS_REPLY_ARRAY ||
parent->type == REDIS_REPLY_MAP ||
+ parent->type == REDIS_REPLY_ATTR ||
parent->type == REDIS_REPLY_SET ||
parent->type == REDIS_REPLY_PUSH);
parent->element[task->idx] = r;
@@ -267,6 +273,7 @@ static void *createNilObject(const redisReadTask *task) {
parent = task->parent->obj;
assert(parent->type == REDIS_REPLY_ARRAY ||
parent->type == REDIS_REPLY_MAP ||
+ parent->type == REDIS_REPLY_ATTR ||
parent->type == REDIS_REPLY_SET ||
parent->type == REDIS_REPLY_PUSH);
parent->element[task->idx] = r;
@@ -287,6 +294,7 @@ static void *createBoolObject(const redisReadTask *task, int bval) {
parent = task->parent->obj;
assert(parent->type == REDIS_REPLY_ARRAY ||
parent->type == REDIS_REPLY_MAP ||
+ parent->type == REDIS_REPLY_ATTR ||
parent->type == REDIS_REPLY_SET ||
parent->type == REDIS_REPLY_PUSH);
parent->element[task->idx] = r;
diff --git a/read.c b/read.c
index 9c8f869..fa40e61 100644
--- a/read.c
+++ b/read.c
@@ -250,6 +250,7 @@ static void moveToNextTask(redisReader *r) {
prv = r->task[r->ridx-1];
assert(prv->type == REDIS_REPLY_ARRAY ||
prv->type == REDIS_REPLY_MAP ||
+ prv->type == REDIS_REPLY_ATTR ||
prv->type == REDIS_REPLY_SET ||
prv->type == REDIS_REPLY_PUSH);
if (cur->idx == prv->elements-1) {
@@ -534,7 +535,7 @@ static int processAggregateItem(redisReader *r) {
moveToNextTask(r);
} else {
- if (cur->type == REDIS_REPLY_MAP) elements *= 2;
+ if (cur->type == REDIS_REPLY_MAP || cur->type == REDIS_REPLY_ATTR) elements *= 2;
if (r->fn && r->fn->createArray)
obj = r->fn->createArray(cur,elements);
@@ -602,6 +603,9 @@ static int processItem(redisReader *r) {
case '%':
cur->type = REDIS_REPLY_MAP;
break;
+ case '|':
+ cur->type = REDIS_REPLY_ATTR;
+ break;
case '~':
cur->type = REDIS_REPLY_SET;
break;
@@ -642,6 +646,7 @@ static int processItem(redisReader *r) {
return processBulkItem(r);
case REDIS_REPLY_ARRAY:
case REDIS_REPLY_MAP:
+ case REDIS_REPLY_ATTR:
case REDIS_REPLY_SET:
case REDIS_REPLY_PUSH:
return processAggregateItem(r);
diff --git a/test.c b/test.c
index 897daf8..d9696f1 100644
--- a/test.c
+++ b/test.c
@@ -795,6 +795,26 @@ static void test_reply_reader(void) {
freeReplyObject(reply);
redisReaderFree(reader);
+ test("Can parse RESP3 attribute: ");
+ reader = redisReaderCreate();
+ redisReaderFeed(reader, "|2\r\n+foo\r\n:123\r\n+bar\r\n#t\r\n",26);
+ ret = redisReaderGetReply(reader,&reply);
+ test_cond(ret == REDIS_OK &&
+ ((redisReply*)reply)->type == REDIS_REPLY_ATTR &&
+ ((redisReply*)reply)->elements == 4 &&
+ ((redisReply*)reply)->element[0]->type == REDIS_REPLY_STATUS &&
+ ((redisReply*)reply)->element[0]->len == 3 &&
+ !strcmp(((redisReply*)reply)->element[0]->str,"foo") &&
+ ((redisReply*)reply)->element[1]->type == REDIS_REPLY_INTEGER &&
+ ((redisReply*)reply)->element[1]->integer == 123 &&
+ ((redisReply*)reply)->element[2]->type == REDIS_REPLY_STATUS &&
+ ((redisReply*)reply)->element[2]->len == 3 &&
+ !strcmp(((redisReply*)reply)->element[2]->str,"bar") &&
+ ((redisReply*)reply)->element[3]->type == REDIS_REPLY_BOOL &&
+ ((redisReply*)reply)->element[3]->integer);
+ freeReplyObject(reply);
+ redisReaderFree(reader);
+
test("Can parse RESP3 set: ");
reader = redisReaderCreate();
redisReaderFeed(reader, "~5\r\n+orange\r\n$5\r\napple\r\n#f\r\n:100\r\n:999\r\n",40);