diff --git a/examples/config_log b/examples/config_log index e7ba2eb4..9261e435 100644 --- a/examples/config_log +++ b/examples/config_log @@ -7,3 +7,4 @@ address = "127.0.0.1:2527" master = "127.0.0.1:2013" start = "main_log" luaservice ="./service/?.lua;./test/?.lua;./examples/?.lua" +snax = "./examples/?.lua;./test/?.lua" diff --git a/lualib/skynet.lua b/lualib/skynet.lua index ab1b8fbe..be8fb708 100644 --- a/lualib/skynet.lua +++ b/lualib/skynet.lua @@ -436,25 +436,19 @@ function skynet.newservice(name, ...) end function skynet.uniqueservice(global, ...) - local handle if global == true then - handle = skynet.call("SERVICE", "lua", "LAUNCH", ...) + return assert(skynet.call(".service", "lua", "GLAUNCH", ...)) else - handle = skynet.call(".service", "lua", "LAUNCH", global, ...) + return assert(skynet.call(".service", "lua", "LAUNCH", global, ...)) end - assert(handle , "Unique service launch failed") - return handle end function skynet.queryservice(global, ...) - local handle if global == true then - handle = skynet.call("SERVICE", "lua", "QUERY", ...) + return assert(skynet.call(".service", "lua", "GQUERY", ...)) else - handle = skynet.call(".service", "lua", "QUERY", global, ...) + return assert(skynet.call(".service", "lua", "QUERY", global, ...)) end - assert(handle , "Unique service query failed") - return handle end local function group_command(cmd, handle, address) diff --git a/lualib/snax.lua b/lualib/snax.lua index cec97570..c712487c 100644 --- a/lualib/snax.lua +++ b/lualib/snax.lua @@ -72,16 +72,14 @@ end local handle_cache = setmetatable( {} , { __mode = "kv" } ) -function snax.newservice(name, ...) +function snax.rawnewservice(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, "snax", t.system.init, ...) end - local ret = wrapper(handle, name, t) - handle_cache[handle] = ret - return ret + return handle end function snax.bind(handle, type) @@ -96,6 +94,39 @@ function snax.bind(handle, type) return ret end +function snax.newservice(name, ...) + local handle = snax.rawnewservice(name, ...) + return snax.bind(handle, name) +end + +local function service_name(global, name, ...) + if global == true then + return name + else + return global + end +end + +function snax.uniqueservice(name, ...) + local handle = assert(skynet.call(".service", "lua", "LAUNCH", "snaxd", name, ...)) + return snax.bind(handle, name) +end + +function snax.globalservice(name, ...) + local handle = assert(skynet.call(".service", "lua", "GLAUNCH", "snaxd", name, ...)) + return snax.bind(handle, name) +end + +function snax.queryservice(name) + local handle = assert(skynet.call(".service", "lua", "QUERY", "snaxd", name)) + return snax.bind(handle, name) +end + +function snax.queryglobal(name) + local handle = assert(skynet.call(".service", "lua", "GQUERY", "snaxd", name)) + return snax.bind(handle, name) +end + function snax.kill(obj, ...) local t = snax.interface(obj.type) skynet_call(obj.handle, "snax", t.system.exit, ...) diff --git a/service/bootstrap.lua b/service/bootstrap.lua index c367a5d4..9e6ff58a 100644 --- a/service/bootstrap.lua +++ b/service/bootstrap.lua @@ -8,7 +8,6 @@ skynet.start(function() local datacenter = assert(skynet.newservice "datacenter") skynet.name("DATACENTER", datacenter) local smgr = assert(skynet.newservice "service_mgr") - skynet.name("SERVICE", smgr) end assert(skynet.newservice(skynet.getenv "start" or "main")) skynet.exit() diff --git a/service/datacenter.lua b/service/datacenter.lua new file mode 100644 index 00000000..999200fa --- /dev/null +++ b/service/datacenter.lua @@ -0,0 +1,43 @@ +local skynet = require "skynet" + +local command = {} +local database = {} + +local function query(db, key, ...) + if key == nil then + return db + else + return query(db[key], ...) + end +end + +function command.QUERY(key, ...) + local d = database[key] + if d then + return query(d, ...) + end +end + +local function update(db, key, value, ...) + if select("#",...) == 0 then + local ret = db[key] + db[key] = value + return ret + else + if db[key] == nil then + db[key] = {} + end + return update(db[key], value, ...) + end +end + +function command.UPDATE(...) + return update(database, ...) +end + +skynet.start(function() + skynet.dispatch("lua", function (_, source, cmd, ...) + local f = assert(command[cmd]) + skynet.ret(skynet.pack(f(source, ...))) + end) +end) diff --git a/service/debug_console.lua b/service/debug_console.lua index 71fd0969..d49dd809 100644 --- a/service/debug_console.lua +++ b/service/debug_console.lua @@ -112,6 +112,7 @@ function COMMAND.help() start = "lanuch a new lua service", snax = "lanuch a new snax service", clearcache = "clear lua code cache", + service = "List unique service", } end @@ -137,3 +138,7 @@ function COMMAND.snax(...) return "Failed" end end + +function COMMAND.service() + return skynet.call("SERVICE", "lua", "LIST") +end diff --git a/service/service_mgr.lua b/service/service_mgr.lua index f387cf36..f49a79f7 100644 --- a/service/service_mgr.lua +++ b/service/service_mgr.lua @@ -1,68 +1,178 @@ local skynet = require "skynet" +local snax = require "snax" local cmd = {} local service = {} -function cmd.LAUNCH(service_name, ...) - local s = service[service_name] - if type(s) == "number" then - return s +local function request(name, func, ...) + local ok, handle = pcall(func, ...) + local s = service[name] + assert(type(s) == "table") + if ok then + service[name] = handle + else + service[name] = tostring(handle) end - if s == nil then - s = { launch = true } - service[service_name] = s - elseif s.launch then - assert(type(s) == "table") - local co = coroutine.running() - table.insert(s, co) - skynet.wait() - s = service[service_name] - assert(type(s) == "number") - return s - end - - local handle = skynet.newservice(service_name, ...) for _,v in ipairs(s) do skynet.wakeup(v) end - service[service_name] = handle - - return handle + if ok then + return handle + else + error(tostring(handle)) + end end -function cmd.QUERY(service_name) - local s = service[service_name] +local function waitfor(name , func, ...) + local s = service[name] if type(s) == "number" then return s end + local co = coroutine.running() + if s == nil then s = {} - service[service_name] = s + service[name] = s + elseif type(s) == "string" then + error(s) end + assert(type(s) == "table") - local co = coroutine.running() + + if not s.launch and func then + s.launch = true + return request(name, func, ...) + end + table.insert(s, co) skynet.wait() - s = service[service_name] + s = service[name] + if type(s) == "string" then + error(s) + end assert(type(s) == "number") return s end +local function read_name(service_name) + if string.byte(service_name) == 64 then -- '@' + return string.sub(service_name , 2) + else + return service_name + end +end + +function cmd.LAUNCH(service_name, subname, ...) + local realname = read_name(service_name) + + if realname == "snaxd" then + return waitfor(service_name.."."..subname, snax.rawnewservice, subname, ...) + else + return waitfor(service_name, skynet.newservice, realname, subname, ...) + end +end + +function cmd.QUERY(service_name, subname) + local realname = read_name(service_name) + + if realname == "snaxd" then + return waitfor(service_name.."."..subname) + else + return waitfor(service_name) + end +end + +local function list_service() + local result = {} + for k,v in pairs(service) do + if type(v) == "string" then + v = "Error: " .. v + elseif type(v) == "table" then + v = "Querying" + else + v = skynet.address(v) + end + + result[k] = v + end + + return result +end + + +local function register_global() + function cmd.GLAUNCH(name, ...) + local global_name = "@" .. name + return cmd.LAUNCH(global_name, ...) + end + + function cmd.GQUERY(name, ...) + local global_name = "@" .. name + return cmd.QUERY(global_name, ...) + end + + local mgr = {} + + function cmd.REPORT(m) + mgr[m] = true + skynet.watch(m) + end + + local function add_list(all, m) + local harbor = "@" .. skynet.harbor(m) + local result = skynet.call(m, "lua", "LIST") + for k,v in pairs(result) do + all[k .. harbor] = v + end + end + + function cmd.LIST() + local result = {} + for k in pairs(mgr) do + pcall(add_list, result, k) + end + local l = list_service() + for k, v in pairs(l) do + result[k] = v + end + return result + end +end + +local function register_local() + function cmd.GLAUNCH(name, ...) + local global_name = "@" .. name + return waitfor(global_name, skynet.call, "SERVICE", "lua", "LAUNCH", global_name, ...) + end + + function cmd.GQUERY(name, ...) + local global_name = "@" .. name + return waitfor(global_name, skynet.call, "SERVICE", "lua", "QUERY", global_name, ...) + end + + function cmd.LIST() + return list_service() + end + + skynet.call("SERVICE", "lua", "REPORT", skynet.self()) +end + skynet.start(function() - skynet.dispatch("lua", function(session, address, command, service_name , ...) + skynet.dispatch("lua", function(session, address, command, ...) local f = cmd[command] if f == nil then - skynet.ret(skynet.pack(nil)) + skynet.ret(skynet.pack(nil, "Invalid command " .. command)) return end - local ok, r = pcall(f, service_name, ...) + local ok, r = pcall(f, ...) + if ok then skynet.ret(skynet.pack(r)) else - skynet.ret(skynet.pack(nil)) + skynet.ret(skynet.pack(nil, r)) end end) local handle = skynet.localname ".service" @@ -72,4 +182,10 @@ skynet.start(function() else skynet.register(".service") end + if skynet.getenv "standalone" then + skynet.register("SERVICE") + register_global() + else + register_local() + end end) diff --git a/test/testping.lua b/test/testping.lua index 61a82bc0..c9f05e63 100644 --- a/test/testping.lua +++ b/test/testping.lua @@ -2,7 +2,7 @@ local skynet = require "skynet" local snax = require "snax" skynet.start(function() - local ps = snax.newservice ("pingserver", "hello world") + local ps = snax.uniqueservice ("pingserver", "hello world") print(ps.req.ping("foobar")) print(ps.post.hello()) print(pcall(ps.req.error))