initial
This commit is contained in:
commit
0f5df88579
175
using_xpcall.lua
Normal file
175
using_xpcall.lua
Normal file
@ -0,0 +1,175 @@
|
||||
local formspec_log = futil and futil.Deque and futil.Deque()
|
||||
|
||||
if not formspec_log then
|
||||
-- no deque implementation found
|
||||
local deq = {}
|
||||
deq.size = function(self)
|
||||
return #self
|
||||
end
|
||||
deq.push_front = function(self, v)
|
||||
table.insert(self, v)
|
||||
end
|
||||
deq.pop_back = function(self)
|
||||
local v = self[1]
|
||||
table.remove(self, 1)
|
||||
return v
|
||||
end
|
||||
deq.iterate = function(self)
|
||||
local i = 0
|
||||
return function()
|
||||
i = i + 1
|
||||
local v = self[i]
|
||||
if v then
|
||||
return v
|
||||
end
|
||||
end
|
||||
end
|
||||
deq.__index = deq
|
||||
formspec_log = setmetatable({}, deq)
|
||||
end
|
||||
|
||||
local LOG_SIZE = 100
|
||||
|
||||
-- use deque for logging, pushing oldest log item out
|
||||
local function log_add(msg)
|
||||
core.log('error', type(msg) == "string" and msg or dump(msg))
|
||||
formspec_log:push_front(msg)
|
||||
if formspec_log:size() > LOG_SIZE then
|
||||
formspec_log:pop_back()
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function formspec_log_clear()
|
||||
formspec_log:clear()
|
||||
end
|
||||
|
||||
|
||||
-- passes to xpcall to be able to capture the call stack
|
||||
local function error_printer(err)
|
||||
log_add(err)
|
||||
log_add(debug.traceback("----------------------", 2))
|
||||
end
|
||||
|
||||
|
||||
-- Takes any function and returns a function that takes and returns
|
||||
-- same [multiple] values if no error happens. On error, logs it.
|
||||
local function safe_wrap(func)
|
||||
local function wrap_f(...)
|
||||
local res = {xpcall(func, error_printer, ...)}
|
||||
if res[1] then
|
||||
-- no error, just return rest of the values
|
||||
return select(2, unpack(res))
|
||||
else
|
||||
-- error was logged by error_printer already
|
||||
local msg = dump(res[2])
|
||||
if msg then
|
||||
log_add(msg)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
end
|
||||
return wrap_f
|
||||
end
|
||||
|
||||
|
||||
local function formspec_log_show(playername)
|
||||
local log_items = {}
|
||||
for item in formspec_log:iterate() do
|
||||
table.insert(log_items, type(item) == "string" and item or dump(item))
|
||||
end
|
||||
local formspec_template = [[ formspec_version[6] size[16,9] textarea[0.1,0.4;15.8,8.5;log;log;%s] ]]
|
||||
local log_text = core.formspec_escape(table.concat(log_items,'\n'))
|
||||
core.show_formspec(playername, "yl_commons:formspec_log", string.format(formspec_template, log_text))
|
||||
end
|
||||
|
||||
|
||||
|
||||
core.register_chatcommand(
|
||||
"debug_formspec_log_show",
|
||||
{
|
||||
privs = { server = true },
|
||||
func = function(playername, _params)
|
||||
formspec_log_show(playername)
|
||||
return true
|
||||
end,
|
||||
}
|
||||
)
|
||||
|
||||
core.register_chatcommand(
|
||||
"debug_formspec_log_clear",
|
||||
{
|
||||
privs = { server = true },
|
||||
func = function(playername, _params)
|
||||
formspec_log_clear(playername)
|
||||
return true
|
||||
end,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
--- Usage example
|
||||
|
||||
local function bugged(playername, params)
|
||||
for _=1,tonumber(params) do
|
||||
core.chat_send_all("Hello!")
|
||||
end
|
||||
return true, playername
|
||||
end
|
||||
|
||||
|
||||
core.register_chatcommand(
|
||||
"bugged",
|
||||
{
|
||||
privs = { },
|
||||
func = function(playername, params)
|
||||
return bugged(playername, params)
|
||||
end,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
core.register_chatcommand(
|
||||
"bugged_safe",
|
||||
{
|
||||
privs = { },
|
||||
func = function(playername, params)
|
||||
local status, ret1, ret2 = pcall(bugged, playername, params)
|
||||
-- `status` will be `false` if function call raised an error
|
||||
-- `ret1` will contain the error message on error, or first returned value on no errors
|
||||
-- `ret2` will contain second returned value on no errors
|
||||
-- etc.
|
||||
return status, string.format("%s | %s", ret1, ret2)
|
||||
end,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
core.register_chatcommand(
|
||||
"bugged_safe2",
|
||||
{
|
||||
privs = { },
|
||||
func = function(playername, params)
|
||||
-- NOTE: if this does not work, you may need to make sure you're using luajit or newer lua
|
||||
local status, ret1, ret2 = xpcall(bugged, error_printer, playername, params)
|
||||
-- `status` will be `false` if function call raised an error
|
||||
-- `ret1` will contain the error message on error, or first returned value on no errors
|
||||
-- `ret2` will contain second returned value on no errors
|
||||
-- etc.
|
||||
return status, string.format("%s | %s", ret1, ret2)
|
||||
end,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
core.register_chatcommand(
|
||||
"bugged_safe3",
|
||||
{
|
||||
privs = { },
|
||||
func = function(playername, params)
|
||||
local safe_bugged = safe_wrap(bugged)
|
||||
return safe_bugged(playername, params)
|
||||
end,
|
||||
}
|
||||
)
|
Loading…
Reference in New Issue
Block a user