aboutsummaryrefslogtreecommitdiffstats
path: root/plugins/mod_storage_memory.lua
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/mod_storage_memory.lua')
-rw-r--r--plugins/mod_storage_memory.lua108
1 files changed, 101 insertions, 7 deletions
diff --git a/plugins/mod_storage_memory.lua b/plugins/mod_storage_memory.lua
index 745e394b..9b0024ab 100644
--- a/plugins/mod_storage_memory.lua
+++ b/plugins/mod_storage_memory.lua
@@ -4,10 +4,13 @@ local envload = require "util.envload".envload;
local st = require "util.stanza";
local is_stanza = st.is_stanza or function (s) return getmetatable(s) == st.stanza_mt end
local new_id = require "util.id".medium;
+local set = require "util.set";
local auto_purge_enabled = module:get_option_boolean("storage_memory_temporary", false);
local auto_purge_stores = module:get_option_set("storage_memory_temporary_stores", {});
+local archive_item_limit = module:get_option_number("storage_archive_item_limit", 1000);
+
local memory = setmetatable({}, {
__index = function(t, k)
local store = module:shared(k)
@@ -51,6 +54,14 @@ archive_store.__index = archive_store;
archive_store.users = _users;
+archive_store.caps = {
+ total = true;
+ quota = archive_item_limit;
+ truncate = true;
+ full_id_range = true;
+ ids = true;
+};
+
function archive_store:append(username, key, value, when, with)
if is_stanza(value) then
value = st.preserialize(value);
@@ -70,6 +81,8 @@ function archive_store:append(username, key, value, when, with)
end
if a[key] then
table.remove(a, a[key]);
+ elseif #a >= archive_item_limit then
+ return nil, "quota-limit";
end
local i = #a+1;
a[i] = v;
@@ -80,10 +93,18 @@ end
function archive_store:find(username, query)
local items = self.store[username or NULL];
if not items then
- return function () end, 0;
+ if query then
+ if query.before or query.after then
+ return nil, "item-not-found";
+ end
+ if query.total then
+ return function () end, 0;
+ end
+ end
+ return function () end;
end
- local count = #items;
- local i = 0;
+ local count = nil;
+ local i, last_key = 0;
if query then
items = array():append(items);
if query.key then
@@ -91,6 +112,12 @@ function archive_store:find(username, query)
return item.key == query.key;
end);
end
+ if query.ids then
+ local ids = set.new(query.ids);
+ items:filter(function (item)
+ return ids:contains(item.key);
+ end);
+ end
if query.with then
items:filter(function (item)
return item.with == query.with;
@@ -106,24 +133,40 @@ function archive_store:find(username, query)
return item.when <= query["end"];
end);
end
- count = #items;
+ if query.total then
+ count = #items;
+ end
if query.reverse then
items:reverse();
if query.before then
- for j = 1, count do
+ local found = false;
+ for j = 1, #items do
if (items[j].key or tostring(j)) == query.before then
+ found = true;
i = j;
break;
end
end
+ if not found then
+ return nil, "item-not-found";
+ end
end
+ last_key = query.after;
elseif query.after then
- for j = 1, count do
+ local found = false;
+ for j = 1, #items do
if (items[j].key or tostring(j)) == query.after then
+ found = true;
i = j;
break;
end
end
+ if not found then
+ return nil, "item-not-found";
+ end
+ last_key = query.before;
+ elseif query.before then
+ last_key = query.before;
end
if query.limit and #items - i > query.limit then
items[i+query.limit+1] = nil;
@@ -132,11 +175,62 @@ function archive_store:find(username, query)
return function ()
i = i + 1;
local item = items[i];
- if not item then return; end
+ if not item or (last_key and item.key == last_key) then return; end
return item.key, item.value(), item.when, item.with;
end, count;
end
+function archive_store:get(username, wanted_key)
+ local items = self.store[username or NULL];
+ if not items then return nil, "item-not-found"; end
+ local i = items[wanted_key];
+ if not i then return nil, "item-not-found"; end
+ local item = items[i];
+ return item.value(), item.when, item.with;
+end
+
+function archive_store:set(username, wanted_key, new_value, new_when, new_with)
+ local items = self.store[username or NULL];
+ if not items then return nil, "item-not-found"; end
+ local i = items[wanted_key];
+ if not i then return nil, "item-not-found"; end
+ local item = items[i];
+
+ if is_stanza(new_value) then
+ new_value = st.preserialize(new_value);
+ item.value = envload("return xml"..serialize(new_value), "=(stanza)", { xml = st.deserialize })
+ else
+ item.value = envload("return "..serialize(new_value), "=(data)", {});
+ end
+ if new_when then
+ item.when = new_when;
+ end
+ if new_with then
+ item.with = new_when;
+ end
+ return true;
+end
+
+function archive_store:summary(username, query)
+ local iter, err = self:find(username, query)
+ if not iter then return iter, err; end
+ local counts = {};
+ local earliest = {};
+ local latest = {};
+ for _, _, when, with in iter do
+ counts[with] = (counts[with] or 0) + 1;
+ if earliest[with] == nil then
+ earliest[with] = when;
+ end
+ latest[with] = when;
+ end
+ return {
+ counts = counts;
+ earliest = earliest;
+ latest = latest;
+ };
+end
+
function archive_store:delete(username, query)
if not query or next(query) == nil then