赞
踩
inject是一个用于动态加载 Lua 代码文件并执行其中定义的函数的功能。可以在运行时动态加载 Lua 代码文件,然后调用其中定义的函数,通过修改模块及其函数的upvalue,实现代码的动态注入和执行。热更实现的大概思路:通过向指定服务注入cmd实现热更
参考wiki https://blog.codingnow.com/2016/11/lua_update.html
-- debug_console.lua
local function adjust_address(address)
local prefix = address:sub(1,1)
if prefix == '.' then
return assert(skynet.localname(address), "Not a valid name")
elseif prefix ~= ':' then
address = assert(tonumber("0x" .. address), "Need an address") | (skynet.harbor(skynet.self()) << 24)
end
return address
end
function COMMAND.inject(address, filename, ...)
address = adjust_address(address)
local f = io.open(filename, "rb")
if not f then
return "Can't open " .. filename
end
local source = f:read "*a"
f:close()
local ok, output = skynet.call(address, "debug", "RUN", source, filename, ...)
if ok == false then
error(output)
end
return output
end
adjust_address: 用于调整传入的地址参数,对传入的地址参数进行转换,以保证将热更脚本注入到正确的服务地址
io.open(filename, “rb”): 以二进制只读的方式读取文件内容
source: 存放读取到的热更脚本内容
skynet.call(address, “debug”, “RUN”, …): 通过skynet的debug消息类型,将读取的热更脚本内容注入到目标服务地址(debug.RUN内部实现)
-- skynet.debug.lua
function dbgcmd.RUN(source, filename, ...)
local inject = require "skynet.inject"
local args = table.pack(...)
local ok, output = inject(skynet, source, filename, args, export.dispatch, skynet.register_protocol)
collectgarbage "collect"
skynet.ret(skynet.pack(ok, table.concat(output, "\n")))
end
-- skynet.inject.lua
return function(skynet, source, filename, args, ...)
if filename then
filename = "@" .. filename
else
filename = "=(load)"
end
local output = {}
local function print(...)
local value = { ... }
for k,v in ipairs(value) do
value[k] = tostring(v)
end
table.insert(output, table.concat(value, "\t"))
end
local u = {}
local unique = {}
local funcs = { ... }
for k, func in ipairs(funcs) do
getupvaluetable(u, func, unique)
end
local p = {}
local proto = u.proto
if proto then
for k,v in pairs(proto) do
local name, dispatch = v.name, v.dispatch
if name and dispatch and not p[name] then
local pp = {}
p[name] = pp
getupvaluetable(pp, dispatch, unique)
end
end
end
local env = setmetatable( { print = print , _U = u, _P = p}, { __index = _ENV })
local func, err = load(source, filename, "bt", env)
if not func then
return false, { err }
end
local ok, err = skynet.pcall(func, table.unpack(args, 1, args.n))
if not ok then
table.insert(output, err)
return false, output
end
return true, output
end
这两段核心代码实现了一个动态加载和执行 Lua 代码的功能,通过构建环境表、加载代码并执行,最终返回执行结果。这个函数是实现动态注入功能的关键部分,能够实现在 Skynet 框架中动态加载并执行 Lua代码,完成注入热更脚本
方案1:
方案2:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。