mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-24 20:23:06 +00:00
use a patch to hotfix
This commit is contained in:
@@ -101,9 +101,9 @@ local function test_result(ok, ...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function snax.hotfix(obj, ...)
|
function snax.hotfix(obj, source, ...)
|
||||||
local t = snax.interface(obj.type)
|
local t = snax.interface(obj.type)
|
||||||
test_result(skynet_call(obj.handle, "lua", t.system.hotfix, obj.type, ...))
|
return test_result(skynet_call(obj.handle, "lua", t.system.hotfix, source, ...))
|
||||||
end
|
end
|
||||||
|
|
||||||
return snax
|
return snax
|
||||||
|
|||||||
@@ -3,105 +3,92 @@ local io = io
|
|||||||
|
|
||||||
local hotfix = {}
|
local hotfix = {}
|
||||||
|
|
||||||
local function loader(filename, ...)
|
local function collect_uv(f , uv)
|
||||||
local f = io.open(filename, "rb")
|
|
||||||
if not f then
|
|
||||||
return false, string.format("Can't open %s", filename)
|
|
||||||
end
|
|
||||||
local source = f:read "*a"
|
|
||||||
f:close()
|
|
||||||
|
|
||||||
return load(source, "@"..filename, ...)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function check_funcs(f1,f2)
|
|
||||||
for k,a in pairs(f1) do
|
|
||||||
local b = f2[k]
|
|
||||||
assert(a[1] == b[1] and a[2] == b[2] and a[3] == b[3] ,
|
|
||||||
string.format("%s.%s %s.%s , function mismatch", a[2], a[3] , b[2], b[3]))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function get_upvalues(f, global)
|
|
||||||
local uv = {}
|
|
||||||
local i = 1
|
local i = 1
|
||||||
while true do
|
while true do
|
||||||
local name = debug.getupvalue(f, i)
|
local name, value = debug.getupvalue(f, i)
|
||||||
if name then
|
if name == nil then
|
||||||
local uid = debug.upvalueid(f, i)
|
|
||||||
uv[name] = i
|
|
||||||
if global[name] and global[name][1] ~= uid then
|
|
||||||
error(string.format("ambiguity upvalue %s", name))
|
|
||||||
end
|
|
||||||
global[name] = { uid , f , i }
|
|
||||||
else
|
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
i = i + 1
|
local id = debug.upvalueid(f, i)
|
||||||
end
|
|
||||||
return uv
|
|
||||||
end
|
|
||||||
|
|
||||||
local function join_upvalues(f, new_f, uv)
|
if uv[name] then
|
||||||
local i = 1
|
assert(uv[name].id == id, string.format("ambiguity local value %s", name))
|
||||||
while true do
|
|
||||||
local name = debug.getupvalue(new_f, i)
|
|
||||||
if name then
|
|
||||||
if uv[name] then
|
|
||||||
debug.upvaluejoin(new_f, i, f, uv[name])
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
break
|
uv[name] = { func = f, index = i, id = id }
|
||||||
|
|
||||||
|
if type(value) == "function" then
|
||||||
|
collect_uv(value, uv)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
i = i + 1
|
i = i + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function join_global_upvalues(f, global)
|
local function collect_all_uv(funcs)
|
||||||
local i = 1
|
|
||||||
while true do
|
|
||||||
local name = debug.getupvalue(f, i)
|
|
||||||
if name then
|
|
||||||
local uv = global[name]
|
|
||||||
if uv then
|
|
||||||
debug.upvaluejoin(f, i, uv[2], uv[3])
|
|
||||||
end
|
|
||||||
else
|
|
||||||
break
|
|
||||||
end
|
|
||||||
i = i + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function update_upvalues(funcs, newfuncs)
|
|
||||||
local global = {}
|
local global = {}
|
||||||
for id,v in pairs(funcs) do
|
for _, v in pairs(funcs) do
|
||||||
local f = v[4]
|
if v[4] then
|
||||||
local new_f = newfuncs[id][4]
|
collect_uv(v[4], global)
|
||||||
if f and new_f then
|
|
||||||
local uv = get_upvalues(f, global)
|
|
||||||
v[4] = new_f
|
|
||||||
join_upvalues(f, new_f, uv)
|
|
||||||
newfuncs[id] = nil
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
for id,v in pairs(newfuncs) do
|
|
||||||
if v[2] == "system" then
|
return global
|
||||||
funcs[id] = v
|
end
|
||||||
local f = v[4]
|
|
||||||
join_global_upvalues(f, global)
|
local function loader(source)
|
||||||
else
|
return function (filename, ...)
|
||||||
error(string.format("Detect unkown function %s.%s", v[2], v[3]))
|
return load(source, "=patch", ...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function find_func(funcs, group , name)
|
||||||
|
for _, desc in pairs(funcs) do
|
||||||
|
local _, g, n = table.unpack(desc)
|
||||||
|
if group == g and name == n then
|
||||||
|
return desc
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function inject(funcs, new)
|
local dummy_env = {}
|
||||||
check_funcs(funcs, new)
|
|
||||||
update_upvalues(funcs, new)
|
local function patch_func(funcs, global, group, name, f)
|
||||||
|
local desc = assert(find_func(funcs, group, name) , string.format("Patch mismatch %s.%s", group, name))
|
||||||
|
local i = 1
|
||||||
|
while true do
|
||||||
|
local name, value = debug.getupvalue(f, i)
|
||||||
|
if name == nil then
|
||||||
|
break
|
||||||
|
elseif value == nil or value == dummy_env then
|
||||||
|
local old_uv = global[name]
|
||||||
|
if old_uv then
|
||||||
|
debug.upvaluejoin(f, i, old_uv.func, old_uv.index)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
i = i + 1
|
||||||
|
end
|
||||||
|
desc[4] = f
|
||||||
end
|
end
|
||||||
|
|
||||||
return function (funcs, modname)
|
local function inject(funcs, source, ...)
|
||||||
local new_funcs = si(modname, _ENV, loader)
|
local patch = si("patch", dummy_env, loader(source))
|
||||||
return pcall(inject, funcs, new_funcs)
|
local global = collect_all_uv(funcs)
|
||||||
|
|
||||||
|
for _, v in pairs(patch) do
|
||||||
|
local _, group, name, f = table.unpack(v)
|
||||||
|
if f then
|
||||||
|
patch_func(funcs, global, group, name, f)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local hf = find_func(patch, "system", "hotfix")
|
||||||
|
if hf and hf[4] then
|
||||||
|
return hf[4](...)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return function (funcs, source, ...)
|
||||||
|
return pcall(inject, funcs, source, ...)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -11,13 +11,7 @@ skynet.start(function()
|
|||||||
local command = method[3]
|
local command = method[3]
|
||||||
if command == "hotfix" then
|
if command == "hotfix" then
|
||||||
local hotfix = require "snax_hotfix"
|
local hotfix = require "snax_hotfix"
|
||||||
local ok, msg = hotfix(func, ...)
|
skynet.ret(skynet.pack(hotfix(func, ...)))
|
||||||
if ok then
|
|
||||||
local hf = func[id][4]
|
|
||||||
skynet.ret(skynet.pack(pcall(hf, select(2,...))))
|
|
||||||
else
|
|
||||||
skynet.ret(skynet.pack(ok, msg))
|
|
||||||
end
|
|
||||||
elseif command == "init" then
|
elseif command == "init" then
|
||||||
assert(not init, "Already init")
|
assert(not init, "Already init")
|
||||||
local initfunc = method[4] or function() end
|
local initfunc = method[4] or function() end
|
||||||
|
|||||||
@@ -6,7 +6,23 @@ skynet.start(function()
|
|||||||
print(ps.pub.hello())
|
print(ps.pub.hello())
|
||||||
print(ps.req.ping("foobar"))
|
print(ps.req.ping("foobar"))
|
||||||
print(pcall(ps.req.error))
|
print(pcall(ps.req.error))
|
||||||
snax.hotfix(ps)
|
print("Hotfix (i) :", snax.hotfix(ps, [[
|
||||||
|
|
||||||
|
local i
|
||||||
|
local hello
|
||||||
|
|
||||||
|
function subscribe.hello()
|
||||||
|
i = i + 1
|
||||||
|
print ("fix", i, hello)
|
||||||
|
end
|
||||||
|
|
||||||
|
function hotfix(...)
|
||||||
|
local temp = i
|
||||||
|
i = 100
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
|
||||||
|
]]))
|
||||||
print(ps.pub.hello())
|
print(ps.pub.hello())
|
||||||
print(snax.kill(ps,"exit"))
|
print(snax.kill(ps,"exit"))
|
||||||
skynet.exit()
|
skynet.exit()
|
||||||
|
|||||||
Reference in New Issue
Block a user