#include #include #include #include #include #include #include #include #include #include static void cmdCallback(redisAsyncContext *c, void *r, void *privdata) { (void)c; struct evbuffer *body; redisReply *reply = r; struct evhttp_request *rq = privdata; if (reply == NULL) { evhttp_send_reply(rq, 404, "Not Found", NULL); return; } switch(reply->type) { case REDIS_REPLY_STRING: case REDIS_REPLY_STATUS: /* send reply */ body = evbuffer_new(); evbuffer_add(body, reply->str, strlen(reply->str)); evhttp_send_reply(rq, 200, "OK", body); evbuffer_free(body); break; default: evhttp_send_reply(rq, 500, "Unknown redis format", NULL); } } static void connectCallback(const redisAsyncContext *c) { ((void)c); printf("connected...\n"); } static void disconnectCallback(const redisAsyncContext *c, int status) { if (status != REDIS_OK) { printf("Error: %s\n", c->errstr); } printf("disconnected...\n"); } void run_async_command(redisAsyncContext *c, struct evhttp_request *rq, const char *uri) { int uri_len = strlen(uri); char *slash = strchr(uri + 1, '/'); char *cmd; int cmd_len; int param_count = 0, cur_param = 1; const char **arguments; size_t *argument_sizes; const char *p; /* count arguments */ for(p = uri; p && p < uri + uri_len; param_count++) { p = strchr(p+1, '/'); } arguments = malloc(param_count * sizeof(char*)); argument_sizes = malloc(param_count * sizeof(size_t)); if(slash) { cmd_len = slash - uri - 1; } else { cmd_len = uri_len - 1; } cmd = calloc(1 + cmd_len, 1); memcpy(cmd, uri + 1, cmd_len); /* there is always a first parameter, it's the command name */ arguments[0] = cmd; argument_sizes[0] = cmd_len; if(!slash) { redisAsyncCommandArgv(c, cmdCallback, rq, 1, arguments, argument_sizes); } p = slash + 1; while(p < uri + uri_len) { const char *arg = p; int arg_len; char *next = strchr(arg, '/'); if(next) { arg_len = next - arg; p = next + 1; } else { arg_len = uri + uri_len - arg; p = uri + uri_len; } /* record argument */ arguments[cur_param] = arg; argument_sizes[cur_param] = arg_len; cur_param++; } redisAsyncCommandArgv(c, cmdCallback, rq, param_count, arguments, argument_sizes); } void on_request(struct evhttp_request *rq, void *ctx) { struct evkeyvalq headers; const char *uri = evhttp_request_uri(rq); /* get context */ redisAsyncContext *c = ctx; /* parse URI */ evhttp_parse_query(uri, &headers); if(rq->type == EVHTTP_REQ_GET) { /* run async command */ run_async_command(c, rq, uri); } } int main(int argc, char *argv[]) { (void)argc; (void)argv; struct event_base *base = event_base_new(); struct evhttp *http = evhttp_new(base); redisAsyncContext *c = redisAsyncConnect("127.0.0.1", 6379); if(c->err) { /* Let *c leak for now... */ printf("Error: %s\n", c->errstr); return 1; } /* start http server */ evhttp_bind_socket(http, "0.0.0.0", 7379); evhttp_set_gencb(http, on_request, c); /* attach hiredis to libevent base */ redisLibeventAttach(c, base); redisAsyncSetConnectCallback(c, connectCallback); redisAsyncSetDisconnectCallback(c, disconnectCallback); /* loop */ event_base_dispatch(base); return EXIT_SUCCESS; }