aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES2
-rw-r--r--core/features.lua2
-rw-r--r--core/moduleapi.lua8
-rw-r--r--plugins/mod_bosh.lua2
-rw-r--r--plugins/mod_http_altconnect.lua52
-rw-r--r--plugins/mod_websocket.lua2
-rw-r--r--util/prosodyctl/check.lua68
7 files changed, 130 insertions, 6 deletions
diff --git a/CHANGES b/CHANGES
index 0347c597..697c9c2d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -62,6 +62,7 @@ TRUNK
- Method for retrieving integer settings from config
- It is now easy for modules to expose a Prosody shell command, by adding a shell-command item
- Modules can now implement a module.ready method which will be called after server initialization
+- module:depends() now accepts a second parameter 'soft' to enable soft dependencies
### Configuration
@@ -84,6 +85,7 @@ TRUNK
- Support for systemd socket activation in server_epoll
- mod_invites_adhoc gained a command for creating password resets
- mod_cloud_notify imported from community modules for push notification support
+- mod_http_altconnect imported from community modules, simplifying web clients
## Removed
diff --git a/core/features.lua b/core/features.lua
index d8cefe74..8e155f70 100644
--- a/core/features.lua
+++ b/core/features.lua
@@ -12,6 +12,8 @@ return {
"mod_cloud_notify";
-- mod_muc has built-in vcard support
"muc_vcard";
+ -- mod_http_altconnect bundled
+ "http_altconnect";
-- Roles, module.may and per-session authz
"permissions";
-- prosody.* namespace
diff --git a/core/moduleapi.lua b/core/moduleapi.lua
index b93536b5..50524b32 100644
--- a/core/moduleapi.lua
+++ b/core/moduleapi.lua
@@ -136,10 +136,14 @@ function api:require(lib)
return f();
end
-function api:depends(name)
+function api:depends(name, soft)
local modulemanager = require"prosody.core.modulemanager";
if self:get_option_inherited_set("modules_disabled", {}):contains(name) then
- error("Dependency on disabled module mod_"..name);
+ if not soft then
+ error("Dependency on disabled module mod_"..name);
+ end
+ self:log("debug", "Not loading disabled soft dependency mod_%s", name);
+ return nil, "disabled";
end
if not self.dependencies then
self.dependencies = {};
diff --git a/plugins/mod_bosh.lua b/plugins/mod_bosh.lua
index 091a7d81..fc2c92ae 100644
--- a/plugins/mod_bosh.lua
+++ b/plugins/mod_bosh.lua
@@ -557,6 +557,8 @@ function module.add_host(module)
["POST /"] = handle_POST;
};
});
+
+ module:depends("http_altconnect", true);
end
if require"prosody.core.modulemanager".get_modules_for_host("*"):contains(module.name) then
diff --git a/plugins/mod_http_altconnect.lua b/plugins/mod_http_altconnect.lua
new file mode 100644
index 00000000..9252433e
--- /dev/null
+++ b/plugins/mod_http_altconnect.lua
@@ -0,0 +1,52 @@
+-- mod_http_altconnect
+-- XEP-0156: Discovering Alternative XMPP Connection Methods
+
+module:depends"http";
+
+local mm = require "prosody.core.modulemanager";
+local json = require"prosody.util.json";
+local st = require"prosody.util.stanza";
+local array = require"prosody.util.array";
+
+local advertise_bosh = module:get_option_boolean("advertise_bosh", true);
+local advertise_websocket = module:get_option_boolean("advertise_websocket", true);
+
+local function get_supported()
+ local uris = array();
+ if advertise_bosh and (mm.is_loaded(module.host, "bosh") or mm.is_loaded("*", "bosh")) then
+ uris:push({ rel = "urn:xmpp:alt-connections:xbosh", href = module:http_url("bosh", "/http-bind") });
+ end
+ if advertise_websocket and (mm.is_loaded(module.host, "websocket") or mm.is_loaded("*", "websocket")) then
+ uris:push({ rel = "urn:xmpp:alt-connections:websocket", href = module:http_url("websocket", "xmpp-websocket"):gsub("^http", "ws") });
+ end
+ return uris;
+end
+
+
+local function GET_xml(event)
+ local response = event.response;
+ local xrd = st.stanza("XRD", { xmlns='http://docs.oasis-open.org/ns/xri/xrd-1.0' });
+ local uris = get_supported();
+ for _, method in ipairs(uris) do
+ xrd:tag("Link", method):up();
+ end
+ response.headers.content_type = "application/xrd+xml"
+ response.headers.access_control_allow_origin = "*";
+ return '<?xml version="1.0" encoding="UTF-8"?>' .. tostring(xrd);
+end
+
+local function GET_json(event)
+ local response = event.response;
+ local jrd = { links = get_supported() };
+ response.headers.content_type = "application/json"
+ response.headers.access_control_allow_origin = "*";
+ return json.encode(jrd);
+end;
+
+module:provides("http", {
+ default_path = "/.well-known";
+ route = {
+ ["GET /host-meta"] = GET_xml;
+ ["GET /host-meta.json"] = GET_json;
+ };
+});
diff --git a/plugins/mod_websocket.lua b/plugins/mod_websocket.lua
index 7120f3cc..dfc1a215 100644
--- a/plugins/mod_websocket.lua
+++ b/plugins/mod_websocket.lua
@@ -367,6 +367,8 @@ function module.add_host(module)
};
});
+ module:depends("http_altconnect", true);
+
module:hook("c2s-read-timeout", keepalive, -0.9);
end
diff --git a/util/prosodyctl/check.lua b/util/prosodyctl/check.lua
index a297fea5..1ea8d56d 100644
--- a/util/prosodyctl/check.lua
+++ b/util/prosodyctl/check.lua
@@ -1486,6 +1486,10 @@ local function check(arg)
muc = "groups";
};
+ local recommended_component_modules = {
+ muc = { "muc_mam" };
+ };
+
local function print_feature_status(feature, host)
if quiet then return; end
print("", feature.ok and "OK" or "(!)", feature.name);
@@ -1501,11 +1505,20 @@ local function check(arg)
table.sort(feature.lacking_components);
for _, component_module in ipairs(feature.lacking_components) do
local subdomain = common_subdomains[component_module];
+ local recommended_mods = recommended_component_modules[component_module];
if subdomain then
print("", "", "Suggested component:");
print("");
- print("", "", "", ("Component %q %q"):format(subdomain.."."..host, component_module));
print("", "", "", ("-- Documentation: https://prosody.im/doc/modules/mod_%s"):format(component_module));
+ print("", "", "", ("Component %q %q"):format(subdomain.."."..host, component_module));
+ if recommended_mods then
+ print("", "", "", " modules_enabled = {");
+ table.sort(recommended_mods);
+ for _, mod in ipairs(recommended_mods) do
+ print("", "", "", (" %q;"):format(mod));
+ end
+ print("", "", "", " }");
+ end
else
print("", "", ("Suggested component: %s"):format(component_module));
end
@@ -1514,6 +1527,30 @@ local function check(arg)
print("", "", "If you have already configured any these components, they may not be");
print("", "", "linked correctly to "..host..". For more info see https://prosody.im/doc/components");
end
+ if feature.lacking_component_modules then
+ table.sort(feature.lacking_component_modules, function (a, b)
+ return a.host < b.host;
+ end);
+ for _, problem in ipairs(feature.lacking_component_modules) do
+ local hostapi = api(problem.host);
+ local current_modules_enabled = hostapi:get_option_array("modules_enabled", {});
+ print("", "", ("Component %q is missing the following modules: %s"):format(problem.host, table.concat(problem.missing_mods)));
+ print("");
+ print("","", "Add the missing modules to your modules_enabled under the Component, like this:");
+ print("");
+ print("");
+ print("", "", "", ("-- Documentation: https://prosody.im/doc/modules/mod_%s"):format(problem.component_module));
+ print("", "", "", ("Component %q %q"):format(problem.host, problem.component_module));
+ print("", "", "", (" modules_enabled = {"));
+ for _, mod in ipairs(current_modules_enabled) do
+ print("", "", "", (" %q;"):format(mod));
+ end
+ for _, mod in ipairs(problem.missing_mods) do
+ print("", "", "", (" %q; -- Add this!"):format(mod));
+ end
+ print("", "", "", (" }"));
+ end
+ end
end
print("");
end
@@ -1572,8 +1609,27 @@ local function check(arg)
local function check_component(suggested, alternate, ...)
local found;
for _, component_module in ipairs({ suggested, alternate, ... }) do
- found = #host_components[component_module] > 0;
- if found then break; end
+ found = host_components[component_module][1];
+ if found then
+ local enabled_component_modules = api(found):get_option_inherited_set("modules_enabled");
+ local recommended_mods = recommended_component_modules[component_module];
+ local missing_mods = {};
+ for _, mod in ipairs(recommended_mods) do
+ if not enabled_component_modules:contains(mod) then
+ table.insert(missing_mods, mod);
+ end
+ end
+ if #missing_mods > 0 then
+ if not current_feature.lacking_component_modules then
+ current_feature.lacking_component_modules = {};
+ end
+ table.insert(current_feature.lacking_component_modules, {
+ host = found;
+ component_module = component_module;
+ missing_mods = missing_mods;
+ });
+ end
+ end
end
if not found then
current_feature.lacking_components = current_feature.lacking_components or {};
@@ -1664,7 +1720,11 @@ local function check(arg)
for _, feature in ipairs(features) do
current_feature = feature;
feature.check();
- feature.ok = not feature.lacking_modules and not feature.lacking_components;
+ feature.ok = (
+ not feature.lacking_modules and
+ not feature.lacking_components and
+ not feature.lacking_component_modules
+ );
-- For improved presentation, we group the (ok) and (not ok) features
if feature.ok then
print_feature_status(feature, host);