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