service_mgr.lua 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  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.co)
  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. local session, source = skynet.context()
  38. if s.launch == nil and func then
  39. s.launch = {
  40. session = session,
  41. source = source,
  42. co = co,
  43. }
  44. return request(name, func, ...)
  45. end
  46. table.insert(s, {
  47. co = co,
  48. session = session,
  49. source = source,
  50. })
  51. skynet.wait()
  52. s = service[name]
  53. if type(s) == "string" then
  54. error(s)
  55. end
  56. assert(type(s) == "number")
  57. return s
  58. end
  59. local function read_name(service_name)
  60. if string.byte(service_name) == 64 then -- '@'
  61. return string.sub(service_name , 2)
  62. else
  63. return service_name
  64. end
  65. end
  66. function cmd.LAUNCH(service_name, subname, ...)
  67. local realname = read_name(service_name)
  68. if realname == "snaxd" then
  69. return waitfor(service_name.."."..subname, snax.rawnewservice, subname, ...)
  70. else
  71. return waitfor(service_name, skynet.newservice, realname, subname, ...)
  72. end
  73. end
  74. function cmd.QUERY(service_name, subname)
  75. local realname = read_name(service_name)
  76. if realname == "snaxd" then
  77. return waitfor(service_name.."."..subname)
  78. else
  79. return waitfor(service_name)
  80. end
  81. end
  82. local function list_service()
  83. local result = {}
  84. for k,v in pairs(service) do
  85. if type(v) == "string" then
  86. v = "Error: " .. v
  87. elseif type(v) == "table" then
  88. local querying = {}
  89. if v.launch then
  90. local session = skynet.task(v.launch.co)
  91. local launching_address = skynet.call(".launcher", "lua", "QUERY", session)
  92. if launching_address then
  93. table.insert(querying, "Init as " .. skynet.address(launching_address))
  94. table.insert(querying, skynet.call(launching_address, "debug", "TASK", "init"))
  95. table.insert(querying, "Launching from " .. skynet.address(v.launch.source))
  96. table.insert(querying, skynet.call(v.launch.source, "debug", "TASK", v.launch.session))
  97. end
  98. end
  99. if #v > 0 then
  100. table.insert(querying , "Querying:" )
  101. for _, detail in ipairs(v) do
  102. table.insert(querying, skynet.address(detail.source) .. " " .. tostring(skynet.call(detail.source, "debug", "TASK", detail.session)))
  103. end
  104. end
  105. v = table.concat(querying, "\n")
  106. else
  107. v = skynet.address(v)
  108. end
  109. result[k] = v
  110. end
  111. return result
  112. end
  113. local function register_global()
  114. function cmd.GLAUNCH(name, ...)
  115. local global_name = "@" .. name
  116. return cmd.LAUNCH(global_name, ...)
  117. end
  118. function cmd.GQUERY(name, ...)
  119. local global_name = "@" .. name
  120. return cmd.QUERY(global_name, ...)
  121. end
  122. local mgr = {}
  123. function cmd.REPORT(m)
  124. mgr[m] = true
  125. end
  126. local function add_list(all, m)
  127. local harbor = "@" .. skynet.harbor(m)
  128. local result = skynet.call(m, "lua", "LIST")
  129. for k,v in pairs(result) do
  130. all[k .. harbor] = v
  131. end
  132. end
  133. function cmd.LIST()
  134. local result = {}
  135. for k in pairs(mgr) do
  136. pcall(add_list, result, k)
  137. end
  138. local l = list_service()
  139. for k, v in pairs(l) do
  140. result[k] = v
  141. end
  142. return result
  143. end
  144. end
  145. local function register_local()
  146. local function waitfor_remote(cmd, name, ...)
  147. local global_name = "@" .. name
  148. local local_name
  149. if name == "snaxd" then
  150. local_name = global_name .. "." .. (...)
  151. else
  152. local_name = global_name
  153. end
  154. return waitfor(local_name, skynet.call, "SERVICE", "lua", cmd, global_name, ...)
  155. end
  156. function cmd.GLAUNCH(...)
  157. return waitfor_remote("LAUNCH", ...)
  158. end
  159. function cmd.GQUERY(...)
  160. return waitfor_remote("QUERY", ...)
  161. end
  162. function cmd.LIST()
  163. return list_service()
  164. end
  165. skynet.call("SERVICE", "lua", "REPORT", skynet.self())
  166. end
  167. skynet.start(function()
  168. skynet.dispatch("lua", function(session, address, command, ...)
  169. local f = cmd[command]
  170. if f == nil then
  171. skynet.ret(skynet.pack(nil, "Invalid command " .. command))
  172. return
  173. end
  174. local ok, r = pcall(f, ...)
  175. if ok then
  176. skynet.ret(skynet.pack(r))
  177. else
  178. skynet.ret(skynet.pack(nil, r))
  179. end
  180. end)
  181. local handle = skynet.localname ".service"
  182. if handle then
  183. skynet.error(".service is already register by ", skynet.address(handle))
  184. skynet.exit()
  185. else
  186. skynet.register(".service")
  187. end
  188. if skynet.getenv "standalone" then
  189. skynet.register("SERVICE")
  190. register_global()
  191. else
  192. register_local()
  193. end
  194. end)