comparison 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
parents bb18a1f5e9d7
children a03abb4bb6d7
comparison
equal deleted inserted replaced
3897:3a96070f4a14 3898:e9e19b9a6a55
9 local dm = require "core.storagemanager".olddm; 9 local dm = require "core.storagemanager".olddm;
10 local hmac_sha256 = require"util.hashes".hmac_sha256; 10 local hmac_sha256 = require"util.hashes".hmac_sha256;
11 local st = require"util.stanza"; 11 local st = require"util.stanza";
12 local dt = require"util.datetime"; 12 local dt = require"util.datetime";
13 local new_stream = require "util.xmppstream".new; 13 local new_stream = require "util.xmppstream".new;
14 local xml = require "util.xml";
14 local empty = {}; 15 local empty = {};
15 16
16 if not dm.append_raw then 17 if not dm.append_raw then
17 module:require"datamanager_append_raw"; 18 module:require"datamanager_append_raw";
18 end 19 end
55 end 56 end
56 if not ok then 57 if not ok then
57 return nil, err; 58 return nil, err;
58 end 59 end
59 return id; 60 return id;
61 end
62
63 function archive:get(username, id)
64 local dates = self:dates(username) or empty;
65 local day_idx, item_idx, items = self:_get_idx(username, id, dates);
66 if not day_idx then
67 return nil, "item-not-found";
68 end
69 module:log("debug", ":_get_idx(%q, %q) --> %q, %q", username, id, dates[day_idx], items[item_idx]);
70 local day = dates[day_idx];
71 local item = items[item_idx];
72 module:log("debug", "item = %q", item);
73 local filename = dm.getpath(username.."@"..day, self.host, self.store, "xml");
74 local xmlfile, ferr = io.open(filename, "r");
75 if not xmlfile then return nil, ferr; end
76 local p,err = xmlfile:seek("set", item.offset);
77 if p ~= item.offset or err ~= nil then return nil, err; end
78 local data = xmlfile:read(item.length);
79 local parsed, perr = xml.parse(data);
80 if not parsed then return nil, perr; end
81 return parsed, dt.parse(item.when), item.with;
82 end
83
84 local overwrite = module:get_option("xmlarchive_overwrite", false);
85
86 function archive:set(username, id, data, new_when, new_with)
87 if not is_stanza(data) then
88 module:log("error", "Attempt to store non-stanza object, traceback: %s", debug.traceback());
89 return nil, "unsupported-datatype";
90 end
91
92 username = username or "@";
93 data = tostring(data) .. "\n";
94
95 local dates = self:dates(username) or empty;
96 local day_idx, item_idx, items = self:_get_idx(username, id, dates);
97 if not day_idx then
98 return nil, "item-not-found";
99 end
100 local day = dates[day_idx];
101 local item = items[item_idx];
102
103 local filename = dm.getpath(username.."@"..day, self.host, self.store, "xml");
104
105 local replaced, err = dm.append_raw(username.."@"..day, self.host, self.store, "xml", data);
106 if not replaced then return nil, err; end
107 local new_offset = err;
108
109 -- default yes or no?
110 if overwrite then
111 local xmlfile, ferr = io.open(filename, "r+");
112 if not xmlfile then return nil, ferr; end
113 local p,err = xmlfile:seek("set", item.offset);
114 if p ~= item.offset or err ~= nil then return nil, err; end
115 local _,err = xmlfile:write((" "):rep(item.length));
116 if err ~= nil then return nil, err; end
117 local _,err = xmlfile:close();
118 if err ~= nil then return nil, err; end
119 end
120
121 items[item_idx] = {
122 id = id,
123 when = new_when or item.when,
124 with = new_with or item.with,
125 offset = new_offset,
126 length = #data,
127 replaces = item,
128 };
129 local ok, err = dm.list_store(username.."@"..day, self.host, self.store, items);
130 return ok, err;
60 end 131 end
61 132
62 function archive:_get_idx(username, id, dates) 133 function archive:_get_idx(username, id, dates)
63 module:log("debug", "Looking for item with id %q", id); 134 module:log("debug", "Looking for item with id %q", id);
64 dates = dates or self:dates(username) or empty; 135 dates = dates or self:dates(username) or empty;
327 function module.command(arg) 398 function module.command(arg)
328 local jid = require "util.jid"; 399 local jid = require "util.jid";
329 if arg[1] == "convert" and (arg[2] == "to" or arg[2] == "from") and arg[4] then 400 if arg[1] == "convert" and (arg[2] == "to" or arg[2] == "from") and arg[4] then
330 local convert; 401 local convert;
331 if arg[2] == "to" then 402 if arg[2] == "to" then
332 local xml = require "util.xml";
333 function convert(user, host, store) 403 function convert(user, host, store)
334 local dates, err = archive.dates({ host = host, store = store }, user); 404 local dates, err = archive.dates({ host = host, store = store }, user);
335 if not dates then assert(not err, err); return end 405 if not dates then assert(not err, err); return end
336 assert(dm.list_store(user, host, store, nil)); 406 assert(dm.list_store(user, host, store, nil));
337 for _, date in ipairs(dates) do 407 for _, date in ipairs(dates) do