Mercurial > prosody-modules
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 |
| parents | |
| children | 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"); |
