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); |