Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
hanoi2005
redis
提交
928394cd
R
redis
项目概览
hanoi2005
/
redis
与 Fork 源项目一致
从无法访问的项目Fork
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
redis
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
928394cd
编写于
4月 08, 2009
作者:
A
antirez
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Lua client updated
上级
8b382972
变更
2
显示空白变更内容
内联
并排
Showing
2 changed file
with
206 addition
and
193 deletion
+206
-193
client-libraries/README
client-libraries/README
+1
-0
client-libraries/lua/redis.lua
client-libraries/lua/redis.lua
+205
-193
未找到文件。
client-libraries/README
浏览文件 @
928394cd
...
...
@@ -28,5 +28,6 @@ http://code.google.com/p/phpredis/
Lua lib source code:
http://github.com/nrk/redis-lua/tree/master
git://github.com/nrk/redis-lua.git
For all the rest check the Redis tarball or Git repository.
client-libraries/lua/redis.lua
浏览文件 @
928394cd
module
(
'Redis'
,
package
.
seeall
)
local
_G
=
_G
local
require
,
error
,
type
,
print
=
require
,
error
,
type
,
print
local
table
,
pairs
,
tostring
,
tonumber
=
table
,
pairs
,
tostring
,
tonumber
require
(
'socket'
)
-- requires LuaSocket as a dependency
module
(
'Redis'
)
-- ############################################################################
local
socket
=
require
(
'socket'
)
-- requires LuaSocket as a dependency
local
protocol
=
{
newline
=
'
\r\n
'
,
ok
=
'OK'
,
err
=
'ERR'
,
null
=
'nil'
,
}
local
redis_commands
=
{}
local
network
,
request
,
response
,
utils
=
{},
{},
{},
{},
{}
-- ############################################################################
local
protocol
=
{
newline
=
'
\r\n
'
,
ok
=
'OK'
,
err
=
'ERR'
,
null
=
'nil'
}
local
function
toboolean
(
value
)
return
value
==
1
end
local
function
load_methods
(
proto
,
methods
)
local
redis
=
_G
.
setmetatable
({},
_G
.
getmetatable
(
proto
))
for
i
,
v
in
pairs
(
proto
)
do
redis
[
i
]
=
v
end
local
function
toboolean
(
value
)
return
value
==
1
for
i
,
v
in
pairs
(
methods
)
do
redis
[
i
]
=
v
end
return
redis
end
local
function
_write
(
self
,
buffer
)
local
_
,
err
=
self
.
socket
:
send
(
buffer
)
-- ############################################################################
function
network
.
write
(
client
,
buffer
)
local
_
,
err
=
client
.
socket
:
send
(
buffer
)
if
err
then
error
(
err
)
end
end
local
function
_read
(
self
,
len
)
function
network
.
read
(
client
,
len
)
if
len
==
nil
then
len
=
'*l'
end
local
line
,
err
=
self
.
socket
:
receive
(
len
)
local
line
,
err
=
client
.
socket
:
receive
(
len
)
if
not
err
then
return
line
else
error
(
'Connection error: '
..
err
)
end
end
-- ############################################################################
local
function
_read_response
(
self
)
if
options
and
options
.
close
==
true
then
return
end
local
res
=
_read
(
self
)
function
response
.
read
(
client
)
local
res
=
network
.
read
(
client
)
local
prefix
=
res
:
sub
(
1
,
-#
res
)
local
response_handler
=
protocol
.
prefixes
[
prefix
]
if
not
response_handler
then
error
(
"Unknown response prefix: "
..
prefix
)
else
return
response_handler
(
self
,
res
)
return
response_handler
(
client
,
res
)
end
end
function
response
.
status
(
client
,
data
)
local
sub
=
data
:
sub
(
2
)
if
sub
==
protocol
.
ok
then
return
true
else
return
sub
end
end
function
response
.
error
(
client
,
data
)
local
err_line
=
data
:
sub
(
2
)
if
err_line
:
sub
(
1
,
3
)
==
protocol
.
err
then
error
(
"Redis error: "
..
err_line
:
sub
(
5
))
else
error
(
"Redis error: "
..
err_line
)
end
end
function
response
.
bulk
(
client
,
data
)
local
str
=
data
:
sub
(
2
)
local
len
=
tonumber
(
str
)
local
function
_send_raw
(
self
,
buffer
)
if
not
len
then
error
(
'Cannot parse '
..
str
..
' as data length.'
)
else
if
len
==
-
1
then
return
nil
end
local
next_chunk
=
network
.
read
(
client
,
len
+
2
)
return
next_chunk
:
sub
(
1
,
-
3
);
end
end
function
response
.
multibulk
(
client
,
data
)
local
str
=
data
:
sub
(
2
)
-- TODO: add a check if the returned value is indeed a number
local
list_count
=
tonumber
(
str
)
if
list_count
==
-
1
then
return
nil
else
local
list
=
{}
if
list_count
>
0
then
for
i
=
1
,
list_count
do
table.insert
(
list
,
i
,
response
.
bulk
(
client
,
network
.
read
(
client
)))
end
end
return
list
end
end
function
response
.
integer
(
client
,
data
)
local
res
=
data
:
sub
(
2
)
local
number
=
tonumber
(
res
)
if
not
number
then
if
res
==
protocol
.
null
then
return
nil
else
error
(
'Cannot parse '
..
res
..
' as numeric response.'
)
end
end
return
number
end
protocol
.
prefixes
=
{
[
'+'
]
=
response
.
status
,
[
'-'
]
=
response
.
error
,
[
'$'
]
=
response
.
bulk
,
[
'*'
]
=
response
.
multibulk
,
[
':'
]
=
response
.
integer
,
}
-- ############################################################################
function
request
.
raw
(
client
,
buffer
)
-- TODO: optimize
local
bufferType
=
type
(
buffer
)
if
bufferType
==
'string'
then
_write
(
self
,
buffer
)
network
.
write
(
client
,
buffer
)
elseif
bufferType
==
'table'
then
_write
(
self
,
table.concat
(
buffer
))
network
.
write
(
client
,
table.concat
(
buffer
))
else
error
(
'Argument error: '
..
bufferType
)
end
return
_read_response
(
self
)
return
response
.
read
(
client
)
end
local
function
_send_inline
(
self
,
command
,
...
)
function
request
.
inline
(
client
,
command
,
...
)
if
arg
.
n
==
0
then
_write
(
self
,
command
..
protocol
.
newline
)
network
.
write
(
client
,
command
..
protocol
.
newline
)
else
local
arguments
=
arg
arguments
.
n
=
nil
...
...
@@ -70,13 +150,13 @@ local function _send_inline(self, command, ...)
arguments
=
''
end
_write
(
self
,
command
..
' '
..
arguments
..
protocol
.
newline
)
network
.
write
(
client
,
command
..
' '
..
arguments
..
protocol
.
newline
)
end
return
_read_response
(
self
)
return
response
.
read
(
client
)
end
local
function
_send_bulk
(
self
,
command
,
...
)
function
request
.
bulk
(
client
,
command
,
...
)
local
arguments
=
arg
local
data
=
tostring
(
table.remove
(
arguments
))
arguments
.
n
=
nil
...
...
@@ -88,169 +168,127 @@ local function _send_bulk(self, command, ...)
arguments
=
''
end
return
_send_raw
(
self
,
{
return
request
.
raw
(
client
,
{
command
,
' '
,
arguments
,
' '
,
#
data
,
protocol
.
newline
,
data
,
protocol
.
newline
})
end
-- ############################################################################
local
function
_read_line
(
self
,
response
)
return
response
:
sub
(
2
)
end
local
function
_read_error
(
self
,
response
)
local
err_line
=
response
:
sub
(
2
)
if
err_line
:
sub
(
1
,
3
)
==
protocol
.
err
then
error
(
"Redis error: "
..
err_line
:
sub
(
5
))
local
function
custom
(
command
,
send
,
parse
)
return
function
(
self
,
...
)
local
reply
=
send
(
self
,
command
,
...
)
if
parse
then
return
parse
(
reply
,
command
,
...
)
else
error
(
"Redis error: "
..
err_line
)
return
reply
end
end
local
function
_read_bulk
(
self
,
response
)
local
str
=
response
:
sub
(
2
)
local
len
=
tonumber
(
str
)
if
not
len
then
error
(
'Cannot parse '
..
str
..
' as data length.'
)
else
if
len
==
-
1
then
return
nil
end
local
data
=
_read
(
self
,
len
+
2
)
return
data
:
sub
(
1
,
-
3
);
end
end
local
function
_read_multibulk
(
self
,
response
)
local
str
=
response
:
sub
(
2
)
-- TODO: add a check if the returned value is indeed a number
local
list_count
=
tonumber
(
str
)
if
list_count
==
-
1
then
return
nil
else
local
list
=
{}
if
list_count
>
0
then
for
i
=
1
,
list_count
do
table.insert
(
list
,
i
,
_read_bulk
(
self
,
_read
(
self
)))
end
end
local
function
bulk
(
command
,
reader
)
return
custom
(
command
,
request
.
bulk
,
reader
)
end
return
list
end
local
function
inline
(
command
,
reader
)
return
custom
(
command
,
request
.
inline
,
reader
)
end
local
function
_read_integer
(
self
,
response
)
local
res
=
response
:
sub
(
2
)
local
number
=
tonumber
(
res
)
-- ############################################################################
if
not
number
then
if
res
==
protocol
.
null
then
return
nil
else
error
(
'Cannot parse '
..
res
..
' as numeric response.'
)
end
function
connect
(
host
,
port
)
local
client_socket
=
socket
.
connect
(
host
,
port
)
if
not
client_socket
then
error
(
'Could not connect to '
..
host
..
':'
..
port
)
end
return
number
end
-- ############################################################################
local
redis_client
=
{
socket
=
client_socket
,
raw_cmd
=
function
(
self
,
buffer
)
return
request
.
raw
(
self
,
buffer
..
protocol
.
newline
)
end
,
}
protocol
.
prefixes
=
{
[
'+'
]
=
_read_line
,
[
'-'
]
=
_read_error
,
[
'$'
]
=
_read_bulk
,
[
'*'
]
=
_read_multibulk
,
[
':'
]
=
_read_integer
,
}
return
load_methods
(
redis_client
,
redis_commands
)
end
-- ############################################################################
local
metho
ds
=
{
redis_comman
ds
=
{
-- miscellaneous commands
ping
=
{
'PING'
,
_send_inline
,
function
(
response
)
ping
=
inline
(
'PING'
,
function
(
response
)
if
response
==
'PONG'
then
return
true
else
return
false
end
end
}
,
echo
=
{
'ECHO'
,
_send_bulk
},
)
,
echo
=
bulk
(
'ECHO'
),
-- TODO: the server returns an empty -ERR on authentication failure
auth
=
{
'AUTH'
}
,
auth
=
inline
(
'AUTH'
)
,
-- connection handling
quit
=
{
'QUIT'
,
function
(
self
,
command
)
_write
(
self
,
command
..
protocol
.
newline
)
quit
=
custom
(
'QUIT'
,
function
(
client
,
command
)
-- let's fire and forget! the connection is closed as soon
-- as the QUIT command is received by the server.
network
.
write
(
client
,
command
..
protocol
.
newline
)
end
}
,
)
,
-- commands operating on string values
set
=
{
'SET'
,
_send_bulk
}
,
set_preserve
=
{
'SETNX'
,
_send_bulk
,
toboolean
}
,
get
=
{
'GET'
}
,
get_multiple
=
{
'MGET'
}
,
increment
=
{
'INCR'
}
,
increment_by
=
{
'INCRBY'
}
,
decrement
=
{
'DECR'
}
,
decrement_by
=
{
'DECRBY'
}
,
exists
=
{
'EXISTS'
,
_send_inline
,
toboolean
}
,
delete
=
{
'DEL'
,
_send_inline
,
toboolean
}
,
type
=
{
'TYPE'
}
,
set
=
bulk
(
'SET'
)
,
set_preserve
=
bulk
(
'SETNX'
,
toboolean
)
,
get
=
inline
(
'GET'
)
,
get_multiple
=
inline
(
'MGET'
)
,
increment
=
inline
(
'INCR'
)
,
increment_by
=
inline
(
'INCRBY'
)
,
decrement
=
inline
(
'DECR'
)
,
decrement_by
=
inline
(
'DECRBY'
)
,
exists
=
inline
(
'EXISTS'
,
toboolean
)
,
delete
=
inline
(
'DEL'
,
toboolean
)
,
type
=
inline
(
'TYPE'
)
,
-- commands operating on the key space
keys
=
{
'KEYS'
,
_send_inline
,
function
(
response
)
keys
=
inline
(
'KEYS'
,
function
(
response
)
local
keys
=
{}
response
:
gsub
(
'%w+'
,
function
(
key
)
table.insert
(
keys
,
key
)
end
)
return
keys
end
},
random_key
=
{
'RANDOMKEY'
},
rename
=
{
'RENAME'
},
rename_preserve
=
{
'RENAMENX'
},
database_size
=
{
'DBSIZE'
},
),
random_key
=
inline
(
'RANDOMKEY'
),
rename
=
inline
(
'RENAME'
),
rename_preserve
=
inline
(
'RENAMENX'
),
expire
=
inline
(
'EXPIRE'
,
toboolean
),
database_size
=
inline
(
'DBSIZE'
),
-- commands operating on lists
push_tail
=
{
'RPUSH'
,
_send_bulk
},
push_head
=
{
'LPUSH'
,
_send_bulk
},
list_length
=
{
'LLEN'
,
_send_inline
,
function
(
response
,
key
)
--[[ TODO: redis seems to return a -ERR when the specified key does
not hold a list value, but this behaviour is not
consistent with the specs docs. This might be due to the
-ERR response paradigm being new, which supersedes the
check for negative numbers to identify errors. ]]
if
response
==
-
2
then
error
(
'Key '
..
key
..
' does not hold a list value'
)
end
return
response
end
},
list_range
=
{
'LRANGE'
},
list_trim
=
{
'LTRIM'
},
list_index
=
{
'LINDEX'
},
list_set
=
{
'LSET'
,
_send_bulk
},
list_remove
=
{
'LREM'
,
_send_bulk
},
pop_first
=
{
'LPOP'
},
pop_last
=
{
'RPOP'
},
push_tail
=
bulk
(
'RPUSH'
),
push_head
=
bulk
(
'LPUSH'
),
list_length
=
inline
(
'LLEN'
),
list_range
=
inline
(
'LRANGE'
),
list_trim
=
inline
(
'LTRIM'
),
list_index
=
inline
(
'LINDEX'
),
list_set
=
bulk
(
'LSET'
),
list_remove
=
bulk
(
'LREM'
),
pop_first
=
inline
(
'LPOP'
),
pop_last
=
inline
(
'RPOP'
),
-- commands operating on sets
set_add
=
{
'SADD'
}
,
set_remove
=
{
'SREM'
}
,
set_cardinality
=
{
'SCARD'
}
,
set_is_member
=
{
'SISMEMBER'
}
,
set_intersection
=
{
'SINTER'
}
,
set_intersection_store
=
{
'SINTERSTORE'
}
,
set_members
=
{
'SMEMBERS'
}
,
set_add
=
inline
(
'SADD'
)
,
set_remove
=
inline
(
'SREM'
)
,
set_cardinality
=
inline
(
'SCARD'
)
,
set_is_member
=
inline
(
'SISMEMBER'
)
,
set_intersection
=
inline
(
'SINTER'
)
,
set_intersection_store
=
inline
(
'SINTERSTORE'
)
,
set_members
=
inline
(
'SMEMBERS'
)
,
-- multiple databases handling commands
select_database
=
{
'SELECT'
}
,
move_key
=
{
'MOVE'
}
,
flush_database
=
{
'FLUSHDB'
}
,
flush_databases
=
{
'FLUSHALL'
}
,
select_database
=
inline
(
'SELECT'
)
,
move_key
=
inline
(
'MOVE'
)
,
flush_database
=
inline
(
'FLUSHDB'
)
,
flush_databases
=
inline
(
'FLUSHALL'
)
,
-- sorting
--[[
...
...
@@ -262,20 +300,29 @@ local methods = {
sort = { 'desc', 'alpha' }
}
--]]
sort
=
{
'SORT'
},
sort
=
custom
(
'SORT'
,
function
(
client
,
command
,
params
)
-- TODO: here we will put the logic needed to serialize the params
-- table to be sent as the argument of the SORT command.
return
request
.
inline
(
client
,
command
,
params
)
end
),
-- persistence control commands
save
=
{
'SAVE'
},
background_save
=
{
'BGSAVE'
},
last_save
=
{
'LASTSAVE'
},
shutdown
=
{
'SHUTDOWN'
,
function
(
self
,
command
)
_write
(
self
,
command
..
protocol
.
newline
)
save
=
inline
(
'SAVE'
),
background_save
=
inline
(
'BGSAVE'
),
last_save
=
inline
(
'LASTSAVE'
),
shutdown
=
custom
(
'SHUTDOWN'
,
function
(
client
,
command
)
-- let's fire and forget! the connection is closed as soon
-- as the SHUTDOWN command is received by the server.
network
.
write
(
command
..
protocol
.
newline
)
end
}
,
)
,
-- remote server control commands
info
=
{
'INFO'
,
_send_inline
,
function
(
response
)
info
=
inline
(
'INFO'
,
function
(
response
)
local
info
=
{}
response
:
gsub
(
'
(
[^\r\n]*
)
\
r
\
n
', function(kv)
local k,v = kv:match(('
([
^
:]
*
):([
^
:]
*
)
'):rep(1))
...
...
@@ -283,40 +330,5 @@ local methods = {
end)
return info
end
}
,
)
,
}
function connect(host, port)
local client_socket = socket.connect(host, port)
if not client_socket then
error('
Could
not
connect
to
' .. host .. '
:
' .. port)
end
local redis_client = {
socket = client_socket,
raw_cmd = function(self, buffer)
return _send_raw(self, buffer .. protocol.newline)
end,
}
return setmetatable(redis_client, {
__index = function(self, method)
local redis_meth = methods[method]
if redis_meth then
return function(self, ...)
if not redis_meth[2] then
table.insert(redis_meth, 2, _send_inline)
end
local response = redis_meth[2](self, redis_meth[1], ...)
if redis_meth[3] then
return redis_meth[3](response, ...)
else
return response
end
end
end
end
})
end
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录