prosodyctl: check certs: Warn about certificate expiry in the near future
[prosody.git] / core / moduleapi.lua
index 65e00d419134b3c5388fa212c30c217c67cb62f5..402c79275fe0456f2004c2b7aece035329d21dcc 100644 (file)
@@ -7,17 +7,22 @@
 --
 
 local config = require "core.configmanager";
-local modulemanager = require "modulemanager"; -- This is necessary to avoid require loops
 local array = require "util.array";
 local set = require "util.set";
+local it = require "util.iterators";
 local logger = require "util.logger";
 local pluginloader = require "util.pluginloader";
 local timer = require "util.timer";
+local resolve_relative_path = require"util.paths".resolve_relative_path;
+local measure = require "core.statsmanager".measure;
+local st = require "util.stanza";
 
 local t_insert, t_remove, t_concat = table.insert, table.remove, table.concat;
 local error, setmetatable, type = error, setmetatable, type;
-local ipairs, pairs, select, unpack = ipairs, pairs, select, unpack;
+local ipairs, pairs, select = ipairs, pairs, select;
+local unpack = table.unpack or unpack; --luacheck: ignore 113
 local tonumber, tostring = tonumber, tostring;
+local require = require;
 
 local prosody = prosody;
 local hosts = prosody.hosts;
@@ -51,7 +56,7 @@ function api:set_global()
        self.host = "*";
        -- Update the logger
        local _log = logger.init("mod_"..self.name);
-       self.log = function (self, ...) return _log(...); end;
+       self.log = function (self, ...) return _log(...); end; --luacheck: ignore self
        self._log = _log;
        self.global = true;
 end
@@ -59,8 +64,8 @@ end
 function api:add_feature(xmlns)
        self:add_item("feature", xmlns);
 end
-function api:add_identity(category, type, name)
-       self:add_item("identity", {category = category, type = type, name = name});
+function api:add_identity(category, identity_type, name)
+       self:add_item("identity", {category = category, type = identity_type, name = name});
 end
 function api:add_extension(data)
        self:add_item("extension", data);
@@ -71,9 +76,9 @@ function api:has_feature(xmlns)
        end
        return false;
 end
-function api:has_identity(category, type, name)
+function api:has_identity(category, identity_type, name)
        for _, id in ipairs(self:get_host_items("identity")) do
-               if id.category == category and id.type == type and id.name == name then
+               if id.category == category and id.type == identity_type and id.name == name then
                        return true;
                end
        end
@@ -90,6 +95,7 @@ function api:hook_object_event(object, event, handler, priority)
 end
 
 function api:unhook_object_event(object, event, handler)
+       self.event_handlers:set(object, event, handler, nil);
        return object.remove_handler(event, handler);
 end
 
@@ -117,16 +123,26 @@ function api:unhook(event, handler)
        return self:unhook_object_event((hosts[self.host] or prosody).events, event, handler);
 end
 
+function api:wrap_object_event(events_object, event, handler)
+       return self:hook_object_event(assert(events_object.wrappers, "no wrappers"), event, handler);
+end
+
+function api:wrap_event(event, handler)
+       return self:wrap_object_event((hosts[self.host] or prosody).events, event, handler);
+end
+
+function api:wrap_global(event, handler)
+       return self:hook_object_event(prosody.events, event, handler);
+end
+
 function api:require(lib)
-       local f, n = pluginloader.load_code(self.name, lib..".lib.lua", self.environment);
-       if not f then
-               f, n = pluginloader.load_code(lib, lib..".lib.lua", self.environment);
-       end
+       local f, n = pluginloader.load_code_ext(self.name, lib, "lib.lua", self.environment);
        if not f then error("Failed to load plugin library '"..lib.."', error: "..n); end -- FIXME better error message
        return f();
 end
 
 function api:depends(name)
+       local modulemanager = require"core.modulemanager";
        if not self.dependencies then
                self.dependencies = {};
                self:hook("module-reloaded", function (event)
@@ -286,6 +302,20 @@ function api:get_option_inherited_set(name, ...)
        return value;
 end
 
+function api:get_option_path(name, default, parent)
+       if parent == nil then
+               parent = parent or self:get_directory();
+       elseif prosody.paths[parent] then
+               parent = prosody.paths[parent];
+       end
+       local value = self:get_option_string(name, default);
+       if value == nil then
+               return nil;
+       end
+       return resolve_relative_path(parent, value);
+end
+
+
 function api:context(host)
        return setmetatable({host=host or "*"}, {__index=self,__newindex=self});
 end
@@ -308,15 +338,16 @@ function api:remove_item(key, value)
 end
 
 function api:get_host_items(key)
+       local modulemanager = require"core.modulemanager";
        local result = modulemanager.get_items(key, self.host) or {};
        return result;
 end
 
-function api:handle_items(type, added_cb, removed_cb, existing)
-       self:hook("item-added/"..type, added_cb);
-       self:hook("item-removed/"..type, removed_cb);
+function api:handle_items(item_type, added_cb, removed_cb, existing)
+       self:hook("item-added/"..item_type, added_cb);
+       self:hook("item-removed/"..item_type, removed_cb);
        if existing ~= false then
-               for _, item in ipairs(self:get_host_items(type)) do
+               for _, item in ipairs(self:get_host_items(item_type)) do
                        added_cb({ item = item });
                end
        end
@@ -347,6 +378,14 @@ function api:send(stanza)
        return core_post_stanza(hosts[self.host], stanza);
 end
 
+function api:broadcast(jids, stanza, iter)
+       for jid in (iter or it.values)(jids) do
+               local new_stanza = st.clone(stanza);
+               new_stanza.attr.to = jid;
+               core_post_stanza(hosts[self.host], new_stanza);
+       end
+end
+
 function api:add_timer(delay, callback)
        return timer.add_task(delay, function (t)
                if self.loaded == false then return; end
@@ -360,12 +399,35 @@ function api:get_directory()
 end
 
 function api:load_resource(path, mode)
-       path = config.resolve_relative_path(self:get_directory(), path);
+       path = resolve_relative_path(self:get_directory(), path);
        return io.open(path, mode);
 end
 
-function api:open_store(name, type)
-       return storagemanager.open(self.host, name or self.name, type);
+function api:open_store(name, store_type)
+       return require"core.storagemanager".open(self.host, name or self.name, store_type);
+end
+
+function api:measure(name, stat_type)
+       return measure(stat_type, "/"..self.host.."/mod_"..self.name.."/"..name);
+end
+
+function api:measure_object_event(events_object, event_name, stat_name)
+       local m = self:measure(stat_name or event_name, "duration");
+       local function handler(handlers, _event_name, _event_data)
+               local finished = m();
+               local ret = handlers(_event_name, _event_data);
+               finished();
+               return ret;
+       end
+       return self:hook_object_event(events_object, event_name, handler);
+end
+
+function api:measure_event(event_name, stat_name)
+       return self:measure_object_event((hosts[self.host] or prosody).events.wrappers, event_name, stat_name);
+end
+
+function api:measure_global_event(event_name, stat_name)
+       return self:measure_object_event(prosody.events.wrappers, event_name, stat_name);
 end
 
 return api;