service_mgr.lua 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. local skynet = require "skynet"
  2. require "skynet.manager" -- import skynet.register
  3. local snax = require "skynet.snax"
  4. local cmd = {}
  5. local service = {}
  6. local function request(name, func, ...)
  7. local ok, handle = pcall(func, ...)
  8. local s = service[name]
  9. assert(type(s) == "table")
  10. if ok then
  11. service[name] = handle
  12. else
  13. service[name] = tostring(handle)
  14. end
  15. for _,v in ipairs(s) do
  16. skynet.wakeup(v)
  17. end
  18. if ok then
  19. return handle
  20. else
  21. error(tostring(handle))
  22. end
  23. end
  24. local function waitfor(name , func, ...)
  25. local s = service[name]
  26. if type(s) == "number" then
  27. return s
  28. end
  29. local co = coroutine.running()
  30. if s == nil then
  31. s = {}
  32. service[name] = s
  33. elseif type(s) == "string" then
  34. error(s)
  35. end
  36. assert(type(s) == "table")
  37. if not s.launch and func then
  38. s.launch = true
  39. return request(name, func, ...)
  40. end
  41. table.insert(s, co)
  42. skynet.wait()
  43. s = service[name]
  44. if type(s) == "string" then
  45. error(s)
  46. end
  47. assert(type(s) == "number")
  48. return s
  49. end
  50. local function read_name(service_name)
  51. if string.byte(service_name) == 64 then -- '@'
  52. return string.sub(service_name , 2)
  53. else
  54. return service_name
  55. end
  56. end
  57. function cmd.LAUNCH(service_name, subname, ...)
  58. local realname = read_name(service_name)
  59. if realname == "snaxd" then
  60. return waitfor(service_name.."."..subname, snax.rawnewservice, subname, ...)
  61. else
  62. return waitfor(service_name, skynet.newservice, realname, subname, ...)
  63. end
  64. end
  65. function cmd.QUERY(service_name, subname)
  66. local realname = read_name(service_name)
  67. if realname == "snaxd" then
  68. return waitfor(service_name.."."..subname)
  69. else
  70. return waitfor(service_name)
  71. end
  72. end
  73. local function list_service()
  74. local result = {}
  75. for k,v in pairs(service) do
  76. if type(v) == "string" then
  77. v = "Error: " .. v
  78. elseif type(v) == "table" then
  79. v = "Querying"
  80. else
  81. v = skynet.address(v)
  82. end
  83. result[k] = v
  84. end
  85. return result
  86. end
  87. local function register_global()
  88. function cmd.GLAUNCH(name, ...)
  89. local global_name = "@" .. name
  90. return cmd.LAUNCH(global_name, ...)
  91. end
  92. function cmd.GQUERY(name, ...)
  93. local global_name = "@" .. name
  94. return cmd.QUERY(global_name, ...)
  95. end
  96. local mgr = {}
  97. function cmd.REPORT(m)
  98. mgr[m] = true
  99. end
  100. local function add_list(all, m)
  101. local harbor = "@" .. skynet.harbor(m)
  102. local result = skynet.call(m, "lua", "LIST")
  103. for k,v in pairs(result) do
  104. all[k .. harbor] = v
  105. end
  106. end
  107. function cmd.LIST()
  108. local result = {}
  109. for k in pairs(mgr) do
  110. pcall(add_list, result, k)
  111. end
  112. local l = list_service()
  113. for k, v in pairs(l) do
  114. result[k] = v
  115. end
  116. return result
  117. end
  118. end
  119. local function register_local()
  120. local function waitfor_remote(cmd, name, ...)
  121. local global_name = "@" .. name
  122. local local_name
  123. if name == "snaxd" then
  124. local_name = global_name .. "." .. (...)
  125. else
  126. local_name = global_name
  127. end
  128. return waitfor(local_name, skynet.call, "SERVICE", "lua", cmd, global_name, ...)
  129. end
  130. function cmd.GLAUNCH(...)
  131. return waitfor_remote("LAUNCH", ...)
  132. end
  133. function cmd.GQUERY(...)
  134. return waitfor_remote("QUERY", ...)
  135. end
  136. function cmd.LIST()
  137. return list_service()
  138. end
  139. skynet.call("SERVICE", "lua", "REPORT", skynet.self())
  140. end
  141. skynet.start(function()
  142. skynet.dispatch("lua", function(session, address, command, ...)
  143. local f = cmd[command]
  144. if f == nil then
  145. skynet.ret(skynet.pack(nil, "Invalid command " .. command))
  146. return
  147. end
  148. local ok, r = pcall(f, ...)
  149. if ok then
  150. skynet.ret(skynet.pack(r))
  151. else
  152. skynet.ret(skynet.pack(nil, r))
  153. end
  154. end)
  155. local handle = skynet.localname ".service"
  156. if handle then
  157. skynet.error(".service is already register by ", skynet.address(handle))
  158. skynet.exit()
  159. else
  160. skynet.register(".service")
  161. end
  162. if skynet.getenv "standalone" then
  163. skynet.register("SERVICE")
  164. register_global()
  165. else
  166. register_local()
  167. end
  168. end)