Software / code / prosody
Comparison
core/modulemanager.lua @ 438:193f9dd64f17
Bumper commit for the new modulemanager API \o/ Updates all the modules, though some more changes may be in store.
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Thu, 27 Nov 2008 03:12:12 +0000 |
| parent | 400:068a813b6454 |
| child | 439:6608ad3a72f3 |
comparison
equal
deleted
inserted
replaced
| 437:c1a720db2157 | 438:193f9dd64f17 |
|---|---|
| 1 | 1 |
| 2 local log = require "util.logger".init("modulemanager") | 2 |
| 3 local logger = require "util.logger"; | |
| 4 local log = logger.init("modulemanager") | |
| 3 | 5 |
| 4 local loadfile, pcall = loadfile, pcall; | 6 local loadfile, pcall = loadfile, pcall; |
| 5 local setmetatable, setfenv, getfenv = setmetatable, setfenv, getfenv; | 7 local setmetatable, setfenv, getfenv = setmetatable, setfenv, getfenv; |
| 6 local pairs, ipairs = pairs, ipairs; | 8 local pairs, ipairs = pairs, ipairs; |
| 7 local t_insert = table.insert; | 9 local t_insert = table.insert; |
| 12 local _G = _G; | 14 local _G = _G; |
| 13 local debug = debug; | 15 local debug = debug; |
| 14 | 16 |
| 15 module "modulemanager" | 17 module "modulemanager" |
| 16 | 18 |
| 19 local api = {}; -- Module API container | |
| 20 | |
| 21 local modulemap = {}; | |
| 22 | |
| 17 local handler_info = {}; | 23 local handler_info = {}; |
| 18 local handlers = {}; | 24 local stanza_handlers = {}; |
| 19 | 25 |
| 20 local modulehelpers = setmetatable({}, { __index = _G }); | 26 local modulehelpers = setmetatable({}, { __index = _G }); |
| 21 | 27 |
| 22 local function _add_iq_handler(module, origin_type, xmlns, handler) | |
| 23 handlers[origin_type] = handlers[origin_type] or {}; | |
| 24 handlers[origin_type].iq = handlers[origin_type].iq or {}; | |
| 25 if not handlers[origin_type].iq[xmlns] then | |
| 26 handlers[origin_type].iq[xmlns]= handler; | |
| 27 handler_info[handler] = module; | |
| 28 log("debug", "mod_%s now handles tag 'iq' with query namespace '%s'", module.name, xmlns); | |
| 29 else | |
| 30 log("warning", "mod_%s wants to handle tag 'iq' with query namespace '%s' but mod_%s already handles that", module.name, xmlns, handler_info[handlers[origin_type].iq[xmlns]].module.name); | |
| 31 end | |
| 32 end | |
| 33 | 28 |
| 34 function modulehelpers.add_iq_handler(origin_type, xmlns, handler) | 29 function load(host, module_name, config) |
| 35 if not (origin_type and handler and xmlns) then return false; end | 30 local mod, err = loadfile("plugins/mod_"..module_name..".lua"); |
| 36 if type(origin_type) == "table" then | |
| 37 for _, origin_type in ipairs(origin_type) do | |
| 38 _add_iq_handler(getfenv(2).module, origin_type, xmlns, handler); | |
| 39 end | |
| 40 return; | |
| 41 end | |
| 42 _add_iq_handler(getfenv(2).module, origin_type, xmlns, handler); | |
| 43 end | |
| 44 | |
| 45 local function _add_handler(module, origin_type, tag, xmlns, handler) | |
| 46 handlers[origin_type] = handlers[origin_type] or {}; | |
| 47 if not handlers[origin_type][tag] then | |
| 48 handlers[origin_type][tag] = handlers[origin_type][tag] or {}; | |
| 49 handlers[origin_type][tag][xmlns]= handler; | |
| 50 handler_info[handler] = module; | |
| 51 log("debug", "mod_%s now handles tag '%s'", module.name, tag); | |
| 52 elseif handler_info[handlers[origin_type][tag]] then | |
| 53 log("warning", "mod_%s wants to handle tag '%s' but mod_%s already handles that", module.name, tag, handler_info[handlers[origin_type][tag]].module.name); | |
| 54 end | |
| 55 end | |
| 56 | |
| 57 function modulehelpers.add_handler(origin_type, tag, xmlns, handler) | |
| 58 if not (origin_type and tag and xmlns and handler) then return false; end | |
| 59 if type(origin_type) == "table" then | |
| 60 for _, origin_type in ipairs(origin_type) do | |
| 61 _add_handler(getfenv(2).module, origin_type, tag, xmlns, handler); | |
| 62 end | |
| 63 return; | |
| 64 end | |
| 65 _add_handler(getfenv(2).module, origin_type, tag, xmlns, handler); | |
| 66 end | |
| 67 | |
| 68 function load(name) | |
| 69 local mod, err = loadfile("plugins/mod_"..name..".lua"); | |
| 70 if not mod then | 31 if not mod then |
| 71 log("error", "Unable to load module '%s': %s", name or "nil", err or "nil"); | 32 log("error", "Unable to load module '%s': %s", module_name or "nil", err or "nil"); |
| 72 return nil, err; | 33 return nil, err; |
| 73 end | 34 end |
| 74 | 35 |
| 75 local pluginenv = setmetatable({ module = { name = name } }, { __index = modulehelpers }); | 36 if not modulemap[host] then |
| 37 modulemap[host] = {}; | |
| 38 stanza_handlers[host] = {}; | |
| 39 elseif modulemap[host][module_name] then | |
| 40 log("warn", "%s is already loaded for %s, so not loading again", module_name, host); | |
| 41 return nil, "module-already-loaded"; | |
| 42 end | |
| 43 | |
| 44 local _log = logger.init(host..":"..module_name); | |
| 45 local api_instance = setmetatable({ name = module_name, host = host, config = config, _log = _log, log = function (self, ...) return _log(...); end }, { __index = api }); | |
| 46 | |
| 47 local pluginenv = setmetatable({ module = api_instance }, { __index = _G }); | |
| 76 | 48 |
| 77 setfenv(mod, pluginenv); | 49 setfenv(mod, pluginenv); |
| 50 | |
| 78 local success, ret = pcall(mod); | 51 local success, ret = pcall(mod); |
| 79 if not success then | 52 if not success then |
| 80 log("error", "Error initialising module '%s': %s", name or "nil", ret or "nil"); | 53 log("error", "Error initialising module '%s': %s", name or "nil", ret or "nil"); |
| 81 return nil, ret; | 54 return nil, ret; |
| 82 end | 55 end |
| 56 | |
| 57 modulemap[host][module_name] = mod; | |
| 58 | |
| 83 return true; | 59 return true; |
| 84 end | 60 end |
| 85 | 61 |
| 86 function handle_stanza(origin, stanza) | 62 function handle_stanza(host, origin, stanza) |
| 87 local name, xmlns, origin_type = stanza.name, stanza.attr.xmlns, origin.type; | 63 local name, xmlns, origin_type = stanza.name, stanza.attr.xmlns, origin.type; |
| 88 | 64 |
| 65 local handlers = stanza_handlers[host]; | |
| 66 if not handlers then | |
| 67 log("warn", "No handlers for %s", host); | |
| 68 return false; | |
| 69 end | |
| 70 | |
| 89 if name == "iq" and xmlns == "jabber:client" and handlers[origin_type] then | 71 if name == "iq" and xmlns == "jabber:client" and handlers[origin_type] then |
| 90 log("debug", "Stanza is an <iq/>"); | |
| 91 local child = stanza.tags[1]; | 72 local child = stanza.tags[1]; |
| 92 if child then | 73 if child then |
| 93 local xmlns = child.attr.xmlns or xmlns; | 74 local xmlns = child.attr.xmlns or xmlns; |
| 94 log("debug", "Stanza of type %s from %s has xmlns: %s", name, origin_type, xmlns); | 75 log("debug", "Stanza of type %s from %s has xmlns: %s", name, origin_type, xmlns); |
| 95 local handler = handlers[origin_type][name] and handlers[origin_type][name][xmlns]; | 76 local handler = handlers[origin_type][name] and handlers[origin_type][name][xmlns]; |
| 110 end | 91 end |
| 111 log("debug", "Stanza unhandled by any modules, xmlns: %s", stanza.attr.xmlns); | 92 log("debug", "Stanza unhandled by any modules, xmlns: %s", stanza.attr.xmlns); |
| 112 return false; -- we didn't handle it | 93 return false; -- we didn't handle it |
| 113 end | 94 end |
| 114 | 95 |
| 96 ----- API functions exposed to modules ----------- | |
| 97 -- Must all be in api.* | |
| 98 | |
| 99 -- Returns the name of the current module | |
| 100 function api:get_name() | |
| 101 return self.name; | |
| 102 end | |
| 103 | |
| 104 -- Returns the host that the current module is serving | |
| 105 function api:get_host() | |
| 106 return self.host; | |
| 107 end | |
| 108 | |
| 109 | |
| 110 local function _add_iq_handler(module, origin_type, xmlns, handler) | |
| 111 local handlers = stanza_handlers[module.host]; | |
| 112 handlers[origin_type] = handlers[origin_type] or {}; | |
| 113 handlers[origin_type].iq = handlers[origin_type].iq or {}; | |
| 114 if not handlers[origin_type].iq[xmlns] then | |
| 115 handlers[origin_type].iq[xmlns]= handler; | |
| 116 handler_info[handler] = module; | |
| 117 module:log("debug", "I now handle tag 'iq' [%s] with payload namespace '%s'", origin_type, xmlns); | |
| 118 else | |
| 119 module:log("warn", "I wanted to handle tag 'iq' [%s] with payload namespace '%s' but mod_%s already handles that", origin_type, xmlns, handler_info[handlers[origin_type].iq[xmlns]].name); | |
| 120 end | |
| 121 end | |
| 122 | |
| 123 function api:add_iq_handler(origin_type, xmlns, handler) | |
| 124 if not (origin_type and handler and xmlns) then return false; end | |
| 125 if type(origin_type) == "table" then | |
| 126 for _, origin_type in ipairs(origin_type) do | |
| 127 _add_iq_handler(self, origin_type, xmlns, handler); | |
| 128 end | |
| 129 return; | |
| 130 end | |
| 131 _add_iq_handler(self, origin_type, xmlns, handler); | |
| 132 end | |
| 133 | |
| 134 | |
| 115 do | 135 do |
| 116 local event_handlers = {}; | 136 local event_handlers = {}; |
| 117 | 137 |
| 118 function modulehelpers.add_event_hook(name, handler) | 138 function api:add_event_hook(name, handler) |
| 119 if not event_handlers[name] then | 139 if not event_handlers[name] then |
| 120 event_handlers[name] = {}; | 140 event_handlers[name] = {}; |
| 121 end | 141 end |
| 122 t_insert(event_handlers[name] , handler); | 142 t_insert(event_handlers[name] , handler); |
| 143 self:log("debug", "Subscribed to %s", name); | |
| 123 end | 144 end |
| 124 | 145 |
| 125 function fire_event(name, ...) | 146 function fire_event(name, ...) |
| 126 local event_handlers = event_handlers[name]; | 147 local event_handlers = event_handlers[name]; |
| 127 if event_handlers then | 148 if event_handlers then |
| 130 end | 151 end |
| 131 end | 152 end |
| 132 end | 153 end |
| 133 end | 154 end |
| 134 | 155 |
| 156 | |
| 157 local function _add_handler(module, origin_type, tag, xmlns, handler) | |
| 158 local handlers = stanza_handlers[module.host]; | |
| 159 handlers[origin_type] = handlers[origin_type] or {}; | |
| 160 if not handlers[origin_type][tag] then | |
| 161 handlers[origin_type][tag] = handlers[origin_type][tag] or {}; | |
| 162 handlers[origin_type][tag][xmlns]= handler; | |
| 163 handler_info[handler] = module; | |
| 164 module:log("debug", "I now handle tag '%s' [%s] with xmlns '%s'", tag, origin_type, xmlns); | |
| 165 elseif handler_info[handlers[origin_type][tag]] then | |
| 166 log("warning", "I wanted to handle tag '%s' [%s] but mod_%s already handles that", tag, origin_type, handler_info[handlers[origin_type][tag]].module.name); | |
| 167 end | |
| 168 end | |
| 169 | |
| 170 function api:add_handler(origin_type, tag, xmlns, handler) | |
| 171 if not (origin_type and tag and xmlns and handler) then return false; end | |
| 172 if type(origin_type) == "table" then | |
| 173 for _, origin_type in ipairs(origin_type) do | |
| 174 _add_handler(self, origin_type, tag, xmlns, handler); | |
| 175 end | |
| 176 return; | |
| 177 end | |
| 178 _add_handler(self, origin_type, tag, xmlns, handler); | |
| 179 end | |
| 180 | |
| 181 -------------------------------------------------------------------- | |
| 182 | |
| 135 return _M; | 183 return _M; |