snax : a simple skynet auxliliary framework

This commit is contained in:
Cloud Wu
2014-04-16 20:12:17 +08:00
parent a420fe498f
commit df5c619a29
6 changed files with 235 additions and 22 deletions

View File

@@ -7,5 +7,6 @@ master = "127.0.0.1:2013"
start = "main"
standalone = "0.0.0.0:2013"
luaservice = root.."service/?.lua;"..root.."test/?.lua;"..root.."examples/?.lua"
snax = root.."examples/?.lua;"..root.."test/?.lua"
cpath = root.."cservice/?.so"
redis = root .. "examples/redisconf"

98
lualib/snax.lua Normal file
View File

@@ -0,0 +1,98 @@
local skynet = require "skynet"
local snax_interface = require "snax_interface"
local snax = {}
local typeclass = {}
local G = { require = function() end }
function snax.interface(name)
if typeclass[name] then
return typeclass[name]
end
local si = snax_interface(name, G)
local ret = {
subscribe = {},
response = {},
system = {},
}
for _,v in ipairs(si) do
local id, group, name, f = table.unpack(v)
if group == "system" then
if f then
ret.system[name] = id
end
else
ret[group][name] = id
end
end
typeclass[name] = ret
return ret
end
local meta = { __tostring = function(v) return string.format("[%s:%x]", v.type, v.handle) end}
local skynet_send = skynet.send
local skynet_call = skynet.call
local function gen_pub(type, handle)
return setmetatable({} , {
__index = function( t, k )
local id = assert(type.subscribe[k] , string.format("publish %s no exist", k))
return function(...)
skynet_send(handle, "lua", id, ...)
end
end })
end
local function gen_req(type, handle)
return setmetatable({} , {
__index = function( t, k )
local id = assert(type.response[k] , string.format("request %s no exist", k))
return function(...)
return skynet_call(handle, "lua", id, ...)
end
end })
end
local function wrapper(handle, name, type)
return setmetatable ({
pub = gen_pub(type, handle),
req = gen_req(type, handle),
type = name,
handle = handle,
kill = function(...) return skynet_call(handle, "lua", type.system.exit, ...) end,
}, meta)
end
local handle_cache = setmetatable( {} , { __mode = "kv" } )
function snax.newservice(name, ...)
local t = snax.interface(name)
local handle = skynet.newservice("snaxd", name)
assert(handle_cache[handle] == nil)
if t.system.init then
skynet.call(handle, "lua", t.system.init, ...)
end
local ret = wrapper(handle, name, t)
handle_cache[handle] = ret
return ret
end
function snax.bind(handle, type)
local ret = handle_cache[handle]
if ret then
assert(ret.type == type)
return ret
end
local t = snax.interface(type)
ret = wrapper(handle, type, t)
handle_cache[handle] = ret
return ret
end
return snax

84
lualib/snax_interface.lua Normal file
View File

@@ -0,0 +1,84 @@
local skynet = require "skynet"
return function (name , G)
local mainfunc
local function func_id(id, group)
local tmp = {}
local function count( _, name, func)
if type(name) ~= "string" then
error (string.format("%s method only support string", group))
end
if type(func) ~= "function" then
error (string.format("%s.%s must be function"), group, name)
end
if tmp[name] then
error (string.format("%s.%s duplicate definition", group, name))
end
tmp[name] = true
table.insert(id, { #id + 1, group, name, func} )
end
return setmetatable({}, { __newindex = count })
end
do
assert(getmetatable(G) == nil)
assert(G.init == nil)
assert(G.exit == nil)
assert(G.subscribe == nil)
assert(G.response == nil)
end
local env = {}
local func = {}
local system = { "init", "exit" }
do
for k, v in ipairs(system) do
system[v] = k
func[k] = { k , "system", v }
end
end
env.subscribe = func_id(func, "subscribe")
env.response = func_id(func, "response")
local function init_system(t, name, f)
local index = assert(system[name] , string.format("Not support global var %s", name))
if type(f) ~= "function" then
error (string.format("%s must be a function", name))
end
func[index][4] = f
end
setmetatable(G, { __index = env , __newindex = init_system })
do
local path = skynet.getenv "snax"
local errlist = {}
for pat in string.gmatch(path,"[^;]+") do
local filename = string.gsub(pat, "?", name)
local f , err = loadfile(filename, "bt", G)
if f then
mainfunc = f
break
else
table.insert(errlist, err)
end
end
if mainfunc == nil then
error(table.concat(errlist, "\n"))
end
end
mainfunc()
setmetatable(G, nil)
return func
end

33
service/snaxd.lua Normal file
View File

@@ -0,0 +1,33 @@
local skynet = require "skynet"
local snax_interface = require "snax_interface"
local func = snax_interface(tostring(...), _ENV)
skynet.start(function()
local init = false
skynet.dispatch("lua", function ( _, _, id, ...)
local method = func[id]
if method[2] == "system" then
if method[3] == "init" then
assert(not init, "Already init")
local initfunc = method[4] or function() end
skynet.ret(skynet.pack(initfunc(...)))
init = true
else
assert(init, "Never init")
local exitfunc = method[4] or function() end
skynet.ret(skynet.pack(exitfunc(...)))
init = false
skynet.exit()
end
else
assert(init, "Init first")
if method[2] == "subscribe" then
-- no return
method[4](...)
else
skynet.ret(skynet.pack(method[4](...)))
end
end
end)
end)

View File

@@ -1,27 +1,23 @@
local skynet = require "skynet"
local command = {}
function command.PING(hello)
function response.ping(hello)
skynet.sleep(100)
return hello
end
function command.HELLO()
skynet.sleep(100)
return "hello"
function subscribe.hello()
print "hello"
end
function command.EXIT()
skynet.exit()
end
function command.ERROR()
function response.error()
error "throw an error"
end
function init( ... )
print ("ping server start:", ...)
end
skynet.start(function()
skynet.dispatch("lua", function(session,addr, cmd, ...)
skynet.ret(skynet.pack(command[cmd](...)))
end)
end)
function exit(...)
print ("ping server exit:", ...)
return "Exit"
end

View File

@@ -1,10 +1,11 @@
local skynet = require "skynet"
local snax = require "snax"
skynet.start(function()
local ps = skynet.uniqueservice("pingserver")
skynet.watch(ps)
print(pcall(skynet.call,ps,"lua","ERROR"))
print(skynet.call(ps, "lua", "PING", "hello"))
print(skynet.call(ps, "lua", "PING", "hay"))
skynet.call(ps, "lua", "EXIT")
local ps = snax.newservice ("pingserver", "hello world")
print(ps.pub.hello())
print(ps.req.ping("foobar"))
print(pcall(ps.req.error))
print(ps.kill("exit"))
skynet.exit()
end)