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; |