Mercurial > prosody-modules
comparison mod_presence_cache/mod_presence_cache.lua @ 2147:ed2bb50d4f91
mod_presence_cache: Switch to using util.cache for limiting size of cache
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Fri, 01 Apr 2016 15:18:56 +0200 |
parents | 39d958f4a0c3 |
children | bb4a2e4b7ba7 |
comparison
equal
deleted
inserted
replaced
2146:39d958f4a0c3 | 2147:ed2bb50d4f91 |
---|---|
1 local is_contact_subscribed = require"core.rostermanager".is_contact_subscribed; | 1 local is_contact_subscribed = require"core.rostermanager".is_contact_subscribed; |
2 local jid_split = require"util.jid".split; | 2 local jid_split = require"util.jid".split; |
3 local jid_bare = require"util.jid".bare; | 3 local jid_bare = require"util.jid".bare; |
4 local st = require"util.stanza"; | 4 local st = require"util.stanza"; |
5 local datetime = require"util.datetime"; | 5 local datetime = require"util.datetime"; |
6 local cache = require "util.cache"; | |
6 | 7 |
7 local presence_cache = {}; -- Reload to empty | 8 local cache_size = module:get_option_number("presence_cache_size", 100); |
9 | |
10 local bare_cache = {}; -- [username NUL bare_jid] = { [full_jid] = timestamp, ... } | |
11 | |
12 local function on_evict(cache_key) | |
13 local bare_cache_key = cache_key:match("^%Z+%z[^/]+"); | |
14 local full_jid = cache_key:match("%z(.*)$"); | |
15 local jids = bare_cache[bare_cache_key]; | |
16 | |
17 if jids then | |
18 jids[full_jid] = nil; | |
19 end | |
20 if next(jids) == nil then | |
21 bare_cache[bare_cache_key] = nil; | |
22 end | |
23 end | |
24 | |
25 local presence_cache = cache.new(cache_size, on_evict); | |
8 | 26 |
9 local function cache_hook(event) | 27 local function cache_hook(event) |
10 local origin, stanza = event.origin, event.stanza; | 28 local origin, stanza = event.origin, event.stanza; |
11 local typ = stanza.attr.type; | 29 local typ = stanza.attr.type; |
12 module:log("debug", "Cache hook, got %s from a %s", stanza:top_tag(), origin.type); | 30 module:log("debug", "Cache hook, got %s from a %s", stanza:top_tag(), origin.type); |
13 if origin.type == "s2sin" and ( typ == nil or typ == "unavailable" ) then | 31 if origin.type == "s2sin" and ( typ == nil or typ == "unavailable" ) then |
14 local from_jid = stanza.attr.from; | |
15 local from_bare = jid_bare(from_jid); | |
16 local username = jid_split(stanza.attr.to); | |
17 | 32 |
18 if not is_contact_subscribed(username, module.host, from_bare) then | 33 local contact_full = stanza.attr.from; |
19 module:log("debug", "Not in their roster", origin.username); | 34 local contact_bare = jid_bare(contact_full); |
35 local username, host = jid_split(stanza.attr.to); | |
36 | |
37 if not is_contact_subscribed(username, host, contact_bare) then | |
38 module:log("debug", "Presence from jid not in roster"); | |
20 return; | 39 return; |
21 end | 40 end |
22 | 41 |
23 local user_presence_cache = presence_cache[username]; | 42 local cache_key = username .. "\0" .. contact_full; |
24 if not user_presence_cache then | 43 local bare_cache_key = username .. "\0" .. contact_bare; |
25 user_presence_cache = {}; | 44 local stamp = datetime.datetime(); |
26 presence_cache[username] = user_presence_cache; | 45 local jids = bare_cache[bare_cache_key]; |
46 if jids then | |
47 jids[contact_full] = stamp; | |
48 else | |
49 jids = { [contact_full] = stamp }; | |
50 bare_cache[bare_cache_key] = jids; | |
27 end | 51 end |
28 | 52 presence_cache:set(cache_key, true); |
29 local contact_presence_cache = user_presence_cache[from_bare]; | |
30 if not contact_presence_cache then | |
31 contact_presence_cache = {}; | |
32 user_presence_cache[from_bare] = contact_presence_cache; | |
33 end | |
34 | |
35 if typ == "unavailable" then | |
36 contact_presence_cache[from_jid] = nil; | |
37 if next(contact_presence_cache) == nil or from_jid == from_bare then | |
38 user_presence_cache[from_bare] = nil; | |
39 if next(user_presence_cache) == nil then | |
40 presence_cache[username] = nil; | |
41 end | |
42 end | |
43 else -- only cache binary state | |
44 contact_presence_cache[from_jid] = datetime.datetime(); | |
45 end | |
46 end | 53 end |
47 end | 54 end |
48 | 55 |
49 module:hook("presence/bare", cache_hook, 10); | 56 module:hook("presence/bare", cache_hook, 10); |
50 -- module:hook("presence/full", cache_hook, 10); | 57 -- module:hook("presence/full", cache_hook, 10); |
51 | 58 |
52 local function answer_probe_from_cache(event) | 59 local function answer_probe_from_cache(event) |
53 local origin, stanza = event.origin, event.stanza; | 60 local origin, stanza = event.origin, event.stanza; |
54 if stanza.attr.type ~= "probe" then return; end | 61 if stanza.attr.type ~= "probe" then return; end |
62 | |
63 local username = origin.username; | |
55 local contact_bare = stanza.attr.to; | 64 local contact_bare = stanza.attr.to; |
56 | 65 |
57 local user_presence_cache = presence_cache[origin.username]; | 66 local bare_cache_key = username .. "\0" .. contact_bare; |
58 if not user_presence_cache then return; end | |
59 | 67 |
60 local contact_presence_cache = user_presence_cache[contact_bare]; | 68 local cached = bare_cache[bare_cache_key]; |
61 if not contact_presence_cache then return; end | 69 if not cached then return end |
62 | 70 for jid, stamp in pairs(cached) do |
63 local user_jid = stanza.attr.from; | 71 local presence = st.presence({ to = origin.full_jid, from = jid }) |
64 for jid, presence in pairs(contact_presence_cache) do | 72 :tag("delay", { xmlns = "urn:xmpp:delay", from = module.host, stamp = stamp }):up(); |
65 module:log("debug", "Sending cached presence from %s", jid); | |
66 if presence == true then | |
67 presence = st.presence({ from = user_jid, from = jid }); | |
68 elseif type(presence) == "string" then -- a timestamp | |
69 presence = st.presence({ from = user_jid, from = jid }) | |
70 :tag("delay", { xmlns = "urn:xmpp:delay", from = module.host, stamp = presence }):up(); | |
71 end | |
72 origin.send(presence); | 73 origin.send(presence); |
73 end | 74 end |
74 end | 75 end |
75 | 76 |
76 module:hook("pre-presence/bare", answer_probe_from_cache, 10); | 77 module:hook("pre-presence/bare", answer_probe_from_cache, 10); |
77 | |
78 module:add_timer(3600, function (now) | |
79 local older = datetime.datetime(now - 7200); | |
80 for username, user_presence_cache in pairs(presence_cache) do | |
81 for contact, contact_presence_cache in pairs(user_presence_cache) do | |
82 for jid, presence in pairs(contact_presence_cache) do | |
83 if presence == true or (type(presence) == "string" and presence < older) then | |
84 contact_presence_cache[jid] = nil; | |
85 end | |
86 end | |
87 if next(contact_presence_cache) == nil then | |
88 user_presence_cache[contact] = nil; | |
89 end | |
90 end | |
91 if next(user_presence_cache) == nil then | |
92 presence_cache[username] = nil; | |
93 end | |
94 end | |
95 return 3600; | |
96 end); | |
97 |