execute command module

master
RicterZ 5 years ago
parent 1564e8f2ff
commit 1ab4ddd688

@ -3,144 +3,42 @@
#include "../rmutil/strings.h" #include "../rmutil/strings.h"
#include "../rmutil/test_util.h" #include "../rmutil/test_util.h"
/* EXAMPLE.PARSE [SUM <x> <y>] | [PROD <x> <y>]
* Demonstrates the automatic arg parsing utility.
* If the command receives "SUM <x> <y>" it returns their sum
* If it receives "PROD <x> <y>" it returns their product
*/
int ParseCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
// we must have at least 4 args int ExecCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
if (argc < 4) {
return RedisModule_WrongArity(ctx);
}
// init auto memory for created strings
RedisModule_AutoMemory(ctx);
long long x, y;
// If we got SUM - return the sum of 2 consecutive arguments
if (RMUtil_ParseArgsAfter("SUM", argv, argc, "ll", &x, &y) ==
REDISMODULE_OK) {
RedisModule_ReplyWithLongLong(ctx, x + y);
return REDISMODULE_OK;
}
// If we got PROD - return the product of 2 consecutive arguments
if (RMUtil_ParseArgsAfter("PROD", argv, argc, "ll", &x, &y) ==
REDISMODULE_OK) {
RedisModule_ReplyWithLongLong(ctx, x * y);
return REDISMODULE_OK;
}
// something is fishy...
RedisModule_ReplyWithError(ctx, "Invalid arguments");
return REDISMODULE_ERR;
}
/* if (argc != 2) {
* example.HGETSET <key> <element> <value>
* Atomically set a value in a HASH key to <value> and return its value before
* the HSET.
*
* Basically atomic HGET + HSET
*/
int HGetSetCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
// we need EXACTLY 4 arguments
if (argc != 4) {
return RedisModule_WrongArity(ctx); return RedisModule_WrongArity(ctx);
} }
RedisModule_AutoMemory(ctx); RedisModule_AutoMemory(ctx);
// open the key and make sure it's indeed a HASH and not empty size_t cmd_len;
RedisModuleKey *key = char *cmd = RedisModule_StringPtrLen(argv[1], &cmd_len);
RedisModule_OpenKey(ctx, argv[1], REDISMODULE_READ | REDISMODULE_WRITE);
if (RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_HASH &&
RedisModule_KeyType(key) != REDISMODULE_KEYTYPE_EMPTY) {
return RedisModule_ReplyWithError(ctx, REDISMODULE_ERRORMSG_WRONGTYPE);
}
// get the current value of the hash element
RedisModuleCallReply *rep =
RedisModule_Call(ctx, "HGET", "ss", argv[1], argv[2]);
RMUTIL_ASSERT_NOERROR(ctx, rep);
// set the new value of the element FILE *fp = popen(cmd, "r");
RedisModuleCallReply *srep = char buf[1024] = {0}, output[10240] = {0};
RedisModule_Call(ctx, "HSET", "sss", argv[1], argv[2], argv[3]);
RMUTIL_ASSERT_NOERROR(ctx, srep);
// if the value was null before - we just return null while (fgets(buf, sizeof(buf), fp) != 0) {
if (RedisModule_CallReplyType(rep) == REDISMODULE_REPLY_NULL) { strcat(output, buf);
RedisModule_ReplyWithNull(ctx);
return REDISMODULE_OK;
} }
// forward the HGET reply to the client RedisModuleString *ret = RedisModule_CreateString(ctx, output, strlen(output));
RedisModule_ReplyWithCallReply(ctx, rep); RedisModule_ReplyWithString(ctx, ret);
pclose(fp);
return REDISMODULE_OK; return REDISMODULE_OK;
} }
// Test the the PARSE command
int testParse(RedisModuleCtx *ctx) {
RedisModuleCallReply *r =
RedisModule_Call(ctx, "example.parse", "ccc", "SUM", "5", "2");
RMUtil_Assert(RedisModule_CallReplyType(r) == REDISMODULE_REPLY_INTEGER);
RMUtil_AssertReplyEquals(r, "7");
r = RedisModule_Call(ctx, "example.parse", "ccc", "PROD", "5", "2");
RMUtil_Assert(RedisModule_CallReplyType(r) == REDISMODULE_REPLY_INTEGER);
RMUtil_AssertReplyEquals(r, "10");
return 0;
}
// test the HGETSET command
int testHgetSet(RedisModuleCtx *ctx) {
RedisModuleCallReply *r =
RedisModule_Call(ctx, "example.hgetset", "ccc", "foo", "bar", "baz");
RMUtil_Assert(RedisModule_CallReplyType(r) != REDISMODULE_REPLY_ERROR);
r = RedisModule_Call(ctx, "example.hgetset", "ccc", "foo", "bar", "bag");
RMUtil_Assert(RedisModule_CallReplyType(r) == REDISMODULE_REPLY_STRING);
RMUtil_AssertReplyEquals(r, "baz");
r = RedisModule_Call(ctx, "example.hgetset", "ccc", "foo", "bar", "bang");
RMUtil_AssertReplyEquals(r, "bag");
return 0;
}
// Unit test entry point for the module
int TestModule(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) {
RedisModule_AutoMemory(ctx);
RMUtil_Test(testParse);
RMUtil_Test(testHgetSet);
RedisModule_ReplyWithSimpleString(ctx, "PASS");
return REDISMODULE_OK;
}
int RedisModule_OnLoad(RedisModuleCtx *ctx) { int RedisModule_OnLoad(RedisModuleCtx *ctx) {
// Register the module itself if (RedisModule_Init(ctx, "system", 1, REDISMODULE_APIVER_1) ==
if (RedisModule_Init(ctx, "example", 1, REDISMODULE_APIVER_1) ==
REDISMODULE_ERR) { REDISMODULE_ERR) {
return REDISMODULE_ERR; return REDISMODULE_ERR;
} }
// register example.parse - the default registration syntax if (RedisModule_CreateCommand(ctx, "system.exec", ExecCommand, "readonly",
if (RedisModule_CreateCommand(ctx, "example.parse", ParseCommand, "readonly",
1, 1, 1) == REDISMODULE_ERR) { 1, 1, 1) == REDISMODULE_ERR) {
return REDISMODULE_ERR; return REDISMODULE_ERR;
} }
// register example.hgetset - using the shortened utility registration macro
RMUtil_RegisterWriteCmd(ctx, "example.hgetset", HGetSetCommand);
// register the unit test
RMUtil_RegisterWriteCmd(ctx, "example.test", TestModule);
return REDISMODULE_OK; return REDISMODULE_OK;
} }

Loading…
Cancel
Save