redesign connection module

This commit is contained in:
云风
2012-08-14 22:37:30 +08:00
parent 4b3ce3ba5b
commit 4a0265020f
13 changed files with 466 additions and 705 deletions

View File

@@ -1,34 +1,31 @@
local skynet = require "skynet"
local socket = require "socket"
local string = string
local table = table
local tonumber = tonumber
local ipairs = ipairs
local unpack = unpack
local redis_server = ...
local fd
local write_fd
local readline_fd
local read_fd
local close_fd
local function init_fd(fdstr)
fd = fdstr
write_fd = "WRITE "..fd.." "
readline_fd = "READLINE ".. fd .." \r\n"
read_fd = "READ " .. fd .. " "
close_fd = "CLOSE "..fd
end
local function init()
fd = skynet.call(".connection", "CONNECT " .. redis_server)
if fd == nil then
print("Connect to redis server error : ", redis_server)
skynet.exit()
return true
local function read(bytes)
while true do
local result = socket.read(bytes)
if result then
return result
end
coroutine.yield()
end
init_fd(fd)
end
local function readline(sep)
while true do
local result = socket.readline(sep)
if result then
return result
end
coroutine.yield()
end
end
local function compose_message(msg)
local lines = { "*" .. #msg }
@@ -42,72 +39,109 @@ local function compose_message(msg)
return cmd
end
local function init()
socket.connect(redis_server)
end
local request_queue = { head = 1, tail = 1 }
local function push_request_queue(reply)
request_queue[request_queue.tail] = reply
request_queue.tail = request_queue.tail + 1
end
local function pop_request_queue()
assert(request_queue.head < request_queue.tail)
local reply = request_queue[request_queue.head]
request_queue[request_queue.head] = nil
request_queue.head = request_queue.head + 1
return reply
end
local function response(...)
local reply = pop_request_queue()
skynet.send(reply[2],reply[1],skynet.pack(...))
end
local redcmd = {}
redcmd[42] = function(data) -- '*'
local n = tonumber(data)
if n < 1 then
skynet.ret(skynet.pack(true, nil))
response(true, nil)
return
end
local bulk = {}
for i = 1,n do
local line = skynet.call(".connection", readline_fd)
local line = socket.readline "\r\n"
if line == nil then
return "BLOCK"
end
local bytes = tonumber(string.sub(line,2) + 2)
local data = skynet.call(".connection", read_fd .. bytes)
local data = socket.read(bytes)
if data == nil then
return "BLOCK"
end
table.insert(bulk, string.sub(data,1,-3))
end
skynet.ret(skynet.pack(true,bulk))
response(true, bulk)
end
redcmd[36] = function(data) -- '$'
local bytes = tonumber(data)
if bytes < 0 then
skynet.ret(skynet.pack(true, nil))
response(true,nil)
return
end
local firstline = skynet.call(".connection", read_fd .. (bytes + 2))
skynet.ret(skynet.pack(true,string.sub(firstline,1,-3)))
local firstline = socket.read(bytes+2)
if firstline == nil then
return "BLOCK"
end
response(true,string.sub(firstline,1,-3))
end
redcmd[43] = function(data) -- '+'
skynet.ret(skynet.pack(true, data))
response(true,data)
end
redcmd[45] = function(data) -- '-'
skynet.ret(skynet.pack(false, data))
response(false,data)
end
redcmd[58] = function(data) -- ':'
skynet.ret(skynet.pack(true, tonumber(data)))
response(true, tonumber(data))
end
skynet.dispatch(function(msg, sz, session, address)
local message = { skynet.unpack(msg,sz) }
local write_cmd = write_fd .. compose_message(message)
local result
while true do
skynet.send(".connection", write_cmd )
result = skynet.call(".connection", readline_fd)
if result then
break
end
-- reconnect
if init() then
skynet.ret(skynet.pack(false , "Disconnected"))
return
end
local function split_package()
local result = socket.readline "\r\n"
if result == nil then
return
end
local firstchar = string.byte(result)
local data = string.sub(result,2)
local f = redcmd[firstchar]
if f == nil then
skynet.ret(skynet.pack(false , "Invalid result"))
skynet.send(".connection", close_fd)
init()
else
f(data)
assert(f)
if f(data) then
return
end
end)
socket.yield()
return true
end
skynet.filter(
function(session, address , msg, sz)
if session == 0x7fffffff then
socket.push(msg,sz)
while split_package() do end
elseif session < 0 then
local message = { skynet.unpack(msg,sz) }
local cmd = compose_message(message)
socket.write(cmd)
push_request_queue { -session , address }
else
return session, address, msg , sz
end
end
)
skynet.start(init)