diff --git a/examples/config.path b/examples/config.path index 579fece5..568b345d 100644 --- a/examples/config.path +++ b/examples/config.path @@ -1,5 +1,5 @@ root = "./" -luaservice = root.."service/?.lua;"..root.."test/?.lua;"..root.."examples/?.lua" +luaservice = root.."service/?.lua;"..root.."test/?.lua;"..root.."examples/?.lua;"..root.."test/?/init.lua" lualoader = root .. "lualib/loader.lua" lua_path = root.."lualib/?.lua;"..root.."lualib/?/init.lua" lua_cpath = root .. "luaclib/?.so" diff --git a/lualib/skynet/service.lua b/lualib/skynet/service.lua new file mode 100644 index 00000000..32d665cf --- /dev/null +++ b/lualib/skynet/service.lua @@ -0,0 +1,43 @@ +local skynet = require "skynet" + +local service = {} +local cache = {} +local provider + +local function get_provider() + provider = provider or skynet.uniqueservice "service_provider" + return provider +end + +local function check(func) + local info = debug.getinfo(func, "u") + assert(info.nups == 1) + assert(debug.getupvalue(func,1) == "_ENV") +end + +function service.new(name, mainfunc, ...) + local p = get_provider() + local addr, booting = skynet.call(p, "lua", "test", name) + if addr then + service.address = addr + else + if booting then + service.address = skynet.call(p, "lua", "query", name) + else + check(mainfunc) + local code = string.dump(mainfunc) + service.address = skynet.call(p, "lua", "launch", name, code, ...) + end + end + cache[name] = service.address + return service.address +end + +function service.query(name) + if not cache[name] then + cache[name] = skynet.call(get_provider(), "lua", "query", name) + end + return cache[name] +end + +return service diff --git a/service/service_provider.lua b/service/service_provider.lua new file mode 100644 index 00000000..b04067ca --- /dev/null +++ b/service/service_provider.lua @@ -0,0 +1,113 @@ +local skynet = require "skynet" + +local provider = {} + +local function new_service(svr, name) + local s = {} + svr[name] = s + s.queue = {} + return s +end + +local svr = setmetatable({}, { __index = new_service }) + + +function provider.query(name) + local s = svr[name] + if s.queue then + table.insert(s.queue, skynet.response()) + else + if s.address then + return skynet.ret(skynet.pack(s.address)) + else + error(s.error) + end + end +end + +local function boot(addr, name, code, ...) + local s = svr[name] + skynet.call(addr, "lua", "init", code, ...) + local tmp = table.pack( ... ) + for i=1,tmp.n do + tmp[i] = tostring(tmp[i]) + end + + if tmp.n > 0 then + s.init = table.concat(tmp, ",") + end + s.time = skynet.time() +end + +function provider.launch(name, code, ...) + local s = svr[name] + if s.booting then + table.insert(s.queue, skynet.response()) + else + s.booting = true + local err + local ok, addr = pcall(skynet.newservice,"service_cell", name) + if ok then + ok, err = xpcall(boot, debug.traceback, addr, name, code, ...) + else + err = addr + addr = nil + end + s.booting = nil + if ok then + s.address = addr + for _, resp in ipairs(s.queue) do + resp(true, addr) + end + s.queue = nil + skynet.ret(skynet.pack(addr)) + else + if addr then + skynet.send(addr, "debug", "EXIT") + end + s.error = err + for _, resp in ipairs(s.queue) do + resp(false) + end + s.queue = nil + error(err) + end + end +end + +function provider.test(name) + local s = svr[name] + if s.booting then + skynet.ret(skynet.pack(nil, true)) -- booting + elseif s.address then + skynet.ret(skynet.pack(s.address)) + elseif s.error then + error(s.error) + else + skynet.ret() -- nil + end +end + +skynet.start(function() + skynet.dispatch("lua", function(session, address, cmd, ...) + provider[cmd](...) + end) + skynet.info_func(function() + local info = {} + for k,v in pairs(svr) do + local status + if v.booting then + status = "booting" + elseif v.queue then + status = "waiting(" .. #v.queue .. ")" + end + info[skynet.address(v.address)] = { + init = v.init, + name = k, + time = os.date("%Y %b %d %T %z",math.floor(v.time)), + status = status, + } + end + return info + end) +end) diff --git a/test/testservice/init.lua b/test/testservice/init.lua new file mode 100644 index 00000000..d69b8973 --- /dev/null +++ b/test/testservice/init.lua @@ -0,0 +1,7 @@ +local skynet = require "skynet" +local kvdb = require "kvdb" + +skynet.start(function() + kvdb.set("A", 1) + print(kvdb.get "A") +end) diff --git a/test/testservice/kvdb.lua b/test/testservice/kvdb.lua new file mode 100644 index 00000000..5dcd695d --- /dev/null +++ b/test/testservice/kvdb.lua @@ -0,0 +1,43 @@ +local skynet = require "skynet" +local service = require "skynet.service" + +local kvdb = {} + +-- service.address is the default address registered by itself. +function kvdb.get(key) + return skynet.call(service.address, "lua", "get", key) +end + +function kvdb.set(key, value) + skynet.call(service.address, "lua", "set", key , value) +end + +-- this function will be injected into an unique service, so don't refer any upvalues +local function service_mainfunc(...) + local skynet = require "skynet" + + skynet.error(...) -- (...) passed from service.new + + local db = {} + + local command = {} + + function command.get(key) + return db[key] + end + + function command.set(key, value) + db[key] = value + end + + -- skynet.start is compatible + skynet.dispatch("lua", function(session, address, cmd, ...) + skynet.ret(skynet.pack(command[cmd](...))) + end) +end + +skynet.init(function() + service.new("kvdb", service_mainfunc, "Service Init") +end) + +return kvdb