mod_presence_cache/mod_presence_cache.lua
changeset 1956 9d0c33ebbcc5
child 2127 d843e8f1ed78
equal deleted inserted replaced
1955:7974a24d29b6 1956: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");