Permalink
Browse files

implemented status/error/integer reply parsers.

  • Loading branch information...
0 parents commit 70028fd1b0e17b8513e4ad08ce67805f7f9a0afd @agentzh agentzh committed Dec 19, 2010
Showing with 431 additions and 0 deletions.
  1. +7 −0 .gitignore
  2. +58 −0 Makefile
  3. +27 −0 README
  4. +14 −0 ddebug.h
  5. +213 −0 redis-parser.c
  6. +112 −0 t/sanity.t
@@ -0,0 +1,7 @@
+*.swp
+*.so
+*.lo
+*~
+reindex
+test_case.lua
+tags
@@ -0,0 +1,58 @@
+version=0.01
+name=lua-redis-parser
+dist=$(name)-$(version)
+
+.PHONE: all clean dist test
+
+#CC = gcc
+RM = rm -f
+
+# Gives a nice speedup, but also spoils debugging on x86. Comment out this
+# line when debugging.
+OMIT_FRAME_POINTER = -fomit-frame-pointer
+
+# Name of .pc file. "lua5.1" on Debian/Ubuntu
+#LUAPKG = lua5.1
+#CFLAGS = `pkg-config $(LUAPKG) --cflags` -fPIC -O3 -Wall
+#LFLAGS = -shared $(OMIT_FRAME_POINTER)
+#INSTALL_PATH = `pkg-config $(LUAPKG) --variable=INSTALL_CMOD`
+
+## If your system doesn't have pkg-config, comment out the previous lines and
+## uncomment and change the following ones according to your building
+## enviroment.
+
+CFLAGS=-I/usr/include/lua5.1/ -O2 -fPIC -Wall -Werror
+LFLAGS=-shared $(OMIT_FRAME_POINTER)
+INSTALL_PATH=/usr/lib/lua/5.1
+CC=gcc
+
+all: parser.so
+
+parser.lo: redis-parser.c ddebug.h
+ $(CC) $(CFLAGS) -o parser.lo -c $<
+
+parser.so: parser.lo
+ $(CC) -o parser.so $(LFLAGS) $(LIBS) $<
+
+install: parser.so
+ install -D -s parser.so $(DESTDIR)$(INSTALL_PATH)/lz/parser.so
+
+clean:
+ $(RM) *.so *.lo lz/*.so
+
+test: parser.so
+ if [ ! -d redis ]; then mkdir redis; fi
+ cp parser.so redis/
+ prove -r t
+
+valtest: parser.so
+ if [ ! -d lz ]; then mkdir lz; fi
+ cp parser.so lz/
+ TEST_LUA_USE_VALGRIND=1 prove -r t
+
+dist:
+ if [ -d $(dist) ]; then rm -r $(dist); fi
+ mkdir $(dist)
+ cp *.c *.h Makefile $(dist)/
+ tar czvf $(dist).tar.gz $(dist)/
+
@@ -0,0 +1,27 @@
+lua-redis-parser
+
+This lua library implementes simple redis response parsers
+that construct corresponding lua data strucutres.
+
+ local parser = require('redis.parser')
+ local res, typ = parser.parse_reply(reply)
+ if typ == parser.BAD_REPLY then
+ ...
+ elseif typ == parser.INTEGER_REPLY then
+ ...
+ elseif typ == parser.ERROR_REPLY then
+ ...
+ elseif typ == parser.STATUS_REPLY then
+ ...
+ elsif typ == parser.BULK_REPLY then
+ ...
+ elseif typ == parser.MULTI_BULK_REPLY then
+ ...
+ end
+
+This module is originally written for ngx_lua + ngx_redis2:
+
+ http://github.com/chaoslawful/lua-nginx-module
+
+ https://github.com/agentzh/redis2-nginx-module
+
@@ -0,0 +1,14 @@
+#if defined(DDEBUG) && (DDEBUG)
+
+# include <stdio.h>
+
+# define dd(...) \
+ fprintf(stderr, __VA_ARGS__); \
+ fprintf(stderr, "\n")
+
+#else
+
+# define dd(fmt, ...)
+
+#endif
+
@@ -0,0 +1,213 @@
+#define DDEBUG 0
+#include "ddebug.h"
+
+#include <lua.h>
+#include <lauxlib.h>
+#include <stdlib.h>
+#include <string.h>
+
+
+enum {
+ BAD_REPLY = 0,
+ STATUS_REPLY = 1,
+ ERROR_REPLY = 2,
+ INTEGER_REPLY = 3,
+ BULK_REPLY = 4,
+ MULTI_BULK_REPLY = 5,
+};
+
+
+static int redis_parse_reply(lua_State *L);
+static const char * parse_single_line_reply(const char *src, const char *last,
+ size_t *dst_len);
+static const char * parse_bulk_reply(const char *src, const char *last,
+ size_t *dst_len);
+static const char * parse_multi_bulk_reply(const char *src, const char *last,
+ size_t *dst_len);
+
+
+static const struct luaL_Reg redis_parser[] = {
+ {"parse_reply", redis_parse_reply},
+ {NULL, NULL}
+};
+
+
+int
+luaopen_redis_parser(lua_State *L)
+{
+ luaL_register(L, "redis.parser", redis_parser);
+
+ lua_pushnumber(L, BAD_REPLY);
+ lua_setfield(L, -2, "BAD_REPLY");
+
+ lua_pushnumber(L, STATUS_REPLY);
+ lua_setfield(L, -2, "STATUS_REPLY");
+
+ lua_pushnumber(L, ERROR_REPLY);
+ lua_setfield(L, -2, "ERROR_REPLY");
+
+ lua_pushnumber(L, INTEGER_REPLY);
+ lua_setfield(L, -2, "INTEGER_REPLY");
+
+ lua_pushnumber(L, BULK_REPLY);
+ lua_setfield(L, -2, "BULK_REPLY");
+
+ lua_pushnumber(L, MULTI_BULK_REPLY);
+ lua_setfield(L, -2, "MULTI_BULK_REPLY");
+
+ return 1;
+}
+
+
+static int
+redis_parse_reply(lua_State *L)
+{
+ const char *p, *last;
+ size_t len;
+ const char *dst;
+ size_t dst_len;
+ lua_Number num;
+
+ if (lua_gettop(L) != 1) {
+ return luaL_error(L, "expected one argument but got %d",
+ lua_gettop(L));
+ }
+
+ p = luaL_checklstring(L, 1, &len);
+
+ if (len == 0) {
+ lua_pushliteral(L, "empty reply");
+ lua_pushnumber(L, BAD_REPLY);
+ return 2;
+ }
+
+ last = p + len;
+
+ switch (*p) {
+ case '+':
+ p++;
+ dst = parse_single_line_reply(p, last, &dst_len);
+
+ if (dst == NULL) {
+ lua_pushliteral(L, "bad status reply");
+ lua_pushnumber(L, BAD_REPLY);
+ return 2;
+ }
+
+ lua_pushlstring(L, dst, dst_len);
+ lua_pushnumber(L, STATUS_REPLY);
+ break;
+
+ case '-':
+ p++;
+ dst = parse_single_line_reply(p, last, &dst_len);
+
+ if (dst == NULL) {
+ lua_pushliteral(L, "bad error reply");
+ lua_pushnumber(L, BAD_REPLY);
+ return 2;
+ }
+
+ lua_pushlstring(L, dst, dst_len);
+ lua_pushnumber(L, ERROR_REPLY);
+ break;
+
+ case ':':
+ p++;
+ dst = parse_single_line_reply(p, last, &dst_len);
+
+ if (dst == NULL) {
+ lua_pushliteral(L, "bad integer reply");
+ lua_pushnumber(L, BAD_REPLY);
+ return 2;
+ }
+
+ lua_pushlstring(L, dst, dst_len);
+ num = lua_tonumber(L, -1);
+ lua_pushnumber(L, num);
+ lua_pushnumber(L, INTEGER_REPLY);
+ break;
+
+ case '$':
+ p++;
+ dst = parse_bulk_reply(p, last, &dst_len);
+
+ if (dst == NULL) {
+ lua_pushliteral(L, "bad bulk reply");
+ lua_pushnumber(L, BAD_REPLY);
+ return 2;
+ }
+
+ lua_pushlstring(L, dst, dst_len);
+ lua_pushnumber(L, BULK_REPLY);
+ break;
+
+ case '*':
+ p++;
+ dst = parse_multi_bulk_reply(p, last, &dst_len);
+
+ if (dst == NULL) {
+ lua_pushliteral(L, "bad multi bulk reply");
+ lua_pushnumber(L, BAD_REPLY);
+ return 2;
+ }
+
+ lua_pushlstring(L, dst, dst_len);
+ lua_pushnumber(L, MULTI_BULK_REPLY);
+ break;
+
+ default:
+ lua_pushliteral(L, "empty reply");
+ lua_pushnumber(L, BAD_REPLY);
+ break;
+ }
+
+ return 2;
+}
+
+
+static const char *
+parse_single_line_reply(const char *src, const char *last, size_t *dst_len)
+{
+ const char *p = src;
+ int seen_cr = 0;
+
+ while (p != last) {
+
+ if (*p == '\r') {
+ seen_cr = 1;
+
+ } else if (seen_cr) {
+ if (*p == '\n') {
+ *dst_len = p - src - 1;
+ return src;
+ }
+
+ seen_cr = 0;
+ }
+
+ p++;
+ }
+
+ /* CRLF not found at all */
+ *dst_len = 0;
+ return NULL;
+}
+
+
+static const char *
+parse_bulk_reply(const char *src, const char *last, size_t *dst_len)
+{
+ /* TODO */
+ return NULL;
+}
+
+
+static const char *
+parse_multi_bulk_reply(const char *src, const char *last,
+ size_t *dst_len)
+{
+ /* TODO */
+ return NULL;
+}
+
Oops, something went wrong.

0 comments on commit 70028fd

Please sign in to comment.