Comparison

mod_presence_cache/mod_presence_cache.lua @ 1952:9d0c33ebbcc5

mod_presence_cache: Cache incoming presence broadcasts in order to get clients up to speed with who is online faster
author Kim Alvefur <zash@zash.se>
date Mon, 16 Nov 2015 18:19:25 +0100
child 2123:d843e8f1ed78
comparison
equal deleted inserted replaced
1951:7974a24d29b6 1952:9d0c33ebbcc5
1 local is_contact_subscribed = require"core.rostermanager".is_contact_subscribed;
2 local jid_split = require"util.jid".split;
3 local jid_bare = require"util.jid".bare;
4 local st = require"util.stanza";
5 local datetime = require"util.datetime";
6
7 local presence_cache = {}; -- Reload to empty
8
9 local cache_full = module:get_option_boolean(module.name.."_full", false);
10
11 local function cache_hook(event)
12 local origin, stanza = event.origin, event.stanza;
13 local typ = stanza.attr.type;
14 module:log("debug", "Cache hook, got %s from a %s", stanza:top_tag(), origin.type);
15 if origin.type:match"^s2s" and ( typ == nil or typ == "unavailable" ) then
16 local from_jid = stanza.attr.from;
17 local from_bare = jid_bare(from_jid);
18 local username = jid_split(stanza.attr.to);
19
20 if not is_contact_subscribed(username, module.host, from_bare) then
21 module:log("debug", "Not in their roster", origin.username);
22 return;
23 end
24
25 local user_presence_cache = presence_cache[username];
26 if not user_presence_cache then
27 user_presence_cache = {};
28 presence_cache[username] = user_presence_cache;
29 end
30
31 local contact_presence_cache = user_presence_cache[from_bare];
32 if not contact_presence_cache then
33 contact_presence_cache = {};
34 user_presence_cache[from_bare] = contact_presence_cache;
35 end
36
37 if typ == "unavailable" then
38 contact_presence_cache[from_jid] = nil;
39 if next(contact_presence_cache) == nil or from_jid == from_bare then
40 user_presence_cache[from_bare] = nil;
41 if next(user_presence_cache) == nil then
42 presence_cache[username] = nil;
43 end
44 end
45 elseif cache_full then
46 stanza = st.clone(stanza);
47 stanza:tag("delay", { xmlns = "urn:xmpp:delay", from = module.host, stamp = datetime.datetime() }):up();
48 contact_presence_cache[from_jid] = stanza;
49 else -- only cache binary state
50 contact_presence_cache[from_jid] = datetime.datetime();
51 end
52 end
53 end
54
55 module:hook("presence/bare", cache_hook, 10);
56 -- module:hook("presence/full", cache_hook, 10);
57
58 local function answer_probe_from_cache(event)
59 local origin, stanza = event.origin, event.stanza;
60 if stanza.attr.type ~= "probe" then return; end
61 local contact_bare = stanza.attr.to;
62
63 local user_presence_cache = presence_cache[origin.username];
64 if not user_presence_cache then return; end
65
66 local contact_presence_cache = user_presence_cache[contact_bare];
67 if not contact_presence_cache then return; end
68
69 local user_jid = stanza.attr.from;
70 for jid, presence in pairs(contact_presence_cache) do
71 module:log("debug", "Sending cached presence from %s", jid);
72 if presence == true then
73 presence = st.presence({ from = user_jid, from = jid });
74 elseif type(presence) == "string" then -- a timestamp
75 presence = st.presence({ from = user_jid, from = jid })
76 :tag("delay", { xmlns = "urn:xmpp:delay", from = module.host, stamp = presence }):up();
77 end
78 origin.send(presence);
79 end
80 if cache_full then
81 return true;
82 end
83 end
84
85 module:hook("pre-presence/bare", answer_probe_from_cache, 10);
86
87 module:add_timer(3600, function (now)
88 local older = datetime.datetime(now - 7200);
89 for username, user_presence_cache in pairs(presence_cache) do
90 for contact, contact_presence_cache in pairs(user_presence_cache) do
91 for jid, presence in pairs(contact_presence_cache) do
92 if presence == true or (type(presence) == "string" and presence < older) then
93 contact_presence_cache[jid] = nil;
94 end
95 end
96 if next(contact_presence_cache) == nil then
97 user_presence_cache[contact] = nil;
98 end
99 end
100 if next(user_presence_cache) == nil then
101 presence_cache[username] = nil;
102 end
103 end
104 return 3600;
105 end);
106
107 module:log("info", "Loaded");