File: redis.lua

package info (click to toggle)
nmap 6.00-0.3%2Bdeb7u1
  • links: PTS, VCS
  • area: main
  • in suites: wheezy
  • size: 55,576 kB
  • sloc: ansic: 108,190; cpp: 60,191; sh: 19,314; python: 16,531; xml: 9,428; makefile: 2,473; perl: 1,980; yacc: 608; lex: 469; asm: 372
file content (143 lines) | stat: -rw-r--r-- 3,139 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
--- A minimalistic Redis (in-memory key-value data store) library.
--
-- @author "Patrik Karlsson <patrik@cqure.net>"

module(... or "redis", package.seeall)

local match = require 'match'		


Request = {

	new = function(self, cmd, ...)
		local o = { cmd = cmd, args = {...} }
		setmetatable (o,self)
		self.__index = self
		return o
	end,
	
	__tostring = function(self)
		local output = ("*%s\r\n$%d\r\n%s\r\n"):format(#self.args + 1, #self.cmd, self.cmd)
		
		for _, arg in ipairs(self.args) do
			arg = tostring(arg)
			output = output .. ("$%s\r\n%s\r\n"):format(#arg, arg)
		end
		
		return output
	end
	
}


Response = {
	
	Type = {
		STATUS		= 0,
		ERROR		= 1,
		INTEGER		= 2,
		BULK		= 3,
		MULTIBULK	= 4,
	},
	
	new = function(self, socket)
		local o = { socket = socket }
		setmetatable (o,self)
		self.__index = self
		return o
	end,
	
	receive = function(self)
		local status, data = self.socket:receive_buf("\r\n")
		if ( not(status) ) then
			return false, "Failed to receive data from server"
		end

		-- if we have a status, integer or error message 
		if ( data:match("^[%-%+%:]") ) then
			local response = { data = data }
			local t = data:match("^([-+:])")
			if ( t == "-" ) then
				response.type = Response.Type.ERROR
			elseif ( t == "+" ) then
				response.type = Response.Type.STATUS
			elseif ( t == ":" ) then
				response.type = Response.Type.INTEGER
			end
			
			return true, response
		end
		
		-- process bulk reply
		if ( data:match("^%$") ) then
			-- non existing key
			if ( data == "$-1" ) then
				return true, nil
			end
			
			local len = tonumber(data:match("^%$(%d*)"))
			-- we should only have a single line, so we can just peel of the length	
			status, data = self.socket:receive_buf(match.numbytes(len))
			if( not(status) ) then
				return false, "Failed to receive data from server"
			end
			
			return true, { data = data, type = Response.Type.BULK }
		end
		
		-- process multi-bulk reply
		if ( data:match("^%*%d*") ) then
			local count = data:match("^%*(%d*)")
			local results = {}
			
			for i=1, count do
				-- peel of the length
				local status = self.socket:receive_buf("\r\n")
				if( not(status) ) then
					return false, "Failed to receive data from server"
				end

				status, data = self.socket:receive_buf("\r\n")
				if( not(status) ) then
					return false, "Failed to receive data from server"
				end
				table.insert(results, data)
			end
			return true, { data = results, type = Response.Type.MULTIBULK }
		end
		
		return false, "Unsupported response"
	end,
	
	
	
}

Helper = {
		
	new = function(self, host, port)
		local o = { host = host, port = port }
		setmetatable (o,self)
		self.__index = self
		return o
	end,
	
	connect = function(self)
		self.socket = nmap.new_socket()
		return self.socket:connect(self.host, self.port)
	end,
	
	reqCmd = function(self, cmd, ...)
		local req = Request:new(cmd, ...)
		local status, err = self.socket:send(tostring(req))
		if (not(status)) then
			return false, "Failed to send command to server"
		end
		return Response:new(self.socket):receive()
	end,
	
	close = function(self)
		return self.socket:close()
	end
	
}