Blame view

publish/skynet/service/service_mgr.lua 4.72 KB
4d6f285d   zhouhaihai   增加发布功能
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
  local skynet = require "skynet"
  require "skynet.manager"	-- import skynet.register
  local snax = require "skynet.snax"
  
  local cmd = {}
  local service = {}
  
  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
  
  	for _,v in ipairs(s) do
  		skynet.wakeup(v.co)
  	end
  
  	if ok then
  		return handle
  	else
  		error(tostring(handle))
  	end
  end
  
  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[name] = s
  	elseif type(s) == "string" then
  		error(s)
  	end
  
  	assert(type(s) == "table")
  
  	local session, source = skynet.context()
  
  	if s.launch == nil and func then
  		s.launch = {
  			session = session,
  			source = source,
  			co = co,
  		}
  		return request(name, func, ...)
  	end
  
  	table.insert(s, {
  		co = co,
  		session = session,
  		source = source,
  	})
  	skynet.wait()
  	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
  			local querying = {}
  			if v.launch then
  				local session = skynet.task(v.launch.co)
  				local launching_address = skynet.call(".launcher", "lua", "QUERY", session)
  				if launching_address then
  					table.insert(querying, "Init as " .. skynet.address(launching_address))
  					table.insert(querying,  skynet.call(launching_address, "debug", "TASK", "init"))
  					table.insert(querying, "Launching from " .. skynet.address(v.launch.source))
  					table.insert(querying, skynet.call(v.launch.source, "debug", "TASK", v.launch.session))
  				end
  			end
  			if #v > 0 then
  				table.insert(querying , "Querying:" )
  				for _, detail in ipairs(v) do
  					table.insert(querying, skynet.address(detail.source) .. " " .. tostring(skynet.call(detail.source, "debug", "TASK", detail.session)))
  				end
  			end
  			v = table.concat(querying, "\n")
  		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
  	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()
  	local function waitfor_remote(cmd, name, ...)
  		local global_name = "@" .. name
  		local local_name
  		if name == "snaxd" then
  			local_name = global_name .. "." .. (...)
  		else
  			local_name = global_name
  		end
  		return waitfor(local_name, skynet.call, "SERVICE", "lua", cmd, global_name, ...)
  	end
  
  	function cmd.GLAUNCH(...)
  		return waitfor_remote("LAUNCH", ...)
  	end
  
  	function cmd.GQUERY(...)
  		return waitfor_remote("QUERY", ...)
  	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, ...)
  		local f = cmd[command]
  		if f == nil then
  			skynet.ret(skynet.pack(nil, "Invalid command " .. command))
  			return
  		end
  
  		local ok, r = pcall(f, ...)
  
  		if ok then
  			skynet.ret(skynet.pack(r))
  		else
  			skynet.ret(skynet.pack(nil, r))
  		end
  	end)
  	local handle = skynet.localname ".service"
  	if  handle then
  		skynet.error(".service is already register by ", skynet.address(handle))
  		skynet.exit()
  	else
  		skynet.register(".service")
  	end
  	if skynet.getenv "standalone" then
  		skynet.register("SERVICE")
  		register_global()
  	else
  		register_local()
  	end
  end)