Mercurial > prosody-modules
comparison mod_cache_c2s_caps/mod_cache_c2s_caps.lua @ 2899:0273d7583373
mod_cache_c2s_caps: New module caching capabilities from local clients
| author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
|---|---|
| date | Wed, 07 Mar 2018 17:11:12 +0100 |
| parents | |
| children | 0fb44258d2cf |
comparison
equal
deleted
inserted
replaced
| 2898:9fd61234b6f0 | 2899:0273d7583373 |
|---|---|
| 1 local st_iq = require "util.stanza".iq; | |
| 2 local jid_split = require "util.jid".split; | |
| 3 local uuid_gen = require "util.uuid".generate; | |
| 4 local calculate_hash = require "util.caps".calculate_hash; | |
| 5 | |
| 6 -- Map of jid..node, to avoid querying the same client multiple times for the same value. | |
| 7 local in_flight_iqs = {} | |
| 8 | |
| 9 -- Some clients (*ahem* poezio…) don’t include the @node in their result iq. | |
| 10 local iq_node_map = {} | |
| 11 | |
| 12 local function iq_result_handler(event) | |
| 13 local origin, stanza = event.origin, event.stanza; | |
| 14 local from = stanza.attr.from; | |
| 15 local id = stanza.attr.id; | |
| 16 | |
| 17 local query = stanza:get_child("query", "http://jabber.org/protocol/disco#info"); | |
| 18 | |
| 19 local node_string = query.attr.node; | |
| 20 local node_query = iq_node_map[from..id]; | |
| 21 if node_string == nil then | |
| 22 node_string = node_query; | |
| 23 query.attr.node = node_query; | |
| 24 end | |
| 25 iq_node_map[from..id] = nil; | |
| 26 in_flight_iqs[from..node_string] = nil; | |
| 27 | |
| 28 if node_string ~= node_query then | |
| 29 module:log("debug", "Wrong node for our disco#info query, expected %s, received %s", node_string, node_query); | |
| 30 return; | |
| 31 end | |
| 32 | |
| 33 local node, ver = node_query:match("([^#]+)#([^#]+)"); | |
| 34 local hash = calculate_hash(query) | |
| 35 if ver ~= hash then | |
| 36 module:log("debug", "Wrong hash for disco#info: %s ~= %s", ver, hash); | |
| 37 end | |
| 38 | |
| 39 origin.caps_cache = query; | |
| 40 module:log("info", "Stored caps %s", ver); | |
| 41 module:fire_event("c2s-capabilities-changed", { origin = origin }); | |
| 42 return true; | |
| 43 end | |
| 44 | |
| 45 local function iq_error_handler(event) | |
| 46 local origin = event.origin; | |
| 47 origin.caps_cache = nil; | |
| 48 module:fire_event("c2s-capabilities-changed", { origin = origin }); | |
| 49 end | |
| 50 | |
| 51 local function presence_stanza_handler(event) | |
| 52 local origin, stanza = event.origin, event.stanza; | |
| 53 | |
| 54 local from = stanza.attr.from; | |
| 55 if stanza.attr.to ~= nil then | |
| 56 return; | |
| 57 end | |
| 58 | |
| 59 local caps = stanza:get_child("c", "http://jabber.org/protocol/caps"); | |
| 60 if caps == nil then | |
| 61 module:log("debug", "Presence without caps received, skipping"); | |
| 62 return; | |
| 63 end | |
| 64 | |
| 65 local hash = caps.attr.hash; | |
| 66 local node = caps.attr.node; | |
| 67 local ver = caps.attr.ver; | |
| 68 if not hash or not node or not ver then | |
| 69 return; | |
| 70 end | |
| 71 if hash ~= "sha-1" then | |
| 72 module:log("warn", "Non-SHA-1 caps received: %s", hash); | |
| 73 return; | |
| 74 end | |
| 75 | |
| 76 local node_query = node.."#"..ver; | |
| 77 if (origin.caps_cache and origin.caps_cache.attr.node == node_query) or in_flight_iqs[from..node_query] ~= nil then | |
| 78 module:log("debug", "Already requested these caps, skipping"); | |
| 79 return; | |
| 80 end | |
| 81 | |
| 82 module:log("debug", "Received presence with SHA-1 caps %s, querying disco#info", node_query); | |
| 83 | |
| 84 local id = uuid_gen(); | |
| 85 iq_node_map[from..id] = node_query | |
| 86 local iq = st_iq({ type = "get", from = module.host, to = from, id = id }) | |
| 87 :tag("query", { xmlns = "http://jabber.org/protocol/disco#info", node = node_query }); | |
| 88 module:hook("iq-result/host/"..id, iq_result_handler); | |
| 89 module:hook("iq-error/host/"..id, iq_error_handler); | |
| 90 module:send(iq); | |
| 91 | |
| 92 in_flight_iqs[from..node_query] = true; | |
| 93 end | |
| 94 | |
| 95 -- Handle only non-directed presences for now. | |
| 96 module:hook("pre-presence/bare", presence_stanza_handler); |
