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 |