Mercurial > prosody-modules
comparison mod_pubsub_serverinfo/mod_pubsub_serverinfo.lua @ 5808:2465d5191ae9
mod_pubsub_serverinfo: Consider sibling vhosts 'connected'
Prosody does not have s2s connections between vhosts. Multiple domains will therefor not show up as each-other 'remote domains'.
With this commit, the module considers vhosts permanently s2s-connected.
Additional debug logging has been added.
| author | Guus der Kinderen <guus.der.kinderen@gmail.com> |
|---|---|
| date | Thu, 04 Jan 2024 15:14:19 +0100 |
| parents | 55b99f593c3a |
| children | a8cae8322b7c |
comparison
equal
deleted
inserted
replaced
| 5807:f08818b8b87d | 5808:2465d5191ae9 |
|---|---|
| 120 -- mapped to a collection of remote domain names. De-duplicate all remote domain names by using | 120 -- mapped to a collection of remote domain names. De-duplicate all remote domain names by using |
| 121 -- them as an index in a table. | 121 -- them as an index in a table. |
| 122 local domains_by_host = {} | 122 local domains_by_host = {} |
| 123 for session, _ in pairs(prosody.incoming_s2s) do | 123 for session, _ in pairs(prosody.incoming_s2s) do |
| 124 if session ~= nil and session.from_host ~= nil and local_domain == session.to_host then | 124 if session ~= nil and session.from_host ~= nil and local_domain == session.to_host then |
| 125 module:log("debug", "Local host '%s' has remote '%s' (inbound)", session.to_host, session.from_host); | |
| 125 local sessions = domains_by_host[session.to_host] | 126 local sessions = domains_by_host[session.to_host] |
| 126 if sessions == nil then sessions = {} end; -- instantiate a new entry if none existed | 127 if sessions == nil then sessions = {} end; -- instantiate a new entry if none existed |
| 127 sessions[session.from_host] = true | 128 sessions[session.from_host] = true |
| 128 domains_by_host[session.to_host] = sessions | 129 domains_by_host[session.to_host] = sessions |
| 129 end | 130 end |
| 130 end | 131 end |
| 131 | 132 |
| 132 -- At an earlier stage, the code iterated voer all prosody.hosts - but that turned out to be to noisy. | 133 -- At an earlier stage, the code iterated over all prosody.hosts, trying to generate one pubsub item for all local hosts. That turned out to be |
| 134 -- to noisy. Instead, this code now creates an item that includes the local vhost only. It is assumed that this module will also be loaded for | |
| 135 -- other vhosts. Their data should then be published to distinct pub/sub services and nodes. | |
| 136 | |
| 133 -- for host, data in pairs(prosody.hosts) do | 137 -- for host, data in pairs(prosody.hosts) do |
| 134 local host = local_domain | 138 local host = local_domain |
| 135 local data = prosody.hosts[host] | 139 local data = prosody.hosts[host] |
| 136 if data ~= nil then | 140 if data ~= nil then |
| 137 local sessions = domains_by_host[host] | 141 local sessions = domains_by_host[host] |
| 138 if sessions == nil then sessions = {} end; -- instantiate a new entry if none existed | 142 if sessions == nil then sessions = {} end; -- instantiate a new entry if none existed |
| 139 if data.s2sout ~= nil then | 143 if data.s2sout ~= nil then |
| 140 for _, session in pairs(data.s2sout) do | 144 for _, session in pairs(data.s2sout) do |
| 141 if session.to_host ~= nil then | 145 if session.to_host ~= nil then |
| 146 module:log("debug", "Local host '%s' has remote '%s' (outbound)", host, session.to_host); | |
| 142 sessions[session.to_host] = true | 147 sessions[session.to_host] = true |
| 143 domains_by_host[host] = sessions | 148 domains_by_host[host] = sessions |
| 144 end | 149 end |
| 150 end | |
| 151 end | |
| 152 | |
| 153 -- When the instance of Prosody hosts more than one host, the other hosts can be thought of as having a 'permanent' s2s connection. | |
| 154 for host_name, host_info in pairs(prosody.hosts) do | |
| 155 if host ~= host_name and host_info.type ~= "component" then | |
| 156 module:log("debug", "Local host '%s' has remote '%s' (vhost)", host, host_name); | |
| 157 sessions[host_name] = true; | |
| 158 domains_by_host[host] = sessions | |
| 145 end | 159 end |
| 146 end | 160 end |
| 147 end | 161 end |
| 148 | 162 |
| 149 -- Build the publication stanza. | 163 -- Build the publication stanza. |
| 194 function does_opt_in(remoteDomain) | 208 function does_opt_in(remoteDomain) |
| 195 | 209 |
| 196 -- try to read answer from cache. | 210 -- try to read answer from cache. |
| 197 local cached_value = opt_in_cache[remoteDomain] | 211 local cached_value = opt_in_cache[remoteDomain] |
| 198 if cached_value ~= nil and os.difftime(cached_value.expires, os.time()) > 0 then | 212 if cached_value ~= nil and os.difftime(cached_value.expires, os.time()) > 0 then |
| 213 module:log("debug", "Opt-in status (from cache) for '%s': %s", remoteDomain, cached_value.opt_in) | |
| 199 return cached_value.opt_in; | 214 return cached_value.opt_in; |
| 200 end | 215 end |
| 201 | 216 |
| 202 -- TODO worry about not having multiple requests in flight to the same domain.cached_value | 217 -- TODO worry about not having multiple requests in flight to the same domain.cached_value |
| 203 | 218 |
| 204 -- Cache could not provide an answer. Perform service discovery. | 219 -- Cache could not provide an answer. Perform service discovery. |
| 220 module:log("debug", "No cached opt-in status for '%s': performing disco/info to determine opt-in.", remoteDomain) | |
| 205 local discoRequest = st.iq({ type = "get", to = remoteDomain, from = actor, id = new_id() }) | 221 local discoRequest = st.iq({ type = "get", to = remoteDomain, from = actor, id = new_id() }) |
| 206 :tag("query", { xmlns = "http://jabber.org/protocol/disco#info" }) | 222 :tag("query", { xmlns = "http://jabber.org/protocol/disco#info" }) |
| 207 | 223 |
| 208 module:send_iq(discoRequest):next( | 224 module:send_iq(discoRequest):next( |
| 209 function(response) | 225 function(response) |
| 210 if response.stanza ~= nil and response.stanza.attr.type == "result" then | 226 if response.stanza ~= nil and response.stanza.attr.type == "result" then |
| 211 local query = response.stanza:get_child("query", "http://jabber.org/protocol/disco#info") | 227 local query = response.stanza:get_child("query", "http://jabber.org/protocol/disco#info") |
| 212 if query ~= nil then | 228 if query ~= nil then |
| 213 for feature in query:childtags("feature", "http://jabber.org/protocol/disco#info") do | 229 for feature in query:childtags("feature", "http://jabber.org/protocol/disco#info") do |
| 230 module:log("debug", "Disco/info feature for '%s': %s", remoteDomain, feature) | |
| 214 if feature.attr.var == 'urn:xmpp:serverinfo:0' then | 231 if feature.attr.var == 'urn:xmpp:serverinfo:0' then |
| 232 module:log("debug", "Disco/info response included opt-in for '%s'", remoteDomain) | |
| 215 opt_in_cache[remoteDomain] = { | 233 opt_in_cache[remoteDomain] = { |
| 216 opt_in = true; | 234 opt_in = true; |
| 217 expires = os.time() + cache_ttl; | 235 expires = os.time() + cache_ttl; |
| 218 } | 236 } |
| 219 return; -- prevent 'false' to be cached, down below. | 237 return; -- prevent 'false' to be cached, down below. |
| 220 end | 238 end |
| 221 end | 239 end |
| 222 end | 240 end |
| 223 end | 241 end |
| 242 module:log("debug", "Disco/info response did not include opt-in for '%s'", remoteDomain) | |
| 224 opt_in_cache[remoteDomain] = { | 243 opt_in_cache[remoteDomain] = { |
| 225 opt_in = false; | 244 opt_in = false; |
| 226 expires = os.time() + cache_ttl; | 245 expires = os.time() + cache_ttl; |
| 227 } | 246 } |
| 228 end, | 247 end, |
| 229 function(response) | 248 function(response) |
| 249 module:log("debug", "An error occurred while performing a disco/info request to determine opt-in for '%s'", remoteDomain, response) | |
| 230 opt_in_cache[remoteDomain] = { | 250 opt_in_cache[remoteDomain] = { |
| 231 opt_in = false; | 251 opt_in = false; |
| 232 expires = os.time() + cache_ttl; | 252 expires = os.time() + cache_ttl; |
| 233 } | 253 } |
| 234 end | 254 end |
