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 |
