Exported API to call any Redis command from modules. * * * **cmdname**: The Redis command to call. * * **fmt**: A format specifier string for the command's arguments. Each * of the arguments should be specified by a valid type specification. The * format specifier can also contain the modifiers `!`, `A` and `R` which * don't have a corresponding argument. * * * `b` -- The argumen
| 4082 | * This API is documented here: https://redis.io/topics/modules-intro |
| 4083 | */ |
| 4084 | RedisModuleCallReply *RM_Call(RedisModuleCtx *ctx, const char *cmdname, const char *fmt, ...) { |
| 4085 | struct redisCommand *cmd; |
| 4086 | client *c = NULL; |
| 4087 | robj **argv = NULL; |
| 4088 | int argc = 0, flags = 0; |
| 4089 | va_list ap; |
| 4090 | RedisModuleCallReply *reply = NULL; |
| 4091 | int replicate = 0; /* Replicate this command? */ |
| 4092 | |
| 4093 | /* Handle arguments. */ |
| 4094 | va_start(ap, fmt); |
| 4095 | argv = moduleCreateArgvFromUserFormat(cmdname,fmt,&argc,&flags,ap); |
| 4096 | replicate = flags & REDISMODULE_ARGV_REPLICATE; |
| 4097 | va_end(ap); |
| 4098 | |
| 4099 | /* Setup our fake client for command execution. */ |
| 4100 | if (server.module_client == NULL) { |
| 4101 | /* This is the first RM_Call() ever. Create reusable client. */ |
| 4102 | c = server.module_client = createClient(NULL); |
| 4103 | } else if (server.module_client->argv == NULL) { |
| 4104 | /* The reusable module client is not busy with a command. Use it. */ |
| 4105 | c = server.module_client; |
| 4106 | } else { |
| 4107 | /* The reusable module client is busy. (It is probably used in a |
| 4108 | * recursive call to this module.) */ |
| 4109 | c = createClient(NULL); |
| 4110 | } |
| 4111 | c->user = NULL; /* Root user. */ |
| 4112 | c->flags = CLIENT_MODULE; |
| 4113 | |
| 4114 | /* We do not want to allow block, the module do not expect it */ |
| 4115 | c->flags |= CLIENT_DENY_BLOCKING; |
| 4116 | c->db = ctx->client->db; |
| 4117 | c->argv = argv; |
| 4118 | c->argc = argc; |
| 4119 | if (ctx->module) ctx->module->in_call++; |
| 4120 | |
| 4121 | /* We handle the above format error only when the client is setup so that |
| 4122 | * we can free it normally. */ |
| 4123 | if (argv == NULL) { |
| 4124 | errno = EBADF; |
| 4125 | goto cleanup; |
| 4126 | } |
| 4127 | |
| 4128 | /* Call command filters */ |
| 4129 | moduleCallCommandFilters(c); |
| 4130 | |
| 4131 | /* Lookup command now, after filters had a chance to make modifications |
| 4132 | * if necessary. |
| 4133 | */ |
| 4134 | cmd = lookupCommand(c->argv[0]->ptr); |
| 4135 | if (!cmd) { |
| 4136 | errno = ENOENT; |
| 4137 | goto cleanup; |
| 4138 | } |
| 4139 | c->cmd = c->lastcmd = cmd; |
| 4140 | |
| 4141 | /* Basic arity checks. */ |
nothing calls this directly
no test coverage detected