mod_smacks: Switch storage for tracking resumption tokens
authorKim Alvefur <zash@zash.se>
Thu, 02 Dec 2021 14:41:19 +0100
changeset 12057 03e9587fbfd2
parent 12056 d17b8fcf11c7
child 12058 0116fa57f05c
mod_smacks: Switch storage for tracking resumption tokens All that was a complicated way to limit the number of resumable sessions. Let's control resource usage some other way. This leaves the essence of mapping resumption tokens to live sessions. This keeps resumption state across reloads.
plugins/mod_smacks.lua
--- a/plugins/mod_smacks.lua	Wed Dec 01 20:13:08 2021 +0100
+++ b/plugins/mod_smacks.lua	Thu Dec 02 14:41:19 2021 +0100
@@ -18,7 +18,6 @@
 local os_time = os.time;
 local t_remove = table.remove;
 
-local cache = require "util.cache";
 local datetime = require "util.datetime";
 local add_filter = require "util.filters".add_filter;
 local jid = require "util.jid";
@@ -44,47 +43,13 @@
 local max_unacked_stanzas = module:get_option_number("smacks_max_unacked_stanzas", 0);
 local max_inactive_unacked_stanzas = module:get_option_number("smacks_max_inactive_unacked_stanzas", 256);
 local delayed_ack_timeout = module:get_option_number("smacks_max_ack_delay", 30);
-local max_hibernated_sessions = module:get_option_number("smacks_max_hibernated_sessions", 10);
-
-assert(max_hibernated_sessions > 0, "smacks_max_hibernated_sessions must be greater than 0");
 
 local c2s_sessions = module:shared("/*/c2s/sessions");
 
 local function format_h(h) if h then return string.format("%d", h) end end
 
-local function init_session_cache(max_entries, evict_callback)
-	-- use per user limited cache for prosody >= 0.10
-	local stores = {};
-	return {
-			get = function(user, key)
-				if not user then return nil; end
-				if not key then return nil; end
-				if not stores[user] then
-					stores[user] = cache.new(max_entries, evict_callback);
-				end
-				return stores[user]:get(key);
-			end;
-			set = function(user, key, value)
-				if not user then return nil; end
-				if not key then return nil; end
-				if not stores[user] then stores[user] = cache.new(max_entries, evict_callback); end
-				stores[user]:set(key, value);
-				-- remove empty caches completely
-				if stores[user]:count() == 0 then stores[user] = nil; end
-			end;
-		};
-end
 local old_session_registry = module:open_store("smacks_h", "map");
-local session_registry = init_session_cache(max_hibernated_sessions, function(resumption_token, session)
-	if session.destroyed then return true; end -- destroyed session can always be removed from cache
-	session.log("warn", "User has too much hibernated sessions, removing oldest session (token: %s)", resumption_token);
-	-- store old session's h values on force delete
-	-- save only actual h value and username/host (for security)
-	old_session_registry:set(session.username, resumption_token, {
-		h = session.handled_stanza_count,
-	});
-	return true; -- allow session to be removed from full cache to make room for new one
-end);
+local session_registry = module:shared "/*/smacks/resumption-tokens"; -- > user@host/resumption-token --> resource
 
 local function ack_delayed(session, stanza)
 	-- fire event only if configured to do so and our session is not already hibernated or destroyed
@@ -245,7 +210,7 @@
 module:hook("pre-session-close", function(event)
 	local session = event.session;
 	if session.resumption_token then
-		session_registry.set(session.username, session.resumption_token, nil);
+		session_registry[jid.join(session.username, session.host, session.resumption_token)] = nil;
 		old_session_registry:set(session.username, session.resumption_token, nil);
 		session.resumption_token = nil;
 	end
@@ -290,7 +255,7 @@
 	local resume = stanza.attr.resume;
 	if resume == "true" or resume == "1" then
 		resume_token = uuid_generate();
-		session_registry.set(session.username, resume_token, session);
+		session_registry[jid.join(session.username, session.host, resume_token)] = session;
 		session.resumption_token = resume_token;
 	end
 	(session.sends2s or session.send)(st.stanza("enabled", { xmlns = xmlns_sm, id = resume_token, resume = resume, max = tostring(resume_timeout) }));
@@ -489,7 +454,7 @@
 						return resume_timeout-(current_time-timeout_start); -- time left to wait
 					end
 					session.log("debug", "Destroying session for hibernating too long");
-					session_registry.set(session.username, session.resumption_token, nil);
+					session_registry[jid.join(session.username, session.host, session.resumption_token)] = nil;
 					-- save only actual h value and username/host (for security)
 					old_session_registry:set(session.username, session.resumption_token, {
 						h = session.handled_stanza_count,
@@ -541,7 +506,7 @@
 	end
 
 	local id = stanza.attr.previd;
-	local original_session = session_registry.get(session.username, id);
+	local original_session = session_registry[jid.join(session.username, session.host, id)];
 	if not original_session then
 		session.log("debug", "Tried to resume non-existent session with id %s", id);
 		local old_session = old_session_registry:get(session.username, id);