Software / code / prosody-modules
Comparison
mod_pubsub_serverinfo/mod_pubsub_serverinfo.lua @ 5833:76b57bcfe1b2
mod_pubsub_serverinfo: Warm-up opt-in cache
By warming up the cache that contains the opt-in data, the first publication has a better chance of including domain names for remote domains that opt-in.
Without this change, those domains are named only after the _second_ publication, which can take a while. New users are likely thrown off by that.
| author | Guus der Kinderen <guus.der.kinderen@gmail.com> |
|---|---|
| date | Thu, 04 Jan 2024 16:19:55 +0100 |
| parent | 5832:a8cae8322b7c |
| child | 5835:cf5f77491323 |
comparison
equal
deleted
inserted
replaced
| 5832:a8cae8322b7c | 5833:76b57bcfe1b2 |
|---|---|
| 27 module:add_extension(dataform { | 27 module:add_extension(dataform { |
| 28 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/network/serverinfo" }, | 28 { name = "FORM_TYPE", type = "hidden", value = "http://jabber.org/network/serverinfo" }, |
| 29 { name = "serverinfo-pubsub-node", type = "text-single" }, | 29 { name = "serverinfo-pubsub-node", type = "text-single" }, |
| 30 }:form({ ["serverinfo-pubsub-node"] = ("xmpp:%s?;node=%s"):format(service, node) }, "result")); | 30 }:form({ ["serverinfo-pubsub-node"] = ("xmpp:%s?;node=%s"):format(service, node) }, "result")); |
| 31 | 31 |
| 32 cache_warm_up() | |
| 32 module:add_timer(10, publish_serverinfo); | 33 module:add_timer(10, publish_serverinfo); |
| 33 end | 34 end |
| 34 | 35 |
| 35 function module.unload() | 36 function module.unload() |
| 36 -- This removes all subscribers, which may or may not be desirable, depending on the reason for the unload. | 37 -- This removes all subscribers, which may or may not be desirable, depending on the reason for the unload. |
| 37 delete_node(); -- Should this block, to delay unload() until the node is deleted? | 38 delete_node(); -- Should this block, to delay unload() until the node is deleted? |
| 38 end | 39 end |
| 39 | 40 |
| 40 -- Returns a promise of a boolean | 41 -- Returns a promise of a boolean |
| 41 function discover_node() | 42 function discover_node() |
| 42 local request = st.iq({ type = "get", to = service, from = actor, id = new_id() }) | 43 local request = st.iq({ type = "get", to = service, from = actor, id = new_id() }) |
| 43 :tag("query", { xmlns = "http://jabber.org/protocol/disco#items" }) | 44 :tag("query", { xmlns = "http://jabber.org/protocol/disco#items" }) |
| 44 | 45 |
| 45 module:log("debug", "Sending request to discover existence of pub/sub node '%s' at %s", node, service) | 46 module:log("debug", "Sending request to discover existence of pub/sub node '%s' at %s", node, service) |
| 46 return module:send_iq(request):next( | 47 return module:send_iq(request):next( |
| 47 function(response) | 48 function(response) |
| 48 if response.stanza == nil or response.stanza.attr.type ~= "result" then | 49 if response.stanza == nil or response.stanza.attr.type ~= "result" then |
| 113 end | 114 end |
| 114 end | 115 end |
| 115 ) | 116 ) |
| 116 end | 117 end |
| 117 | 118 |
| 118 function publish_serverinfo() | 119 function get_remote_domain_names() |
| 119 -- Iterate over s2s sessions, adding them to a multimap, where the key is the local domain name, | 120 -- Iterate over s2s sessions, adding them to a multimap, where the key is the local domain name, |
| 120 -- mapped to a collection of remote domain names. De-duplicate all remote domain names by using | 121 -- mapped to a collection of remote domain names. De-duplicate all remote domain names by using |
| 121 -- them as an index in a table. | 122 -- them as an index in a table. |
| 122 local domains_by_host = {} | 123 local domains_by_host = {} |
| 123 for session, _ in pairs(prosody.incoming_s2s) do | 124 for session, _ in pairs(prosody.incoming_s2s) do |
| 158 domains_by_host[host] = sessions | 159 domains_by_host[host] = sessions |
| 159 end | 160 end |
| 160 end | 161 end |
| 161 end | 162 end |
| 162 | 163 |
| 164 return domains_by_host | |
| 165 end | |
| 166 | |
| 167 function publish_serverinfo() | |
| 168 local domains_by_host = get_remote_domain_names() | |
| 169 | |
| 163 -- Build the publication stanza. | 170 -- Build the publication stanza. |
| 164 local request = st.iq({ type = "set", to = service, from = actor, id = new_id() }) | 171 local request = st.iq({ type = "set", to = service, from = actor, id = new_id() }) |
| 165 :tag("pubsub", { xmlns = "http://jabber.org/protocol/pubsub" }) | 172 :tag("pubsub", { xmlns = "http://jabber.org/protocol/pubsub" }) |
| 166 :tag("publish", { node = node, xmlns = "http://jabber.org/protocol/pubsub" }) | 173 :tag("publish", { node = node, xmlns = "http://jabber.org/protocol/pubsub" }) |
| 167 :tag("item", { id = "current", xmlns = "http://jabber.org/protocol/pubsub" }) | 174 :tag("item", { id = "current", xmlns = "http://jabber.org/protocol/pubsub" }) |
| 168 :tag("serverinfo", { xmlns = "urn:xmpp:serverinfo:0" }) | 175 :tag("serverinfo", { xmlns = "urn:xmpp:serverinfo:0" }) |
| 169 | 176 |
| 170 request:tag("domain", { name = local_domain }) | 177 request:tag("domain", { name = local_domain }) |
| 171 :tag("federation") | 178 :tag("federation") |
| 172 | 179 |
| 173 local remotes = domains_by_host[host] | 180 local remotes = domains_by_host[local_domain] |
| 174 | 181 |
| 175 if remotes ~= nil then | 182 if remotes ~= nil then |
| 176 for remote, _ in pairs(remotes) do | 183 for remote, _ in pairs(remotes) do |
| 177 -- include a domain name for remote domains, but only if they advertise support. | 184 -- include a domain name for remote domains, but only if they advertise support. |
| 178 if does_opt_in(remote) then | 185 if does_opt_in(remote) then |
| 203 return publication_interval; | 210 return publication_interval; |
| 204 end | 211 end |
| 205 | 212 |
| 206 local opt_in_cache = {} | 213 local opt_in_cache = {} |
| 207 | 214 |
| 215 function cache_warm_up() | |
| 216 module:log("debug", "Warming up opt-in cache") | |
| 217 local domains_by_host = get_remote_domain_names() | |
| 218 local remotes = domains_by_host[local_domain] | |
| 219 if remotes ~= nil then | |
| 220 for remote, _ in pairs(remotes) do | |
| 221 does_opt_in(remote) | |
| 222 end | |
| 223 end | |
| 224 end | |
| 225 | |
| 208 function does_opt_in(remoteDomain) | 226 function does_opt_in(remoteDomain) |
| 209 | 227 |
| 210 -- try to read answer from cache. | 228 -- try to read answer from cache. |
| 211 local cached_value = opt_in_cache[remoteDomain] | 229 local cached_value = opt_in_cache[remoteDomain] |
| 212 if cached_value ~= nil and os.difftime(cached_value.expires, os.time()) > 0 then | 230 if cached_value ~= nil and os.difftime(cached_value.expires, os.time()) > 0 then |
| 216 | 234 |
| 217 -- TODO worry about not having multiple requests in flight to the same domain.cached_value | 235 -- TODO worry about not having multiple requests in flight to the same domain.cached_value |
| 218 | 236 |
| 219 -- Cache could not provide an answer. Perform service discovery. | 237 -- 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) | 238 module:log("debug", "No cached opt-in status for '%s': performing disco/info to determine opt-in.", remoteDomain) |
| 221 local discoRequest = st.iq({ type = "get", to = remoteDomain, from = actor, id = new_id() }) | 239 local discoRequest = st.iq({ type = "get", to = remoteDomain, from = actor, id = new_id() }) |
| 222 :tag("query", { xmlns = "http://jabber.org/protocol/disco#info" }) | 240 :tag("query", { xmlns = "http://jabber.org/protocol/disco#info" }) |
| 223 | 241 |
| 224 module:send_iq(discoRequest):next( | 242 module:send_iq(discoRequest):next( |
| 225 function(response) | 243 function(response) |
| 226 if response.stanza ~= nil and response.stanza.attr.type == "result" then | 244 if response.stanza ~= nil and response.stanza.attr.type == "result" then |
| 227 local query = response.stanza:get_child("query", "http://jabber.org/protocol/disco#info") | 245 local query = response.stanza:get_child("query", "http://jabber.org/protocol/disco#info") |