mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-22 19:13:07 +00:00
171 lines
3.5 KiB
Lua
171 lines
3.5 KiB
Lua
local skynet = require "skynet"
|
|
local socket = require "socket"
|
|
local int64 = require "int64"
|
|
local string = string
|
|
local table = table
|
|
local tonumber = tonumber
|
|
local ipairs = ipairs
|
|
local unpack = unpack
|
|
local redis_server, redis_db = ...
|
|
|
|
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 function select_db(id)
|
|
local result , ok = skynet.call(skynet.self(), "lua", "SELECT", tostring(id))
|
|
assert(result and ok == "OK")
|
|
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.redirect(reply.address,0, "response", reply.session, skynet.pack(...))
|
|
end
|
|
|
|
local function readline(sep)
|
|
while true do
|
|
local line = socket.readline(sep)
|
|
if line then
|
|
return line
|
|
end
|
|
coroutine.yield()
|
|
end
|
|
end
|
|
|
|
local function readbytes(bytes)
|
|
while true do
|
|
local block = socket.read(bytes)
|
|
if block then
|
|
return block
|
|
end
|
|
coroutine.yield()
|
|
end
|
|
end
|
|
|
|
local redcmd = {}
|
|
|
|
redcmd[42] = function(data) -- '*'
|
|
local n = tonumber(data)
|
|
if n < 0 then
|
|
response(true, nil)
|
|
return
|
|
end
|
|
local bulk = {}
|
|
for i = 1,n do
|
|
local line = readline "\r\n"
|
|
local bytes = tonumber(string.sub(line,2) + 2)
|
|
local data = readbytes(bytes)
|
|
table.insert(bulk, string.sub(data,1,-3))
|
|
end
|
|
response(true, bulk)
|
|
end
|
|
|
|
redcmd[36] = function(data) -- '$'
|
|
local bytes = tonumber(data)
|
|
if bytes < 0 then
|
|
response(true,nil)
|
|
return
|
|
end
|
|
local firstline = readbytes(bytes+2)
|
|
response(true,string.sub(firstline,1,-3))
|
|
end
|
|
|
|
redcmd[43] = function(data) -- '+'
|
|
response(true,data)
|
|
end
|
|
|
|
redcmd[45] = function(data) -- '-'
|
|
response(false,data)
|
|
end
|
|
|
|
redcmd[58] = function(data) -- ':'
|
|
-- todo: return string later
|
|
response(true, tonumber(data))
|
|
end
|
|
|
|
local function split_package()
|
|
while true do
|
|
local result = readline "\r\n"
|
|
local firstchar = string.byte(result)
|
|
local data = string.sub(result,2)
|
|
local f = redcmd[firstchar]
|
|
assert(f)
|
|
f(data)
|
|
end
|
|
end
|
|
|
|
local function init()
|
|
while socket.connect(redis_server) do
|
|
skynet.sleep(1000)
|
|
end
|
|
if redis_db then
|
|
select_db(redis_db)
|
|
end
|
|
end
|
|
|
|
local split_co = coroutine.create(split_package)
|
|
|
|
local function reconnect()
|
|
init()
|
|
for i = request_queue.head, request_queue.tail-1 do
|
|
local request = request_queue[i]
|
|
socket.write(request[3])
|
|
end
|
|
split_co = coroutine.create(split_package)
|
|
end
|
|
|
|
skynet.register_protocol {
|
|
name = "client",
|
|
id = 3,
|
|
pack = function(...) return ... end,
|
|
unpack = function(msg,sz)
|
|
if msg == nil then
|
|
skynet.timeout(0, reconnect)
|
|
return
|
|
end
|
|
socket.push(msg,sz)
|
|
assert(coroutine.resume(split_co))
|
|
end,
|
|
dispatch = function () end
|
|
}
|
|
|
|
skynet.start(function()
|
|
skynet.dispatch("lua", function(session, address, ...)
|
|
local message = { ... }
|
|
local cmd = compose_message(message)
|
|
socket.write(cmd)
|
|
push_request_queue { session = session , address = address, cmd = cmd }
|
|
end)
|
|
init()
|
|
end)
|
|
|