changeset 2155:f24b02e0d706

mod_presence_dedup: Attempt at saving bandwith by deduplicating presence stanzas
author Kim Alvefur <zash@zash.se>
date Sun, 03 Apr 2016 17:09:03 +0200
parents ada71b81425a
children 3fcac143fe0b 5e8dec076afc
files mod_presence_dedup/README.markdown mod_presence_dedup/mod_presence_dedup.lua
diffstat 2 files changed, 62 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_presence_dedup/README.markdown	Sun Apr 03 17:09:03 2016 +0200
@@ -0,0 +1,18 @@
+---
+summary: Presence deduplication module
+...
+
+This module tries to squash incoming identical presence stanzas to save
+some bandwith at the cost of increased memory use.
+
+Configuration
+=============
+
+  Option                         Type     Default
+  ------------------------------ -------- ---------
+  presence\_dedup\_cache\_size   number   `100`
+
+The only setting controls how many presence stanzas *per session* are
+kept in memory for comparing with incoming presenece.
+
+Requires Prosody 0.10 or later.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_presence_dedup/mod_presence_dedup.lua	Sun Apr 03 17:09:03 2016 +0200
@@ -0,0 +1,44 @@
+local st = require "util.stanza";
+local cache = require "util.cache";
+local add_filter = require "util.filters".add_filter;
+
+local cache_size = module:get_option_number("presence_dedup_cache_size", 100);
+
+-- stanza equality tests
+local function attr_eq(a, b)
+	if a == b then return true; end -- unlikely but not impossible
+	for k,v in pairs(a) do if b[k] ~= v then return false; end end
+	for k,v in pairs(b) do if a[k] ~= v then return false; end end
+	return true;
+end
+
+local function st_eq(a, b)
+	if a == b then return true; end
+	if type(b) ~= "table" then return false; end
+	if getmetatable(b) ~= st.stanza_mt then return false; end
+	if a.name ~= b.name then return false; end
+	if #a ~= #b then return false; end
+	if not attr_eq(a.attr, b.attr) then return false; end
+	for i = 1, #a do if not st_eq(a[i], b[i]) then return false; end end
+	return true;
+end
+
+local function dedup_presence(stanza, session)
+	if session.presence_cache and session.presence
+	and getmetatable(stanza) == st.stanza_mt and stanza.name == "presence"
+	and stanza.attr.xmlns == nil and stanza.attr.from then
+		local cached = session.presence_cache:get(stanza.attr.from);
+		if st_eq(stanza, cached) then
+			return nil;
+		else
+			session.presence_cache:set(stanza.attr.from, st.clone(stanza));
+		end
+	end
+	return stanza;
+end
+
+module:hook("presence/initial",	function (event)
+	local session, stanza = event.origin, event.stanza;
+	session.presence_cache = cache.new(cache_size);
+	add_filter(session, "stanzas/out", dedup_presence, 90);
+end);