Changeset

1596:b362e6c00fd1

mod_storage_gdbm: Add archive support
author Kim Alvefur <zash@zash.se>
date Sun, 25 Jan 2015 22:18:05 +0100 (2015-01-25)
parents 1595:6288591d5edf
children 1597:dc0cf2ba0e1a
files mod_storage_gdbm/mod_storage_gdbm.lua
diffstat 1 files changed, 69 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/mod_storage_gdbm/mod_storage_gdbm.lua	Sun Jan 25 22:17:20 2015 +0100
+++ b/mod_storage_gdbm/mod_storage_gdbm.lua	Sun Jan 25 22:18:05 2015 +0100
@@ -9,10 +9,22 @@
 local gdbm = require"gdbm";
 local path = require"util.paths";
 local lfs = require"lfs";
+local uuid = require"util.uuid".generate;
 local serialization = require"util.serialization";
+local st = require"util.stanza";
 local serialize = serialization.serialize;
 local deserialize = serialization.deserialize;
 
+local function id(v) return v; end
+
+local function is_stanza(s)
+	return getmetatable(s) == st.stanza_mt;
+end
+
+local function ifelse(cond, iftrue, iffalse)
+	if cond then return iftrue; end return iffalse;
+end
+
 local base_path = path.resolve_relative_path(prosody.paths.data, module.host);
 lfs.mkdir(base_path);
 
@@ -33,8 +45,65 @@
 	return deserialize(data);
 end
 
+local archive = {};
+local archive_mt = { __index = archive, suffix = ".adb" };
+
+archive.get = keyval.get;
+archive.set = keyval.set;
+
+function archive:append(username, key, when, with, value)
+	key = key or uuid();
+	local meta = self:get(username);
+	if not meta then
+		meta = {};
+	end
+	local i = meta[key] or #meta+1;
+	local type;
+	if is_stanza(value) then
+		type, value = "stanza", st.preserialize(value);
+	end
+	meta[i] = { key = key, when = when, with = with, type = type };
+	meta[key] = i;
+	local ok, err = self:set(username, meta);
+	if not ok then return nil, err; end
+	ok, err = self:set(key, value);
+	if not ok then return nil, err; end
+	return key;
+end
+
+local deserialize = {
+	stanza = st.deserialize;
+};
+
+function archive:find(username, query)
+	local meta = self:get(username);
+	local r = query.reverse;
+	local d = r and -1 or 1;
+	local s = meta[ifelse(r, query.before, meta.after)];
+	if s then
+		s = s + d;
+	else
+		s = ifelse(r, #meta, 1)
+	end
+	local e = ifelse(r, 1, #meta);
+	return function ()
+		local item, value;
+		for i = s, e, d do
+			item = meta[i];
+			if (not query.with or item.with == query.with)
+			and (not query.start or item.when >= query.start)
+			and (not query["end"] or item.when >= query["end"]) then
+				s = i + d;
+				value = self:get(item.key);
+				return item.key, (deserialize[item.type] or id)(value), item.when, item.with;
+			end
+		end
+	end
+end
+
 local drivers = {
 	keyval = keyval_mt;
+	archive = archive_mt;
 }
 
 function open(_, store, typ)