Mercurial > prosody-modules
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 |
