Diff

mod_storage_xmlarchive/mod_storage_xmlarchive.lua @ 3898:e9e19b9a6a55

mod_storage_xmlarchive: Add a new API similar to map-stores This can be used to replace messages with tombstones
author Kim Alvefur <zash@zash.se>
date Sat, 22 Feb 2020 21:12:29 +0100
parent 3755:bb18a1f5e9d7
child 3899:a03abb4bb6d7
line wrap: on
line diff
--- a/mod_storage_xmlarchive/mod_storage_xmlarchive.lua	Sat Feb 22 21:11:31 2020 +0100
+++ b/mod_storage_xmlarchive/mod_storage_xmlarchive.lua	Sat Feb 22 21:12:29 2020 +0100
@@ -11,6 +11,7 @@
 local st = require"util.stanza";
 local dt = require"util.datetime";
 local new_stream = require "util.xmppstream".new;
+local xml = require "util.xml";
 local empty = {};
 
 if not dm.append_raw then
@@ -59,6 +60,76 @@
 	return id;
 end
 
+function archive:get(username, id)
+	local dates = self:dates(username) or empty;
+	local day_idx, item_idx, items = self:_get_idx(username, id, dates);
+	if not day_idx then
+		return nil, "item-not-found";
+	end
+	module:log("debug", ":_get_idx(%q, %q) --> %q, %q", username, id, dates[day_idx], items[item_idx]);
+	local day = dates[day_idx];
+	local item = items[item_idx];
+	module:log("debug", "item = %q", item);
+	local filename = dm.getpath(username.."@"..day, self.host, self.store, "xml");
+	local xmlfile, ferr = io.open(filename, "r");
+	if not xmlfile then return nil, ferr; end
+	local p,err = xmlfile:seek("set", item.offset);
+	if p ~= item.offset or err ~= nil then return nil, err; end
+	local data = xmlfile:read(item.length);
+	local parsed, perr = xml.parse(data);
+	if not parsed then return nil, perr; end
+	return parsed, dt.parse(item.when), item.with;
+end
+
+local overwrite = module:get_option("xmlarchive_overwrite", false);
+
+function archive:set(username, id, data, new_when, new_with)
+	if not is_stanza(data) then
+		module:log("error", "Attempt to store non-stanza object, traceback: %s", debug.traceback());
+		return nil, "unsupported-datatype";
+	end
+
+	username = username or "@";
+	data = tostring(data) .. "\n";
+
+	local dates = self:dates(username) or empty;
+	local day_idx, item_idx, items = self:_get_idx(username, id, dates);
+	if not day_idx then
+		return nil, "item-not-found";
+	end
+	local day = dates[day_idx];
+	local item = items[item_idx];
+
+	local filename = dm.getpath(username.."@"..day, self.host, self.store, "xml");
+
+	local replaced, err = dm.append_raw(username.."@"..day, self.host, self.store, "xml", data);
+	if not replaced then return nil, err; end
+	local new_offset = err;
+
+	-- default yes or no?
+	if overwrite then
+		local xmlfile, ferr = io.open(filename, "r+");
+		if not xmlfile then return nil, ferr; end
+		local p,err = xmlfile:seek("set", item.offset);
+		if p ~= item.offset or err ~= nil then return nil, err; end
+		local _,err = xmlfile:write((" "):rep(item.length));
+		if err ~= nil then return nil, err; end
+		local _,err = xmlfile:close();
+		if err ~= nil then return nil, err; end
+	end
+
+	items[item_idx] = {
+		id = id,
+		when = new_when or item.when,
+		with = new_with or item.with,
+		offset = new_offset,
+		length = #data,
+		replaces = item,
+	};
+	local ok, err = dm.list_store(username.."@"..day, self.host, self.store, items);
+	return ok, err;
+end
+
 function archive:_get_idx(username, id, dates)
 	module:log("debug", "Looking for item with id %q", id);
 	dates = dates or self:dates(username) or empty;
@@ -329,7 +400,6 @@
 	if arg[1] == "convert" and (arg[2] == "to" or arg[2] == "from") and arg[4] then
 		local convert;
 		if arg[2] == "to" then
-			local xml = require "util.xml";
 			function convert(user, host, store)
 				local dates, err = archive.dates({ host = host, store = store }, user);
 				if not dates then assert(not err, err); return end