mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-24 20:23:06 +00:00
new socket service and socket lib instead of old connection, and rewrite redis lib
This commit is contained in:
179
lualib/redis.lua
179
lualib/redis.lua
@@ -1,65 +1,168 @@
|
||||
local skynet = require "skynet"
|
||||
local string = string
|
||||
local table = table
|
||||
local unpack = unpack
|
||||
local assert = assert
|
||||
local socket = require "socket"
|
||||
local config = require "config"
|
||||
local redis_conf = skynet.getenv "redis"
|
||||
local name = config (redis_conf)
|
||||
|
||||
local redis_manager
|
||||
local batch = false
|
||||
local readline = socket.readline
|
||||
local readbytes = socket.read
|
||||
local table = table
|
||||
local string = string
|
||||
|
||||
local redis = {}
|
||||
|
||||
local command = {}
|
||||
local meta = {
|
||||
__index = command,
|
||||
__gc = function(self)
|
||||
socket.close(self.__handle)
|
||||
end,
|
||||
}
|
||||
|
||||
function redis.connect(dbname)
|
||||
local fd = socket.open(name[dbname])
|
||||
return setmetatable( { __handle = fd, __mode = false }, meta )
|
||||
end
|
||||
|
||||
function command:disconnect()
|
||||
socket.close(self.__handle)
|
||||
setmetatable(self, nil)
|
||||
end
|
||||
|
||||
local function compose_message(msg)
|
||||
local lines = { "*" .. #msg }
|
||||
for _,v in ipairs(msg) do
|
||||
local t = type(v)
|
||||
if t == "number" then
|
||||
v = tostring(v)
|
||||
elseif t == "userdata" then
|
||||
v = int64.tostring(int64.new(v),10)
|
||||
end
|
||||
table.insert(lines,"$"..#v)
|
||||
table.insert(lines,v)
|
||||
end
|
||||
table.insert(lines,"")
|
||||
|
||||
local cmd = table.concat(lines,"\r\n")
|
||||
return cmd
|
||||
end
|
||||
|
||||
local redcmd = {}
|
||||
|
||||
redcmd[42] = function(fd, data) -- '*'
|
||||
local n = tonumber(data)
|
||||
if n < 0 then
|
||||
return true, nil
|
||||
end
|
||||
local bulk = {}
|
||||
for i = 1,n do
|
||||
local line = readline(fd,"\r\n")
|
||||
local bytes = tonumber(string.sub(line,2))
|
||||
if bytes < 0 then
|
||||
table.insert(bulk, nil)
|
||||
else
|
||||
local data = readbytes(fd, bytes + 2)
|
||||
table.insert(bulk, string.sub(data,1,-3))
|
||||
end
|
||||
end
|
||||
return true, bulk
|
||||
end
|
||||
|
||||
redcmd[36] = function(fd, data) -- '$'
|
||||
local bytes = tonumber(data)
|
||||
if bytes < 0 then
|
||||
return true,nil
|
||||
end
|
||||
local firstline = readbytes(fd, bytes+2)
|
||||
return true,string.sub(firstline,1,-3)
|
||||
end
|
||||
|
||||
redcmd[43] = function(fd, data) -- '+'
|
||||
return true,data
|
||||
end
|
||||
|
||||
redcmd[45] = function(fd, data) -- '-'
|
||||
return false,data
|
||||
end
|
||||
|
||||
redcmd[58] = function(fd, data) -- ':'
|
||||
-- todo: return string later
|
||||
return true, tonumber(data)
|
||||
end
|
||||
|
||||
local function read_response(fd)
|
||||
local result = readline(fd, "\r\n")
|
||||
local firstchar = string.byte(result)
|
||||
local data = string.sub(result,2)
|
||||
return redcmd[firstchar](fd,data)
|
||||
end
|
||||
|
||||
setmetatable(command, { __index = function(t,k)
|
||||
local cmd = string.upper(k)
|
||||
local f = function(self, ...)
|
||||
if batch then
|
||||
skynet.send( self.__handle, "lua", cmd , ...)
|
||||
local f = function (self, ...)
|
||||
local fd = self.__handle
|
||||
if self.__mode then
|
||||
socket.write(fd, compose_message { cmd, ... })
|
||||
self.__batch = self.__batch + 1
|
||||
else
|
||||
local err, result = skynet.call( self.__handle, "lua", cmd, ...)
|
||||
assert(err, result)
|
||||
return result
|
||||
socket.lock(fd)
|
||||
socket.write(fd, compose_message { cmd, ... })
|
||||
local ok, ret = read_response(fd)
|
||||
socket.unlock(fd)
|
||||
return ok, ret
|
||||
end
|
||||
end
|
||||
t[k] = f
|
||||
t[k] = f
|
||||
return f
|
||||
end})
|
||||
|
||||
function command:exists(key)
|
||||
assert(not batch, "exists can't used in batch mode")
|
||||
local result , exists = skynet.call( self.__handle, "lua" , "EXISTS", key)
|
||||
assert(result, exists)
|
||||
assert(not self.__mode, "exists can't used in batch mode")
|
||||
local fd = self.__handle
|
||||
socket.lock(fd)
|
||||
socket.write(fd, compose_message { "EXISTS", key })
|
||||
local ok, exists = read_response(fd)
|
||||
socket.unlock(fd)
|
||||
assert(ok, exists)
|
||||
exists = exists ~= 0
|
||||
return exists
|
||||
end
|
||||
|
||||
function command:batch(mode)
|
||||
if mode == "end" then
|
||||
assert(batch, "Open batch mode first")
|
||||
batch = false
|
||||
local err, result = skynet.unpack(skynet.rawcall( self.__handle, "text", mode))
|
||||
assert(err, result)
|
||||
return result
|
||||
local fd = self.__handle
|
||||
if self.__mode == "read" then
|
||||
local allok = true
|
||||
local allret = {}
|
||||
for i = 1, self.__batch do
|
||||
local ok, ret = read_response(fd)
|
||||
allok = allok and ok
|
||||
allret[i] = ret
|
||||
end
|
||||
assert(allok, "batch read failed")
|
||||
socket.unlock(self.__handle)
|
||||
self.__mode = false
|
||||
return allret
|
||||
else
|
||||
local allok = true
|
||||
local allret = true
|
||||
for i = 1, self.__batch do
|
||||
local ok, ret = read_response(fd)
|
||||
allok = allok and ok
|
||||
if ret~="OK" then
|
||||
allret = false
|
||||
end
|
||||
end
|
||||
socket.unlock(self.__handle)
|
||||
self.__mode = false
|
||||
assert(allret, "reading in batch write")
|
||||
return allok
|
||||
end
|
||||
else
|
||||
assert(mode == "read" or mode == "write")
|
||||
batch = mode
|
||||
skynet.send( self.__handle, "text", mode)
|
||||
self.__mode = mode
|
||||
self.__batch = 0
|
||||
socket.lock(self.__handle)
|
||||
end
|
||||
end
|
||||
|
||||
local meta = {
|
||||
__index = command
|
||||
}
|
||||
|
||||
function redis.connect(dbname)
|
||||
local handle = skynet.call(redis_manager, "lua", dbname)
|
||||
assert(handle ~= nil)
|
||||
return setmetatable({ __handle = handle } , meta)
|
||||
end
|
||||
|
||||
skynet.init(function()
|
||||
redis_manager = skynet.uniqueservice("redis-mgr")
|
||||
end, "redis")
|
||||
|
||||
return redis
|
||||
|
||||
Reference in New Issue
Block a user