diff options
Diffstat (limited to 'core/modulemanager.lua')
-rw-r--r-- | core/modulemanager.lua | 156 |
1 files changed, 94 insertions, 62 deletions
diff --git a/core/modulemanager.lua b/core/modulemanager.lua index bbe24e32..1846e0f0 100644 --- a/core/modulemanager.lua +++ b/core/modulemanager.lua @@ -90,7 +90,45 @@ end prosody_events.add_handler("host-activated", load_modules_for_host); -- -function load(host, module_name, config) +--- Private helpers --- + +local function do_unload_module(host, name) + local mod = get_module(host, name); + if not mod then return nil, "module-not-loaded"; end + + if module_has_method(mod, "unload") then + local ok, err = call_module_method(mod, "unload"); + if (not ok) and err then + log("warn", "Non-fatal error unloading module '%s' on '%s': %s", name, host, err); + end + end + -- unhook event handlers hooked by module:hook + for event, handlers in pairs(hooks:get(host, name) or NULL) do + for handler in pairs(handlers or NULL) do + (hosts[host] or prosody).events.remove_handler(event, handler); + end + end + -- unhook event handlers hooked by module:hook_global + for event, handlers in pairs(hooks:get("*", name) or NULL) do + for handler in pairs(handlers or NULL) do + prosody.events.remove_handler(event, handler); + end + end + hooks:remove(host, name); + if mod.module.items then -- remove items + for key,t in pairs(mod.module.items) do + for i = #t,1,-1 do + local value = t[i]; + t[i] = nil; + hosts[host].events.fire_event("item-removed/"..key, {source = mod.module, item = value}); + end + end + end + modulemap[host][name] = nil; + return true; +end + +local function do_load_module(host, module_name) if not (host and module_name) then return nil, "insufficient-parameters"; elseif not hosts[host] then @@ -116,7 +154,9 @@ function load(host, module_name, config) end local _log = logger.init(host..":"..module_name); - local api_instance = setmetatable({ name = module_name, host = host, path = err, _log = _log, log = function (self, ...) return _log(...); end }, { __index = api }); + local api_instance = setmetatable({ name = module_name, host = host, path = err, + _log = _log, log = function (self, ...) return _log(...); end } + , { __index = api }); local pluginenv = setmetatable({ module = api_instance }, { __index = _G }); api_instance.environment = pluginenv; @@ -125,11 +165,12 @@ function load(host, module_name, config) hosts[host].modules = modulemap[host]; modulemap[host][module_name] = pluginenv; - local success, err = pcall(mod); - if success then + local ok, err = pcall(mod); + if ok then + -- Call module's "load" if module_has_method(pluginenv, "load") then - success, err = call_module_method(pluginenv, "load"); - if not success then + ok, err = call_module_method(pluginenv, "load"); + if not ok then log("warn", "Error loading module '%s' on '%s': %s", module_name, host, err or "nil"); end end @@ -142,62 +183,12 @@ function load(host, module_name, config) end else log("error", "Error initializing module '%s' on '%s': %s", module_name, host, err or "nil"); + do_unload_module(api_instance.host, module_name); -- Ignore error, module may be partially-loaded end - if success then - (hosts[api_instance.host] or prosody).events.fire_event("module-loaded", { module = module_name, host = host }); - return true; - else -- load failed, unloading - unload(api_instance.host, module_name); - return nil, err; - end -end - -function get_module(host, name) - return modulemap[host] and modulemap[host][name]; -end - -function is_loaded(host, name) - return modulemap[host] and modulemap[host][name] and true; + return ok and mod, err; end -function unload(host, name, ...) - local mod = get_module(host, name); - if not mod then return nil, "module-not-loaded"; end - - if module_has_method(mod, "unload") then - local ok, err = call_module_method(mod, "unload"); - if (not ok) and err then - log("warn", "Non-fatal error unloading module '%s' on '%s': %s", name, host, err); - end - end - -- unhook event handlers hooked by module:hook - for event, handlers in pairs(hooks:get(host, name) or NULL) do - for handler in pairs(handlers or NULL) do - (hosts[host] or prosody).events.remove_handler(event, handler); - end - end - -- unhook event handlers hooked by module:hook_global - for event, handlers in pairs(hooks:get("*", name) or NULL) do - for handler in pairs(handlers or NULL) do - prosody.events.remove_handler(event, handler); - end - end - hooks:remove(host, name); - if mod.module.items then -- remove items - for key,t in pairs(mod.module.items) do - for i = #t,1,-1 do - local value = t[i]; - t[i] = nil; - hosts[host].events.fire_event("item-removed/"..key, {source = mod.module, item = value}); - end - end - end - modulemap[host][name] = nil; - (hosts[host] or prosody).events.fire_event("module-unloaded", { module = name, host = host }); - return true; -end - -function reload(host, name, ...) +local function do_reload_module(host, name) local mod = get_module(host, name); if not mod then return nil, "module-not-loaded"; end @@ -224,8 +215,8 @@ function reload(host, name, ...) end end - unload(host, name, ...); - local ok, err = load(host, name, ...); + do_unload_module(host, name); + local ok, err = do_load_module(host, name); if ok then mod = get_module(host, name); if module_has_method(mod, "restore") then @@ -234,11 +225,52 @@ function reload(host, name, ...) log("warn", "Error restoring module '%s' from '%s': %s", name, host, err); end end - return true; + end + return ok and mod, err; +end + +--- Public API --- + +-- Load a module and fire module-loaded event +function load(host, name) + local mod, err = do_load_module(host, name); + if mod then + (hosts[mod.host] or prosody).events.fire_event("module-loaded", { module = module_name, host = host }); + end + return mod, err; +end + +-- Unload a module and fire module-unloaded +function unload(host, name) + local ok, err = do_unload_module(host, name); + if ok then + (hosts[host] or prosody).events.fire_event("module-unloaded", { module = name, host = host }); + end + return ok, err; +end + +function reload(host, name) + local ok, err = do_reload_module(host, name); + if ok then + (hosts[host] or prosody).events.fire_event("module-reloaded", { module = name, host = host }); + elseif not is_loaded(host, name) then + (hosts[host] or prosody).events.fire_event("module-unloaded", { module = name, host = host }); end return ok, err; end +function get_module(host, name) + return modulemap[host] and modulemap[host][name]; +end + +function get_modules(host) + return modulemap[host]; +end + +function is_loaded(host, name) + return modulemap[host] and modulemap[host][name] and true; +end + function module_has_method(module, method) return type(module.module[method]) == "function"; end |