diff --git a/Makefile b/Makefile index ee3171b..44018fb 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ OUT=radish OBJS=radish.o hiredis/hiredis.o hiredis/sds.o hiredis/net.o hiredis/async.o -CFLAGS=-O3 -Wall -Wextra -I. +CFLAGS=-O0 -ggdb -Wall -Wextra -I. LDFLAGS=-levent prefix=/usr diff --git a/radish.c b/radish.c index 79851e8..4e52fd4 100644 --- a/radish.c +++ b/radish.c @@ -10,24 +10,135 @@ #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 evbuffer *body; struct evkeyvalq headers; const char *uri = evhttp_request_uri(rq); - evhttp_parse_query(uri, &headers); + /* get context */ + redisAsyncContext *c = ctx; + + /* parse URI */ + evhttp_parse_query(uri, &headers); - /* send reply */ - body = evbuffer_new(); - evbuffer_add(body, "hello world\n", 12); - evhttp_send_reply(rq, 200, "OK", body); - evbuffer_free(body); + 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); @@ -42,10 +153,14 @@ main(int argc, char *argv[]) { /* start http server */ evhttp_bind_socket(http, "0.0.0.0", 7379); - evhttp_set_gencb(http, on_request, NULL); + 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;