/* This is a simple command to test replication. Because of the "!" modified * in the RedisModule_Call() call, the two INCRs get replicated. * Also note how the ECHO is replicated in an unexpected position (check * comments the function implementation). */ int HelloRepl1_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { RedisModuleCallReply *reply; RedisModule_AutoMemory(ctx); /* This will be replicated *after* the two INCR statements, since * the Call() replication has precedence, so the actual replication * stream will be: * * MULTI * INCR foo * INCR bar * ECHO c foo * EXEC */ RedisModule_Replicate(ctx,"ECHO","c","foo"); /* Using the "!" modifier we replicate the command if it * modified the dataset in some way. */ reply = RedisModule_Call(ctx,"INCR","c!","foo"); reply = RedisModule_Call(ctx,"INCR","c!","bar"); RedisModule_ReplyWithLongLong(ctx,0); return REDISMODULE_OK; }
void RMUtil_SCAN(RedisModuleCtx *ctx, const char *pattern, RedisModuleString **keys, size_t *key_count) { int scan_idx = 0; /* SCAN cursor. */ size_t total_keys = 0; /* Number of keys retrieved. */ RedisModuleCallReply *reply; /* Consume SCAN */ do { reply = RedisModule_Call(ctx, "SCAN", "lcc", scan_idx, "MATCH", pattern); /* First element is the scan cursor, 0 indicates end of SCAN. */ RedisModuleCallReply *element = RedisModule_CallReplyArrayElement(reply, 0); scan_idx = RedisModule_CallReplyInteger(element); /* Process SCAN results. */ RedisModuleCallReply *scan_results = RedisModule_CallReplyArrayElement(reply, 1); /* Number of elements in replay. */ size_t keys_count = RedisModule_CallReplyLength(scan_results); /* Extract SCAN result elements. */ for(int idx = 0; idx < keys_count && *key_count > total_keys; idx++) { element = RedisModule_CallReplyArrayElement(scan_results, idx); RedisModuleString *key = RedisModule_CreateStringFromCallReply(element); keys[total_keys] = key; total_keys++; } RedisModule_FreeCallReply(reply); } while(scan_idx != 0); /* Update number of stores fetched. */ *key_count = total_keys; }
RMUtilInfo *RMUtil_HGetAll(RedisModuleCtx *ctx, RedisModuleString *id) { RedisModuleCallReply *reply = RedisModule_Call(ctx, "HGETALL", "s", id); if(RedisModule_CallReplyType(reply) != REDISMODULE_REPLY_ARRAY) { printf("ERROE expecting an array \n"); return NULL; } size_t reply_len = RedisModule_CallReplyLength(reply); RMUtilInfo *hgetall = malloc(sizeof(RMUtilInfo)); hgetall->numEntries = reply_len/2; hgetall->entries = malloc(sizeof(RMUtilInfoEntry) * hgetall->numEntries); // Consume HGETALL for(int idx = 0; idx < reply_len; idx+=2) { RedisModuleCallReply *subreply; subreply = RedisModule_CallReplyArrayElement(reply, idx); size_t len; char *key = strdup(RedisModule_CallReplyStringPtr(subreply, &len)); key[len] = 0; hgetall->entries[idx/2].key = key; subreply = RedisModule_CallReplyArrayElement(reply, idx+1); char *val = strdup(RedisModule_CallReplyStringPtr(subreply, &len)); val[len] = 0; hgetall->entries[idx/2].val = val; } RedisModule_FreeCallReply(reply); return hgetall; }
/* HELLO.PUSH.CALL2 * This is exaxctly as HELLO.PUSH.CALL, but shows how we can reply to the * client using directly a reply object that Call() returned. */ int HelloPushCall2_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc != 3) return RedisModule_WrongArity(ctx); RedisModuleCallReply *reply; reply = RedisModule_Call(ctx,"RPUSH","ss",argv[1],argv[2]); RedisModule_ReplyWithCallReply(ctx,reply); RedisModule_FreeCallReply(reply); return REDISMODULE_OK; }
static int cmd_password_hcheck(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { RedisModuleCallReply *reply; if (argc != 4) { RedisModule_WrongArity(ctx); return REDISMODULE_OK; } reply = RedisModule_Call(ctx, "HGET", "ss", argv[1], argv[2]); validate(ctx, reply, argv[3]); return REDISMODULE_OK; }
int TestModule(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { RedisModule_AutoMemory(ctx); /* TODO: calling flushall but checking only for db 0. */ RedisModuleCallReply *r = RedisModule_Call(ctx, "DBSIZE", ""); if (RedisModule_CallReplyInteger(r) != 0) { RedisModule_ReplyWithError(ctx, "ERR test must be run on an empty instance"); return REDISMODULE_ERR; } RMUtil_Test(testMSIsMember); RedisModule_ReplyWithSimpleString(ctx, "PASS"); return REDISMODULE_OK; }
static int router_simple_command(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { RedisModule_AutoMemory(ctx); if (argc < 2) { RedisModule_WrongArity(ctx); return REDISMODULE_OK; } RedisModuleCallReply *reply; size_t len; const char *realCmd = RedisModule_StringPtrLen(argv[1], &len); if (argc == 2) { reply = RedisModule_Call(ctx, realCmd, ""); } else { char *fmt = (char *) malloc(argc-1); memset(fmt, 's', argc-2); fmt[argc-2] = '\0'; ffi_cif cif; ffi_type **ffi_argv = (ffi_type **)malloc(sizeof(ffi_type *) * (argc + 1)); void *result; int i; for (i = 0; i < argc+1; i++) { ffi_argv[i] = &ffi_type_pointer; } void **values = (void **) malloc(sizeof(void *) * (argc + 1)); values[0] = &ctx; values[1] = &realCmd; values[2] = &fmt; for (i = 3; i < argc + 1; i++) { values[i] = &argv[i-1]; } if (ffi_prep_cif(&cif, FFI_DEFAULT_ABI, (argc + 1), &ffi_type_pointer, ffi_argv) == FFI_OK) { ffi_call(&cif, FFI_FN(RedisModule_Call), &result, values); } reply = (RedisModuleCallReply *) result; } if (reply == NULL) { const char *err = "command error"; RedisModule_ReplyWithError(ctx, err); } else { RedisModule_ReplyWithCallReply(ctx, reply); } return REDISMODULE_OK; }
int testMSIsMember(RedisModuleCtx *ctx) { RedisModuleCallReply *r; r = RedisModule_Call(ctx, "msismember", "ccc", "s1", "s2", "ele"); RMUtil_Assert(RedisModule_CallReplyInteger(r) == 0); r = RedisModule_Call(ctx, "SADD", "ccc", "s1", "ele", "foo"); r = RedisModule_Call(ctx, "msismember", "ccc", "s1", "s2", "ele"); RMUtil_Assert(RedisModule_CallReplyInteger(r) == 1); r = RedisModule_Call(ctx, "SADD", "cc", "s2", "bar"); r = RedisModule_Call(ctx, "msismember", "ccc", "s1", "s2", "ele"); RMUtil_Assert(RedisModule_CallReplyInteger(r) == 1); r = RedisModule_Call(ctx, "SADD", "cc", "s2", "ele"); r = RedisModule_Call(ctx, "msismember", "ccc", "s1", "s2", "ele"); RMUtil_Assert(RedisModule_CallReplyInteger(r) == 2); r = RedisModule_Call(ctx, "FLUSHALL", ""); return 0; }
/* HELLO.LIST.SUM.LEN returns the total length of all the items inside * a Redis list, by using the high level Call() API. * This command is an example of the array reply access. */ int HelloListSumLen_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc != 2) return RedisModule_WrongArity(ctx); RedisModuleCallReply *reply; reply = RedisModule_Call(ctx,"LRANGE","sll",argv[1],(long long)0,(long long)-1); size_t strlen = 0; size_t items = RedisModule_CallReplyLength(reply); size_t j; for (j = 0; j < items; j++) { RedisModuleCallReply *ele = RedisModule_CallReplyArrayElement(reply,j); strlen += RedisModule_CallReplyLength(ele); } RedisModule_FreeCallReply(reply); RedisModule_ReplyWithLongLong(ctx,strlen); return REDISMODULE_OK; }
/* * MSISMEMBER key1 [key2 ...] member * Checks for membership in multiple sets. * Reply: Integer, the count of sets to which the member belongs. */ int MSIsMemberCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc < 3) { if (RedisModule_IsKeysPositionRequest(ctx)) /* TODO: handle this once the getkey-api allows signalling errors */ return REDISMODULE_OK; else return RedisModule_WrongArity(ctx); } if (RedisModule_IsKeysPositionRequest(ctx)) { size_t i; for (i = 1; i < argc - 1; i++) RedisModule_KeyAtPos(ctx, i); return REDISMODULE_OK; } RedisModule_AutoMemory(ctx); int iele = argc - 1; size_t count = 0; int i; for (i = 1; i < iele; i++) { RedisModuleKey *key = RedisModule_OpenKey(ctx, argv[i], REDISMODULE_READ | REDISMODULE_WRITE); if (RedisModule_KeyType(key) == REDISMODULE_KEYTYPE_EMPTY) continue; if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_SET) { RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE); return REDISMODULE_ERR; } RedisModuleCallReply *rep = RedisModule_Call(ctx, "SISMEMBER", "ss", argv[i], argv[iele]); RMUTIL_ASSERT_NOERROR(rep) count += RedisModule_CallReplyInteger(rep); } RedisModule_ReplyWithLongLong(ctx, count); return REDISMODULE_OK; }
static int cmd_password_hset(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { RedisModuleCallReply *reply; size_t len; char crypt_buf[64]; char *hash; if (argc != 4) { RedisModule_WrongArity(ctx); return REDISMODULE_OK; } hash = do_crypt(RedisModule_StringPtrLen(argv[3], &len), crypt_buf, sizeof(crypt_buf)); if (!hash) { RedisModule_ReplyWithError(ctx, "ERR hash error"); return REDISMODULE_ERR; } reply = RedisModule_Call(ctx, "HSET", "ssc!", argv[1], argv[2], hash); RedisModule_ReplyWithCallReply(ctx, reply); return REDISMODULE_OK; }
RMUtilInfo *RMUtil_GetRedisInfo(RedisModuleCtx *ctx) { RedisModuleCallReply *r = RedisModule_Call(ctx, "INFO", "c", "all"); if (r == NULL || RedisModule_CallReplyType(r) == REDISMODULE_REPLY_ERROR) { return NULL; } int cap = 100; // rough estimate of info lines RMUtilInfo *info = malloc(sizeof(RMUtilInfo)); info->entries = calloc(cap, sizeof(RMUtilInfoEntry)); int i = 0; char *text = (char *)RedisModule_StringPtrLen(RedisModule_CreateStringFromCallReply(r), NULL); char *line = text; while (line) { char *line = strsep(&text, "\r\n"); if (line == NULL) break; if (!(*line >= 'a' && *line <= 'z')) { //skip non entry lines continue; } char *key = strsep(&line, ":"); info->entries[i].key = key; info->entries[i].val = line; printf("Got info '%s' = '%s'\n", key, line); i++; if (i >= cap) { cap *=2; info->entries = realloc(info->entries, cap*sizeof(RMUtilInfoEntry)); } } info->numEntries = i; return info; }