view mod_mam/fallback_archive.lib.lua @ 3656:3e0f4d727825

mod_vcard_muc: Add an alternative method of signaling avatar change When the avatar has been changed, a signal is sent that the room configuration has changed. Clients then do a disco#info query to find the SHA-1 of the new avatar. They can then fetch it as before, or not if they have it cached already. This is meant to be less disruptive than signaling via presence, which caused problems for some clients. If clients transition to the new method, the old one can eventually be removed. The namespace is made up while waiting for standardization. Otherwise it is very close to what's described in https://xmpp.org/extensions/inbox/muc-avatars.html
author Kim Alvefur <zash@zash.se>
date Sun, 25 Aug 2019 20:46:43 +0200
parents 03f6d9ed2903
children
line wrap: on
line source

-- luacheck: ignore 212/self

local uuid = require "util.uuid".generate;
local store = module:shared("archive");
local archive_store = { _provided_by = "mam"; name = "fallback"; };

function archive_store:append(username, key, value, when, with)
	local archive = store[username];
	if not archive then
		archive = { [0] = 0 };
		store[username] = archive;
	end
	local index = (archive[0] or #archive)+1;
	local item = { key = key, when = when, with = with, value = value };
	if not key or archive[key] then
		key = uuid();
		item.key = key;
	end
	archive[index] = item;
	archive[key] = index;
	archive[0] = index;
	return key;
end

function archive_store:find(username, query)
	local archive = store[username] or {};
	local start, stop, step = 1, archive[0] or #archive, 1;
	local qstart, qend, qwith = -math.huge, math.huge;
	local limit;

	if query then
		if query.reverse then
			start, stop, step = stop, start, -1;
			if query.before and archive[query.before] then
				start = archive[query.before] - 1;
			end
		elseif query.after and archive[query.after] then
			start = archive[query.after] + 1;
		end
		qwith = query.with;
		limit = query.limit;
		qstart = query.start or qstart;
		qend = query["end"] or qend;
	end

	return function ()
		if limit and limit <= 0 then return end
		for i = start, stop, step do
			local item = archive[i];
			if (not qwith or qwith == item.with) and item.when >= qstart and item.when <= qend then
				if limit then limit = limit - 1; end
				start = i + step; -- Start on next item
				return item.key, item.value, item.when, item.with;
			end
		end
	end
end

function archive_store:delete(username, query)
	if not query or next(query) == nil then
		-- no specifics, delete everything
		store[username] = nil;
		return true;
	end
	local archive = store[username];
	if not archive then return true; end -- no messages, nothing to delete

	local qstart = query.start or -math.huge;
	local qend = query["end"] or math.huge;
	local qwith = query.with;
	store[username] = nil;
	for i = 1, #archive do
		local item = archive[i];
		local when, with = item.when, item.when;
		-- Add things that don't match the query
		if not ((not qwith or qwith == item.with) and item.when >= qstart and item.when <= qend) then
			self:append(username, item.key, item.value, when, with);
		end
	end
	return true;
end

return archive_store;