Software /
code /
prosody-modules
Changeset
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 | 2146:39d958f4a0c3 |
children | 2148:c472a454be61 |
files | mod_presence_cache/README.markdown mod_presence_cache/mod_presence_cache.lua |
diffstat | 2 files changed, 52 insertions(+), 81 deletions(-) [+] |
line wrap: on
line diff
--- a/mod_presence_cache/README.markdown Fri Apr 01 15:15:56 2016 +0200 +++ b/mod_presence_cache/README.markdown Fri Apr 01 15:18:56 2016 +0200 @@ -1,17 +1,13 @@ --- -summary: Cache presence incoming presence +summary: Cache presence from remote users ... Introduction ============ -This module stores presence from users contact even when they are -offline, so that the client can see who is online faster when they sign -in, and won't have to wait for remote servers to reply. - -Note that in its current form, the number of presence stanzas sent to a -client is doubled, as the client would get both the cached stanzas and -replies to presence probes. Also see [mod\_throttle\_presence]. +This module stores a timestamp of the latest presence received from +users contacts so that the client can see who is online faster when they +sign in, and won't have to wait for remote servers to reply. Configuration ============= @@ -26,16 +22,11 @@ Advanced configuration ====================== - - +The size of the cache is tuneable: -TODO -==== + presence_cache_size = 99 -- Deduplication, i.e don's send stanzas that are identical to the last - seen. -- Cache invalidation or expiry, eg if a remote server goes down or is - gone a long time. -- Sending probes at some interval to keep the cache reasonably fresh. +Compatibility +============= - +Requires 0.10 or later
--- a/mod_presence_cache/mod_presence_cache.lua Fri Apr 01 15:15:56 2016 +0200 +++ b/mod_presence_cache/mod_presence_cache.lua Fri Apr 01 15:18:56 2016 +0200 @@ -3,46 +3,53 @@ local jid_bare = require"util.jid".bare; local st = require"util.stanza"; local datetime = require"util.datetime"; +local cache = require "util.cache"; -local presence_cache = {}; -- Reload to empty +local cache_size = module:get_option_number("presence_cache_size", 100); + +local bare_cache = {}; -- [username NUL bare_jid] = { [full_jid] = timestamp, ... } + +local function on_evict(cache_key) + local bare_cache_key = cache_key:match("^%Z+%z[^/]+"); + local full_jid = cache_key:match("%z(.*)$"); + local jids = bare_cache[bare_cache_key]; + + if jids then + jids[full_jid] = nil; + end + if next(jids) == nil then + bare_cache[bare_cache_key] = nil; + end +end + +local presence_cache = cache.new(cache_size, on_evict); local function cache_hook(event) local origin, stanza = event.origin, event.stanza; local typ = stanza.attr.type; module:log("debug", "Cache hook, got %s from a %s", stanza:top_tag(), origin.type); if origin.type == "s2sin" and ( typ == nil or typ == "unavailable" ) then - local from_jid = stanza.attr.from; - local from_bare = jid_bare(from_jid); - local username = jid_split(stanza.attr.to); - if not is_contact_subscribed(username, module.host, from_bare) then - module:log("debug", "Not in their roster", origin.username); + local contact_full = stanza.attr.from; + local contact_bare = jid_bare(contact_full); + local username, host = jid_split(stanza.attr.to); + + if not is_contact_subscribed(username, host, contact_bare) then + module:log("debug", "Presence from jid not in roster"); return; end - local user_presence_cache = presence_cache[username]; - if not user_presence_cache then - user_presence_cache = {}; - presence_cache[username] = user_presence_cache; - end - - local contact_presence_cache = user_presence_cache[from_bare]; - if not contact_presence_cache then - contact_presence_cache = {}; - user_presence_cache[from_bare] = contact_presence_cache; + local cache_key = username .. "\0" .. contact_full; + local bare_cache_key = username .. "\0" .. contact_bare; + local stamp = datetime.datetime(); + local jids = bare_cache[bare_cache_key]; + if jids then + jids[contact_full] = stamp; + else + jids = { [contact_full] = stamp }; + bare_cache[bare_cache_key] = jids; end - - if typ == "unavailable" then - contact_presence_cache[from_jid] = nil; - if next(contact_presence_cache) == nil or from_jid == from_bare then - user_presence_cache[from_bare] = nil; - if next(user_presence_cache) == nil then - presence_cache[username] = nil; - end - end - else -- only cache binary state - contact_presence_cache[from_jid] = datetime.datetime(); - end + presence_cache:set(cache_key, true); end end @@ -52,46 +59,19 @@ local function answer_probe_from_cache(event) local origin, stanza = event.origin, event.stanza; if stanza.attr.type ~= "probe" then return; end + + local username = origin.username; local contact_bare = stanza.attr.to; - local user_presence_cache = presence_cache[origin.username]; - if not user_presence_cache then return; end - - local contact_presence_cache = user_presence_cache[contact_bare]; - if not contact_presence_cache then return; end + local bare_cache_key = username .. "\0" .. contact_bare; - local user_jid = stanza.attr.from; - for jid, presence in pairs(contact_presence_cache) do - module:log("debug", "Sending cached presence from %s", jid); - if presence == true then - presence = st.presence({ from = user_jid, from = jid }); - elseif type(presence) == "string" then -- a timestamp - presence = st.presence({ from = user_jid, from = jid }) - :tag("delay", { xmlns = "urn:xmpp:delay", from = module.host, stamp = presence }):up(); - end + local cached = bare_cache[bare_cache_key]; + if not cached then return end + for jid, stamp in pairs(cached) do + local presence = st.presence({ to = origin.full_jid, from = jid }) + :tag("delay", { xmlns = "urn:xmpp:delay", from = module.host, stamp = stamp }):up(); origin.send(presence); end end module:hook("pre-presence/bare", answer_probe_from_cache, 10); - -module:add_timer(3600, function (now) - local older = datetime.datetime(now - 7200); - for username, user_presence_cache in pairs(presence_cache) do - for contact, contact_presence_cache in pairs(user_presence_cache) do - for jid, presence in pairs(contact_presence_cache) do - if presence == true or (type(presence) == "string" and presence < older) then - contact_presence_cache[jid] = nil; - end - end - if next(contact_presence_cache) == nil then - user_presence_cache[contact] = nil; - end - end - if next(user_presence_cache) == nil then - presence_cache[username] = nil; - end - end - return 3600; -end); -