diff options
-rw-r--r-- | CHANGES | 2 | ||||
-rw-r--r-- | core/features.lua | 2 | ||||
-rw-r--r-- | core/moduleapi.lua | 8 | ||||
-rw-r--r-- | plugins/mod_bosh.lua | 2 | ||||
-rw-r--r-- | plugins/mod_http_altconnect.lua | 52 | ||||
-rw-r--r-- | plugins/mod_websocket.lua | 2 | ||||
-rw-r--r-- | util/prosodyctl/check.lua | 68 |
7 files changed, 130 insertions, 6 deletions
@@ -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); |