launcher.lua 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. local skynet = require "skynet"
  2. local core = require "skynet.core"
  3. require "skynet.manager" -- import manager apis
  4. local string = string
  5. local services = {}
  6. local command = {}
  7. local instance = {} -- for confirm (function command.LAUNCH / command.ERROR / command.LAUNCHOK)
  8. local launch_session = {} -- for command.QUERY, service_address -> session
  9. local function handle_to_address(handle)
  10. return tonumber("0x" .. string.sub(handle , 2))
  11. end
  12. local NORET = {}
  13. function command.LIST()
  14. local list = {}
  15. for k,v in pairs(services) do
  16. list[skynet.address(k)] = v
  17. end
  18. return list
  19. end
  20. local function list_srv(ti, fmt_func, ...)
  21. local list = {}
  22. local sessions = {}
  23. local req = skynet.request()
  24. for addr in pairs(services) do
  25. local r = { addr, "debug", ... }
  26. req:add(r)
  27. sessions[r] = addr
  28. end
  29. for req, resp in req:select(ti) do
  30. local addr = req[1]
  31. if resp then
  32. local stat = resp[1]
  33. list[skynet.address(addr)] = fmt_func(stat, addr)
  34. else
  35. list[skynet.address(addr)] = fmt_func("ERROR", addr)
  36. end
  37. sessions[req] = nil
  38. end
  39. for session, addr in pairs(sessions) do
  40. list[skynet.address(addr)] = fmt_func("TIMEOUT", addr)
  41. end
  42. return list
  43. end
  44. function command.STAT(addr, ti)
  45. return list_srv(ti, function(v) return v end, "STAT")
  46. end
  47. function command.KILL(_, handle)
  48. skynet.kill(handle)
  49. local ret = { [skynet.address(handle)] = tostring(services[handle]) }
  50. services[handle] = nil
  51. return ret
  52. end
  53. function command.MEM(addr, ti)
  54. return list_srv(ti, function(kb, addr)
  55. local v = services[addr]
  56. if type(kb) == "string" then
  57. return string.format("%s (%s)", kb, v)
  58. else
  59. return string.format("%.2f Kb (%s)",kb,v)
  60. end
  61. end, "MEM")
  62. end
  63. function command.GC(addr, ti)
  64. for k,v in pairs(services) do
  65. skynet.send(k,"debug","GC")
  66. end
  67. return command.MEM(addr, ti)
  68. end
  69. function command.REMOVE(_, handle, kill)
  70. services[handle] = nil
  71. local response = instance[handle]
  72. if response then
  73. -- instance is dead
  74. response(not kill) -- return nil to caller of newservice, when kill == false
  75. instance[handle] = nil
  76. launch_session[handle] = nil
  77. end
  78. -- don't return (skynet.ret) because the handle may exit
  79. return NORET
  80. end
  81. local function launch_service(service, ...)
  82. local param = table.concat({...}, " ")
  83. local inst = skynet.launch(service, param)
  84. local session = skynet.context()
  85. local response = skynet.response()
  86. if inst then
  87. services[inst] = service .. " " .. param
  88. instance[inst] = response
  89. launch_session[inst] = session
  90. else
  91. response(false)
  92. return
  93. end
  94. return inst
  95. end
  96. function command.LAUNCH(_, service, ...)
  97. launch_service(service, ...)
  98. return NORET
  99. end
  100. function command.LOGLAUNCH(_, service, ...)
  101. local inst = launch_service(service, ...)
  102. if inst then
  103. core.command("LOGON", skynet.address(inst))
  104. end
  105. return NORET
  106. end
  107. function command.ERROR(address)
  108. -- see serivce-src/service_lua.c
  109. -- init failed
  110. local response = instance[address]
  111. if response then
  112. response(false)
  113. launch_session[address] = nil
  114. instance[address] = nil
  115. end
  116. services[address] = nil
  117. return NORET
  118. end
  119. function command.LAUNCHOK(address)
  120. -- init notice
  121. local response = instance[address]
  122. if response then
  123. response(true, address)
  124. instance[address] = nil
  125. launch_session[address] = nil
  126. end
  127. return NORET
  128. end
  129. function command.QUERY(_, request_session)
  130. for address, session in pairs(launch_session) do
  131. if session == request_session then
  132. return address
  133. end
  134. end
  135. end
  136. -- for historical reasons, launcher support text command (for C service)
  137. skynet.register_protocol {
  138. name = "text",
  139. id = skynet.PTYPE_TEXT,
  140. unpack = skynet.tostring,
  141. dispatch = function(session, address , cmd)
  142. if cmd == "" then
  143. command.LAUNCHOK(address)
  144. elseif cmd == "ERROR" then
  145. command.ERROR(address)
  146. else
  147. error ("Invalid text command " .. cmd)
  148. end
  149. end,
  150. }
  151. skynet.dispatch("lua", function(session, address, cmd , ...)
  152. cmd = string.upper(cmd)
  153. local f = command[cmd]
  154. if f then
  155. local ret = f(address, ...)
  156. if ret ~= NORET then
  157. skynet.ret(skynet.pack(ret))
  158. end
  159. else
  160. skynet.ret(skynet.pack {"Unknown command"} )
  161. end
  162. end)
  163. skynet.start(function() end)