Software / code / prosody
Comparison
core/modulemanager.lua @ 4532:d8dbf569766c
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.
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Sun, 22 Jan 2012 18:46:17 +0000 |
| parent | 4531:c778ce7e3c78 |
| child | 4533:c6480d17be1e |
comparison
equal
deleted
inserted
replaced
| 4531:c778ce7e3c78 | 4532:d8dbf569766c |
|---|---|
| 88 end | 88 end |
| 89 end | 89 end |
| 90 prosody_events.add_handler("host-activated", load_modules_for_host); | 90 prosody_events.add_handler("host-activated", load_modules_for_host); |
| 91 -- | 91 -- |
| 92 | 92 |
| 93 function load(host, module_name, config) | 93 --- Private helpers --- |
| 94 if not (host and module_name) then | 94 |
| 95 return nil, "insufficient-parameters"; | 95 local function do_unload_module(host, name) |
| 96 elseif not hosts[host] then | |
| 97 return nil, "unknown-host"; | |
| 98 end | |
| 99 | |
| 100 if not modulemap[host] then | |
| 101 modulemap[host] = {}; | |
| 102 end | |
| 103 | |
| 104 if modulemap[host][module_name] then | |
| 105 log("warn", "%s is already loaded for %s, so not loading again", module_name, host); | |
| 106 return nil, "module-already-loaded"; | |
| 107 elseif modulemap["*"][module_name] then | |
| 108 return nil, "global-module-already-loaded"; | |
| 109 end | |
| 110 | |
| 111 | |
| 112 local mod, err = pluginloader.load_code(module_name); | |
| 113 if not mod then | |
| 114 log("error", "Unable to load module '%s': %s", module_name or "nil", err or "nil"); | |
| 115 return nil, err; | |
| 116 end | |
| 117 | |
| 118 local _log = logger.init(host..":"..module_name); | |
| 119 local api_instance = setmetatable({ name = module_name, host = host, path = err, _log = _log, log = function (self, ...) return _log(...); end }, { __index = api }); | |
| 120 | |
| 121 local pluginenv = setmetatable({ module = api_instance }, { __index = _G }); | |
| 122 api_instance.environment = pluginenv; | |
| 123 | |
| 124 setfenv(mod, pluginenv); | |
| 125 hosts[host].modules = modulemap[host]; | |
| 126 modulemap[host][module_name] = pluginenv; | |
| 127 | |
| 128 local success, err = pcall(mod); | |
| 129 if success then | |
| 130 if module_has_method(pluginenv, "load") then | |
| 131 success, err = call_module_method(pluginenv, "load"); | |
| 132 if not success then | |
| 133 log("warn", "Error loading module '%s' on '%s': %s", module_name, host, err or "nil"); | |
| 134 end | |
| 135 end | |
| 136 | |
| 137 -- Use modified host, if the module set one | |
| 138 if api_instance.host == "*" and host ~= "*" then | |
| 139 modulemap[host][module_name] = nil; | |
| 140 modulemap["*"][module_name] = pluginenv; | |
| 141 api_instance:set_global(); | |
| 142 end | |
| 143 else | |
| 144 log("error", "Error initializing module '%s' on '%s': %s", module_name, host, err or "nil"); | |
| 145 end | |
| 146 if success then | |
| 147 (hosts[api_instance.host] or prosody).events.fire_event("module-loaded", { module = module_name, host = host }); | |
| 148 return true; | |
| 149 else -- load failed, unloading | |
| 150 unload(api_instance.host, module_name); | |
| 151 return nil, err; | |
| 152 end | |
| 153 end | |
| 154 | |
| 155 function get_module(host, name) | |
| 156 return modulemap[host] and modulemap[host][name]; | |
| 157 end | |
| 158 | |
| 159 function is_loaded(host, name) | |
| 160 return modulemap[host] and modulemap[host][name] and true; | |
| 161 end | |
| 162 | |
| 163 function unload(host, name, ...) | |
| 164 local mod = get_module(host, name); | 96 local mod = get_module(host, name); |
| 165 if not mod then return nil, "module-not-loaded"; end | 97 if not mod then return nil, "module-not-loaded"; end |
| 166 | 98 |
| 167 if module_has_method(mod, "unload") then | 99 if module_has_method(mod, "unload") then |
| 168 local ok, err = call_module_method(mod, "unload"); | 100 local ok, err = call_module_method(mod, "unload"); |
| 191 hosts[host].events.fire_event("item-removed/"..key, {source = mod.module, item = value}); | 123 hosts[host].events.fire_event("item-removed/"..key, {source = mod.module, item = value}); |
| 192 end | 124 end |
| 193 end | 125 end |
| 194 end | 126 end |
| 195 modulemap[host][name] = nil; | 127 modulemap[host][name] = nil; |
| 196 (hosts[host] or prosody).events.fire_event("module-unloaded", { module = name, host = host }); | |
| 197 return true; | 128 return true; |
| 198 end | 129 end |
| 199 | 130 |
| 200 function reload(host, name, ...) | 131 local function do_load_module(host, module_name) |
| 132 if not (host and module_name) then | |
| 133 return nil, "insufficient-parameters"; | |
| 134 elseif not hosts[host] then | |
| 135 return nil, "unknown-host"; | |
| 136 end | |
| 137 | |
| 138 if not modulemap[host] then | |
| 139 modulemap[host] = {}; | |
| 140 end | |
| 141 | |
| 142 if modulemap[host][module_name] then | |
| 143 log("warn", "%s is already loaded for %s, so not loading again", module_name, host); | |
| 144 return nil, "module-already-loaded"; | |
| 145 elseif modulemap["*"][module_name] then | |
| 146 return nil, "global-module-already-loaded"; | |
| 147 end | |
| 148 | |
| 149 | |
| 150 local mod, err = pluginloader.load_code(module_name); | |
| 151 if not mod then | |
| 152 log("error", "Unable to load module '%s': %s", module_name or "nil", err or "nil"); | |
| 153 return nil, err; | |
| 154 end | |
| 155 | |
| 156 local _log = logger.init(host..":"..module_name); | |
| 157 local api_instance = setmetatable({ name = module_name, host = host, path = err, | |
| 158 _log = _log, log = function (self, ...) return _log(...); end } | |
| 159 , { __index = api }); | |
| 160 | |
| 161 local pluginenv = setmetatable({ module = api_instance }, { __index = _G }); | |
| 162 api_instance.environment = pluginenv; | |
| 163 | |
| 164 setfenv(mod, pluginenv); | |
| 165 hosts[host].modules = modulemap[host]; | |
| 166 modulemap[host][module_name] = pluginenv; | |
| 167 | |
| 168 local ok, err = pcall(mod); | |
| 169 if ok then | |
| 170 -- Call module's "load" | |
| 171 if module_has_method(pluginenv, "load") then | |
| 172 ok, err = call_module_method(pluginenv, "load"); | |
| 173 if not ok then | |
| 174 log("warn", "Error loading module '%s' on '%s': %s", module_name, host, err or "nil"); | |
| 175 end | |
| 176 end | |
| 177 | |
| 178 -- Use modified host, if the module set one | |
| 179 if api_instance.host == "*" and host ~= "*" then | |
| 180 modulemap[host][module_name] = nil; | |
| 181 modulemap["*"][module_name] = pluginenv; | |
| 182 api_instance:set_global(); | |
| 183 end | |
| 184 else | |
| 185 log("error", "Error initializing module '%s' on '%s': %s", module_name, host, err or "nil"); | |
| 186 do_unload_module(api_instance.host, module_name); -- Ignore error, module may be partially-loaded | |
| 187 end | |
| 188 return ok and mod, err; | |
| 189 end | |
| 190 | |
| 191 local function do_reload_module(host, name) | |
| 201 local mod = get_module(host, name); | 192 local mod = get_module(host, name); |
| 202 if not mod then return nil, "module-not-loaded"; end | 193 if not mod then return nil, "module-not-loaded"; end |
| 203 | 194 |
| 204 local _mod, err = pluginloader.load_code(name); -- checking for syntax errors | 195 local _mod, err = pluginloader.load_code(name); -- checking for syntax errors |
| 205 if not _mod then | 196 if not _mod then |
| 222 log("warn", "Continuing with reload (using the force)"); | 213 log("warn", "Continuing with reload (using the force)"); |
| 223 end | 214 end |
| 224 end | 215 end |
| 225 end | 216 end |
| 226 | 217 |
| 227 unload(host, name, ...); | 218 do_unload_module(host, name); |
| 228 local ok, err = load(host, name, ...); | 219 local ok, err = do_load_module(host, name); |
| 229 if ok then | 220 if ok then |
| 230 mod = get_module(host, name); | 221 mod = get_module(host, name); |
| 231 if module_has_method(mod, "restore") then | 222 if module_has_method(mod, "restore") then |
| 232 local ok, err = call_module_method(mod, "restore", saved or {}) | 223 local ok, err = call_module_method(mod, "restore", saved or {}) |
| 233 if (not ok) and err then | 224 if (not ok) and err then |
| 234 log("warn", "Error restoring module '%s' from '%s': %s", name, host, err); | 225 log("warn", "Error restoring module '%s' from '%s': %s", name, host, err); |
| 235 end | 226 end |
| 236 end | 227 end |
| 237 return true; | 228 end |
| 229 return ok and mod, err; | |
| 230 end | |
| 231 | |
| 232 --- Public API --- | |
| 233 | |
| 234 -- Load a module and fire module-loaded event | |
| 235 function load(host, name) | |
| 236 local mod, err = do_load_module(host, name); | |
| 237 if mod then | |
| 238 (hosts[mod.host] or prosody).events.fire_event("module-loaded", { module = module_name, host = host }); | |
| 239 end | |
| 240 return mod, err; | |
| 241 end | |
| 242 | |
| 243 -- Unload a module and fire module-unloaded | |
| 244 function unload(host, name) | |
| 245 local ok, err = do_unload_module(host, name); | |
| 246 if ok then | |
| 247 (hosts[host] or prosody).events.fire_event("module-unloaded", { module = name, host = host }); | |
| 238 end | 248 end |
| 239 return ok, err; | 249 return ok, err; |
| 250 end | |
| 251 | |
| 252 function reload(host, name) | |
| 253 local ok, err = do_reload_module(host, name); | |
| 254 if ok then | |
| 255 (hosts[host] or prosody).events.fire_event("module-reloaded", { module = name, host = host }); | |
| 256 elseif not is_loaded(host, name) then | |
| 257 (hosts[host] or prosody).events.fire_event("module-unloaded", { module = name, host = host }); | |
| 258 end | |
| 259 return ok, err; | |
| 260 end | |
| 261 | |
| 262 function get_module(host, name) | |
| 263 return modulemap[host] and modulemap[host][name]; | |
| 264 end | |
| 265 | |
| 266 function get_modules(host) | |
| 267 return modulemap[host]; | |
| 268 end | |
| 269 | |
| 270 function is_loaded(host, name) | |
| 271 return modulemap[host] and modulemap[host][name] and true; | |
| 240 end | 272 end |
| 241 | 273 |
| 242 function module_has_method(module, method) | 274 function module_has_method(module, method) |
| 243 return type(module.module[method]) == "function"; | 275 return type(module.module[method]) == "function"; |
| 244 end | 276 end |