From a153b3c26704686bf9a3f2255d9aeb3c5f6aa2b1 Mon Sep 17 00:00:00 2001 From: Matthew Wild Date: Thu, 27 Nov 2008 03:12:12 +0000 Subject: Bumper commit for the new modulemanager API \o/ Updates all the modules, though some more changes may be in store. --- core/modulemanager.lua | 156 ++++++++++++++++++++++++++++++++----------------- core/stanza_router.lua | 10 +--- 2 files changed, 104 insertions(+), 62 deletions(-) (limited to 'core') diff --git a/core/modulemanager.lua b/core/modulemanager.lua index d313130c..704bd26f 100644 --- a/core/modulemanager.lua +++ b/core/modulemanager.lua @@ -1,5 +1,7 @@ -local log = require "util.logger".init("modulemanager") + +local logger = require "util.logger"; +local log = logger.init("modulemanager") local loadfile, pcall = loadfile, pcall; local setmetatable, setfenv, getfenv = setmetatable, setfenv, getfenv; @@ -14,80 +16,59 @@ local debug = debug; module "modulemanager" -local handler_info = {}; -local handlers = {}; - -local modulehelpers = setmetatable({}, { __index = _G }); +local api = {}; -- Module API container -local function _add_iq_handler(module, origin_type, xmlns, handler) - handlers[origin_type] = handlers[origin_type] or {}; - handlers[origin_type].iq = handlers[origin_type].iq or {}; - if not handlers[origin_type].iq[xmlns] then - handlers[origin_type].iq[xmlns]= handler; - handler_info[handler] = module; - log("debug", "mod_%s now handles tag 'iq' with query namespace '%s'", module.name, xmlns); - else - 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); - end -end +local modulemap = {}; -function modulehelpers.add_iq_handler(origin_type, xmlns, handler) - if not (origin_type and handler and xmlns) then return false; end - if type(origin_type) == "table" then - for _, origin_type in ipairs(origin_type) do - _add_iq_handler(getfenv(2).module, origin_type, xmlns, handler); - end - return; - end - _add_iq_handler(getfenv(2).module, origin_type, xmlns, handler); -end +local handler_info = {}; +local stanza_handlers = {}; -local function _add_handler(module, origin_type, tag, xmlns, handler) - handlers[origin_type] = handlers[origin_type] or {}; - if not handlers[origin_type][tag] then - handlers[origin_type][tag] = handlers[origin_type][tag] or {}; - handlers[origin_type][tag][xmlns]= handler; - handler_info[handler] = module; - log("debug", "mod_%s now handles tag '%s'", module.name, tag); - elseif handler_info[handlers[origin_type][tag]] then - 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); - end -end +local modulehelpers = setmetatable({}, { __index = _G }); -function modulehelpers.add_handler(origin_type, tag, xmlns, handler) - if not (origin_type and tag and xmlns and handler) then return false; end - if type(origin_type) == "table" then - for _, origin_type in ipairs(origin_type) do - _add_handler(getfenv(2).module, origin_type, tag, xmlns, handler); - end - return; - end - _add_handler(getfenv(2).module, origin_type, tag, xmlns, handler); -end -function load(name) - local mod, err = loadfile("plugins/mod_"..name..".lua"); +function load(host, module_name, config) + local mod, err = loadfile("plugins/mod_"..module_name..".lua"); if not mod then - log("error", "Unable to load module '%s': %s", name or "nil", err or "nil"); + log("error", "Unable to load module '%s': %s", module_name or "nil", err or "nil"); return nil, err; end - local pluginenv = setmetatable({ module = { name = name } }, { __index = modulehelpers }); + if not modulemap[host] then + modulemap[host] = {}; + stanza_handlers[host] = {}; + elseif modulemap[host][module_name] then + log("warn", "%s is already loaded for %s, so not loading again", module_name, host); + return nil, "module-already-loaded"; + end + + local _log = logger.init(host..":"..module_name); + local api_instance = setmetatable({ name = module_name, host = host, config = config, _log = _log, log = function (self, ...) return _log(...); end }, { __index = api }); + + local pluginenv = setmetatable({ module = api_instance }, { __index = _G }); setfenv(mod, pluginenv); + local success, ret = pcall(mod); if not success then log("error", "Error initialising module '%s': %s", name or "nil", ret or "nil"); return nil, ret; end + + modulemap[host][module_name] = mod; + return true; end -function handle_stanza(origin, stanza) +function handle_stanza(host, origin, stanza) local name, xmlns, origin_type = stanza.name, stanza.attr.xmlns, origin.type; + local handlers = stanza_handlers[host]; + if not handlers then + log("warn", "No handlers for %s", host); + return false; + end + if name == "iq" and xmlns == "jabber:client" and handlers[origin_type] then - log("debug", "Stanza is an "); local child = stanza.tags[1]; if child then local xmlns = child.attr.xmlns or xmlns; @@ -112,14 +93,54 @@ function handle_stanza(origin, stanza) return false; -- we didn't handle it end +----- API functions exposed to modules ----------- +-- Must all be in api.* + +-- Returns the name of the current module +function api:get_name() + return self.name; +end + +-- Returns the host that the current module is serving +function api:get_host() + return self.host; +end + + +local function _add_iq_handler(module, origin_type, xmlns, handler) + local handlers = stanza_handlers[module.host]; + handlers[origin_type] = handlers[origin_type] or {}; + handlers[origin_type].iq = handlers[origin_type].iq or {}; + if not handlers[origin_type].iq[xmlns] then + handlers[origin_type].iq[xmlns]= handler; + handler_info[handler] = module; + module:log("debug", "I now handle tag 'iq' [%s] with payload namespace '%s'", origin_type, xmlns); + else + 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); + end +end + +function api:add_iq_handler(origin_type, xmlns, handler) + if not (origin_type and handler and xmlns) then return false; end + if type(origin_type) == "table" then + for _, origin_type in ipairs(origin_type) do + _add_iq_handler(self, origin_type, xmlns, handler); + end + return; + end + _add_iq_handler(self, origin_type, xmlns, handler); +end + + do local event_handlers = {}; - function modulehelpers.add_event_hook(name, handler) + function api:add_event_hook(name, handler) if not event_handlers[name] then event_handlers[name] = {}; end t_insert(event_handlers[name] , handler); + self:log("debug", "Subscribed to %s", name); end function fire_event(name, ...) @@ -132,4 +153,31 @@ do end end + +local function _add_handler(module, origin_type, tag, xmlns, handler) + local handlers = stanza_handlers[module.host]; + handlers[origin_type] = handlers[origin_type] or {}; + if not handlers[origin_type][tag] then + handlers[origin_type][tag] = handlers[origin_type][tag] or {}; + handlers[origin_type][tag][xmlns]= handler; + handler_info[handler] = module; + module:log("debug", "I now handle tag '%s' [%s] with xmlns '%s'", tag, origin_type, xmlns); + elseif handler_info[handlers[origin_type][tag]] then + 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); + end +end + +function api:add_handler(origin_type, tag, xmlns, handler) + if not (origin_type and tag and xmlns and handler) then return false; end + if type(origin_type) == "table" then + for _, origin_type in ipairs(origin_type) do + _add_handler(self, origin_type, tag, xmlns, handler); + end + return; + end + _add_handler(self, origin_type, tag, xmlns, handler); +end + +-------------------------------------------------------------------- + return _M; diff --git a/core/stanza_router.lua b/core/stanza_router.lua index 2505fca3..308ae2f4 100644 --- a/core/stanza_router.lua +++ b/core/stanza_router.lua @@ -1,10 +1,4 @@ --- The code in this file should be self-explanatory, though the logic is horrible --- for more info on that, see doc/stanza_routing.txt, which attempts to condense --- the rules from the RFCs (mainly 3921) - -require "core.servermanager" - local log = require "util.logger".init("stanzarouter") local st = require "util.stanza"; @@ -82,7 +76,7 @@ function core_process_stanza(origin, stanza) elseif hosts[to] and hosts[to].type == "local" then -- directed at a local server core_handle_stanza(origin, stanza); elseif stanza.attr.xmlns and stanza.attr.xmlns ~= "jabber:client" and stanza.attr.xmlns ~= "jabber:server" then - modules_handle_stanza(origin, stanza); + modules_handle_stanza(host or origin.host or origin.to_host, origin, stanza); elseif hosts[to_bare] and hosts[to_bare].type == "component" then -- hack to allow components to handle node@server component_handle_stanza(origin, stanza); elseif hosts[to] and hosts[to].type == "component" then -- hack to allow components to handle node@server/resource and server/resource @@ -105,7 +99,7 @@ end -- that is, they are handled by this server function core_handle_stanza(origin, stanza) -- Handlers - if modules_handle_stanza(origin, stanza) then return; end + if modules_handle_stanza(stanza.attr.to or origin.host, origin, stanza) then return; end if origin.type == "c2s" or origin.type == "c2s_unauthed" then local session = origin; -- cgit v1.2.3