core/modulemanager.lua

changeset 438
193f9dd64f17
parent 400
068a813b6454
child 439
6608ad3a72f3
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;

mercurial