mirror of
https://github.com/koreader/koreader.git
synced 2025-12-13 20:36:53 +01:00
Add plugin handler traceback when started in debug mode (#13677)
This commit is contained in:
@@ -1,3 +1,17 @@
|
||||
--[[--
|
||||
Allows extending KOReader through plugins.
|
||||
|
||||
Plugins will be sourced from DEFAULT_PLUGIN_PATH. If set, extra_plugin_paths
|
||||
is also used. Directories are considered plugins if the name matches
|
||||
".+%.koplugin".
|
||||
|
||||
Running with debug turned on will log stacktraces for event handlers.
|
||||
Plugins are controlled by the following settings.
|
||||
|
||||
- plugins_disabled
|
||||
- extra_plugin_paths
|
||||
]]
|
||||
local dbg = require("dbg")
|
||||
local lfs = require("libs/libkoreader-lfs")
|
||||
local logger = require("logger")
|
||||
local util = require("util")
|
||||
@@ -55,22 +69,54 @@ local function getMenuTable(plugin)
|
||||
return t
|
||||
end
|
||||
|
||||
local function sandboxPluginEventHandlers(plugin)
|
||||
for key, value in pairs(plugin) do
|
||||
if key:sub(1, 2) == "on" and type(value) == "function" then
|
||||
plugin[key] = function(self, ...)
|
||||
local ok, re = pcall(value, self, ...)
|
||||
if ok then
|
||||
return re
|
||||
else
|
||||
logger.err("failed to call event handler", key, re)
|
||||
return false
|
||||
end
|
||||
end
|
||||
-- Event handlers defined by plugins are wrapped in a HandlerSandbox.
|
||||
-- The purpose of the sandbox is to get meaningful stack-traces out of errors happening in plugins.
|
||||
local HandlerSandbox = { mt = {} }
|
||||
|
||||
function HandlerSandbox.new(context, fname, f, module)
|
||||
local t = {
|
||||
context = context,
|
||||
fname = fname,
|
||||
f = f,
|
||||
log_stacktrace = dbg.is_on,
|
||||
}
|
||||
return setmetatable(t, HandlerSandbox.mt)
|
||||
end
|
||||
|
||||
function HandlerSandbox:call(module, ...)
|
||||
-- NOTE the signature is (self, module, ...)
|
||||
-- self refers to the HandlerSandbox instance but module refers to the
|
||||
-- self parameter of the handlers
|
||||
local ok, re
|
||||
if self.log_stacktrace then
|
||||
local traceback = function(err)
|
||||
-- do not print 2 topmost entries in traceback. The first is this local function
|
||||
-- and the second is the `call` method of HandlerSandbox.
|
||||
logger.err("An error occurred while executing a handler:\n"..err.."\n"..debug.traceback(self.context.name..":"..self.fname, 2))
|
||||
end
|
||||
ok, re = xpcall(self.f, traceback, module, ...)
|
||||
else
|
||||
ok, re = pcall(self.f, module, ...)
|
||||
if not ok then logger.err("An error occurred while executing handler "..self.context.name..":"..self.fname..":\n", re) end
|
||||
end
|
||||
-- NOTE backward compatibility with previous implementation
|
||||
-- of handler wrapping that returned false on error
|
||||
if ok then
|
||||
return re
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
HandlerSandbox.mt.__call = HandlerSandbox.call
|
||||
|
||||
local function sandboxPluginEventHandlers(plugin)
|
||||
for key, value in pairs(plugin) do
|
||||
if key:sub(1, 2) == "on" and type(value) == "function" then
|
||||
plugin[key] = HandlerSandbox.new(plugin, key, value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local PluginLoader = {
|
||||
show_info = true,
|
||||
|
||||
Reference in New Issue
Block a user