aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthew Wild <mwild1@gmail.com>2012-01-22 18:46:17 +0000
committerMatthew Wild <mwild1@gmail.com>2012-01-22 18:46:17 +0000
commit184f681d3f1d8eef901e16f8d5bdc0c5a6c11edf (patch)
tree11d75a02bff664165b2ec64e15fdeee405b5fe0b
parent36542853efea8ca4a4767996408e46b1657ec93e (diff)
downloadprosody-184f681d3f1d8eef901e16f8d5bdc0c5a6c11edf.tar.gz
prosody-184f681d3f1d8eef901e16f8d5bdc0c5a6c11edf.zip
modulemanager: Some reorganisation. Only external change is (should be) that module-unloaded and module-loaded are no longer fired when reloading a module, the new event module-reloaded is fired instead.
-rw-r--r--core/modulemanager.lua156
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