#include "redismodule.h" #include #include /* See moduleconfigs.c for registering module configs. We need to register some * module configs with our module in order to test the interaction between * module configs and the RM_Get/Set*Config APIs. */ int configaccess_bool; int getBoolConfigCommand(const char *name, void *privdata) { REDISMODULE_NOT_USED(name); return (*(int *)privdata); } int setBoolConfigCommand(const char *name, int new, void *privdata, RedisModuleString **err) { REDISMODULE_NOT_USED(name); REDISMODULE_NOT_USED(err); *(int *)privdata = new; return REDISMODULE_OK; } /* Test command for RM_GetConfigType */ int TestGetConfigType_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc != 2) { return RedisModule_WrongArity(ctx); } size_t len; const char *config_name = RedisModule_StringPtrLen(argv[1], &len); RedisModuleConfigType type; int res = RedisModule_ConfigGetType(config_name, &type); if (res == REDISMODULE_ERR) { RedisModule_ReplyWithError(ctx, "ERR Config does not exist"); return REDISMODULE_ERR; } const char *type_str; switch (type) { case REDISMODULE_CONFIG_TYPE_BOOL: type_str = "bool"; break; case REDISMODULE_CONFIG_TYPE_NUMERIC: type_str = "numeric"; break; case REDISMODULE_CONFIG_TYPE_STRING: type_str = "string"; break; case REDISMODULE_CONFIG_TYPE_ENUM: type_str = "enum"; break; default: assert(0); break; } RedisModule_ReplyWithSimpleString(ctx, type_str); return REDISMODULE_OK; } /* Test command for config iteration */ int TestConfigIteration_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { REDISMODULE_NOT_USED(argv); if (argc > 2) { return RedisModule_WrongArity(ctx); } const char *pattern = NULL; if (argc == 2) { pattern = RedisModule_StringPtrLen(argv[1], NULL); } RedisModuleConfigIterator *iter = RedisModule_ConfigIteratorCreate(ctx, pattern); if (!iter) { RedisModule_ReplyWithError(ctx, "ERR Failed to get config iterator"); return REDISMODULE_ERR; } /* Start array reply for the configs */ RedisModule_ReplyWithArray(ctx, REDISMODULE_POSTPONED_ARRAY_LEN); /* Iterate through the dictionary */ const char *config_name = NULL; long count = 0; while ((config_name = RedisModule_ConfigIteratorNext(iter)) != NULL) { RedisModuleString *value = NULL; RedisModule_ConfigGet(ctx, config_name, &value); RedisModule_ReplyWithArray(ctx, 2); RedisModule_ReplyWithStringBuffer(ctx, config_name, strlen(config_name)); RedisModule_ReplyWithString(ctx, value); RedisModule_FreeString(ctx, value); ++count; } RedisModule_ReplySetArrayLength(ctx, count); /* Free the iterator */ RedisModule_ConfigIteratorRelease(ctx, iter); return REDISMODULE_OK; } /* Test command for RM_GetBoolConfig */ int TestGetBoolConfig_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc != 2) { return RedisModule_WrongArity(ctx); } size_t len; const char *config_name = RedisModule_StringPtrLen(argv[1], &len); int value; if (RedisModule_ConfigGetBool(ctx, config_name, &value) == REDISMODULE_ERR) { RedisModule_ReplyWithError(ctx, "ERR Failed to get bool config"); return REDISMODULE_ERR; } RedisModule_ReplyWithLongLong(ctx, value); return REDISMODULE_OK; } /* Test command for RM_GetNumericConfig */ int TestGetNumericConfig_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc != 2) { return RedisModule_WrongArity(ctx); } size_t len; const char *config_name = RedisModule_StringPtrLen(argv[1], &len); long long value; if (RedisModule_ConfigGetNumeric(ctx, config_name, &value) == REDISMODULE_ERR) { RedisModule_ReplyWithError(ctx, "ERR Failed to get numeric config"); return REDISMODULE_ERR; } RedisModule_ReplyWithLongLong(ctx, value); return REDISMODULE_OK; } /* Test command for RM_GetConfig */ int TestGetConfig_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc != 2) { return RedisModule_WrongArity(ctx); } size_t len; const char *config_name = RedisModule_StringPtrLen(argv[1], &len); RedisModuleString *value; if (RedisModule_ConfigGet(ctx, config_name, &value) == REDISMODULE_ERR) { RedisModule_ReplyWithError(ctx, "ERR Failed to get string config"); return REDISMODULE_ERR; } RedisModule_ReplyWithString(ctx, value); RedisModule_FreeString(ctx,value); return REDISMODULE_OK; } /* Test command for RM_GetEnumConfig */ int TestGetEnumConfig_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc != 2) { return RedisModule_WrongArity(ctx); } size_t len; const char *config_name = RedisModule_StringPtrLen(argv[1], &len); RedisModuleString *value; if (RedisModule_ConfigGetEnum(ctx, config_name, &value) == REDISMODULE_ERR) { RedisModule_ReplyWithError(ctx, "ERR Failed to get enum name config"); return REDISMODULE_ERR; } RedisModule_ReplyWithString(ctx, value); RedisModule_Free(value); return REDISMODULE_OK; } /* Test command for RM_SetBoolConfig */ int TestSetBoolConfig_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc != 3) { return RedisModule_WrongArity(ctx); } size_t name_len, value_len; const char *config_name = RedisModule_StringPtrLen(argv[1], &name_len); const char *config_value = RedisModule_StringPtrLen(argv[2], &value_len); int bool_value; if (!strcasecmp(config_value, "yes")) { bool_value = 1; } else if (!strcasecmp(config_value, "no")) { bool_value = 0; } else { bool_value = -1; } RedisModuleString *error = NULL; int result = RedisModule_ConfigSetBool(ctx, config_name, bool_value, &error); if (result == REDISMODULE_ERR) { RedisModule_ReplyWithErrorFormat(ctx, "ERR Failed to set bool config %s: %s", config_name, RedisModule_StringPtrLen(error, NULL)); RedisModule_FreeString(ctx, error); return REDISMODULE_ERR; } RedisModule_ReplyWithSimpleString(ctx, "OK"); return REDISMODULE_OK; } /* Test command for RM_SetNumericConfig */ int TestSetNumericConfig_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc != 3) { return RedisModule_WrongArity(ctx); } size_t name_len; const char *config_name = RedisModule_StringPtrLen(argv[1], &name_len); long long value; const char *value_str= RedisModule_StringPtrLen(argv[2], NULL); if (value_str[0] == '-') { if (RedisModule_StringToLongLong(argv[2], &value) != REDISMODULE_OK) { RedisModule_ReplyWithError(ctx, "ERR Invalid numeric value"); return REDISMODULE_ERR; } } else { if (RedisModule_StringToULongLong(argv[2], (unsigned long long*)&value) != REDISMODULE_OK) { RedisModule_ReplyWithError(ctx, "ERR Invalid numeric value"); return REDISMODULE_ERR; } } RedisModuleString *error = NULL; int result = RedisModule_ConfigSetNumeric(ctx, config_name, value, &error); if (result == REDISMODULE_OK) { RedisModule_ReplyWithSimpleString(ctx, "OK"); } else { RedisModule_ReplyWithErrorFormat(ctx, "ERR Failed to set numeric config %s: %s", config_name, RedisModule_StringPtrLen(error, NULL)); RedisModule_FreeString(ctx, error); return REDISMODULE_ERR; } return REDISMODULE_OK; } /* Test command for RM_SetConfig */ int TestSetConfig_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc != 3) { return RedisModule_WrongArity(ctx); } size_t name_len; const char *config_name = RedisModule_StringPtrLen(argv[1], &name_len); RedisModuleString *error = NULL; int result = RedisModule_ConfigSet(ctx, config_name, argv[2], &error); if (result == REDISMODULE_OK) { RedisModule_ReplyWithSimpleString(ctx, "OK"); } else { RedisModule_ReplyWithErrorFormat(ctx, "ERR Failed to set string config %s: %s", config_name, RedisModule_StringPtrLen(error, NULL)); RedisModule_FreeString(ctx, error); return REDISMODULE_ERR; } return REDISMODULE_OK; } /* Test command for RM_SetEnumConfig with name */ int TestSetEnumConfig_RedisCommand(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { if (argc < 3) { return RedisModule_WrongArity(ctx); } const char *config_name = RedisModule_StringPtrLen(argv[1], NULL); RedisModuleString *error = NULL; int result = RedisModule_ConfigSetEnum(ctx, config_name, argv[2], &error); if (result == REDISMODULE_OK) { RedisModule_ReplyWithSimpleString(ctx, "OK"); } else { RedisModule_ReplyWithErrorFormat(ctx, "ERR Failed to set enum config %s: %s", config_name, RedisModule_StringPtrLen(error, NULL)); RedisModule_FreeString(ctx, error); return REDISMODULE_ERR; } return REDISMODULE_OK; } int RedisModule_OnLoad(RedisModuleCtx *ctx, RedisModuleString **argv, int argc) { REDISMODULE_NOT_USED(argv); REDISMODULE_NOT_USED(argc); if (RedisModule_Init(ctx, "configaccess", 1, REDISMODULE_APIVER_1) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedisModule_CreateCommand(ctx, "configaccess.getconfigs", TestConfigIteration_RedisCommand, "readonly", 0, 0, 0) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedisModule_CreateCommand(ctx, "configaccess.getbool", TestGetBoolConfig_RedisCommand, "readonly", 0, 0, 0) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedisModule_CreateCommand(ctx, "configaccess.getnumeric", TestGetNumericConfig_RedisCommand, "readonly", 0, 0, 0) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedisModule_CreateCommand(ctx, "configaccess.get", TestGetConfig_RedisCommand, "readonly", 0, 0, 0) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedisModule_CreateCommand(ctx, "configaccess.getenum", TestGetEnumConfig_RedisCommand, "readonly", 0, 0, 0) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedisModule_CreateCommand(ctx, "configaccess.setbool", TestSetBoolConfig_RedisCommand, "write", 0, 0, 0) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedisModule_CreateCommand(ctx, "configaccess.setnumeric", TestSetNumericConfig_RedisCommand, "write", 0, 0, 0) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedisModule_CreateCommand(ctx, "configaccess.set", TestSetConfig_RedisCommand, "write", 0, 0, 0) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedisModule_CreateCommand(ctx, "configaccess.setenum", TestSetEnumConfig_RedisCommand, "write", 0, 0, 0) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedisModule_CreateCommand(ctx, "configaccess.getconfigtype", TestGetConfigType_RedisCommand, "readonly", 0, 0, 0) == REDISMODULE_ERR) return REDISMODULE_ERR; if (RedisModule_RegisterBoolConfig(ctx, "bool", 1, REDISMODULE_CONFIG_DEFAULT, getBoolConfigCommand, setBoolConfigCommand, NULL, &configaccess_bool) == REDISMODULE_ERR) { RedisModule_Log(ctx, "warning", "Failed to register configaccess_bool"); return REDISMODULE_ERR; } RedisModule_Log(ctx, "debug", "Loading configaccess module configuration"); if (RedisModule_LoadConfigs(ctx) == REDISMODULE_ERR) { RedisModule_Log(ctx, "warning", "Failed to load configaccess module configuration"); return REDISMODULE_ERR; } return REDISMODULE_OK; }