1 local cache
= require
"util.cache";
2 local datamanager
= require
"core.storagemanager".olddm
;
3 local array
= require
"util.array";
4 local datetime
= require
"util.datetime";
5 local st
= require
"util.stanza";
6 local now
= require
"util.time".now
;
7 local id
= require
"util.id".medium
;
8 local jid_join
= require
"util.jid".join
;
10 local host
= module
.host
;
12 local archive_item_limit
= module
:get_option_number("storage_archive_item_limit", 10000);
13 local archive_item_count_cache
= cache
.new(module
:get_option("storage_archive_item_limit_cache_size", 1000));
17 function driver
:open(store
, typ
)
18 local mt
= self
[typ
or "keyval"]
20 return nil, "unsupported-store";
22 return setmetatable({ store
= store
, type = typ
}, mt
);
25 function driver
:stores(username
) -- luacheck: ignore 212/self
26 return datamanager
.stores(username
, host
);
29 function driver
:purge(user
) -- luacheck: ignore 212/self
30 return datamanager
.purge(user
, host
);
34 driver
.keyval
= { __index
= keyval
};
36 function keyval
:get(user
)
37 return datamanager
.load(user
, host
, self
.store
);
40 function keyval
:set(user
, data
)
41 return datamanager
.store(user
, host
, self
.store
, data
);
44 function keyval
:users()
45 return datamanager
.users(host
, self
.store
, self
.type);
49 driver
.archive
= { __index
= archive
};
53 quota
= archive_item_limit
;
57 function archive
:append(username
, key
, value
, when
, with
)
59 if not st
.is_stanza(value
) then
60 return nil, "unsupported-datatype";
62 value
= st
.preserialize(st
.clone(value
));
65 value
.attr
.stamp
= datetime
.datetime(when
);
66 value
.attr
.stamp_legacy
= datetime
.legacy(when
);
68 local cache_key
= jid_join(username
, host
, self
.store
);
69 local item_count
= archive_item_count_cache
:get(cache_key
);
72 local items
, err
= datamanager
.list_load(username
, host
, self
.store
);
73 if not items
and err
then return items
, err
; end
76 item_count
= items
and #items
or 0;
77 archive_item_count_cache
:set(cache_key
, item_count
);
78 if item_count
>= archive_item_limit
then
79 module
:log("debug", "%s reached or over quota, not adding to store", username
);
80 return nil, "quota-limit";
84 -- Filter out any item with the same key as the one being added
86 items
:filter(function (item
)
87 return item
.key
~= key
;
92 local ok
, err
= datamanager
.list_store(username
, host
, self
.store
, items
);
93 if not ok
then return ok
, err
; end
94 archive_item_count_cache
:set(cache_key
, #items
);
98 if not item_count
then -- Item count not cached?
99 -- We need to load the list to get the number of items currently stored
100 local items
, err
= datamanager
.list_load(username
, host
, self
.store
);
101 if not items
and err
then return items
, err
; end
102 item_count
= items
and #items
or 0;
103 archive_item_count_cache
:set(cache_key
, item_count
);
105 if item_count
>= archive_item_limit
then
106 module
:log("debug", "%s reached or over quota, not adding to store", username
);
107 return nil, "quota-limit";
112 module
:log("debug", "%s has %d items out of %d limit in store %s", username
, item_count
, archive_item_limit
, self
.store
);
116 local ok
, err
= datamanager
.list_append(username
, host
, self
.store
, value
);
117 if not ok
then return ok
, err
; end
118 archive_item_count_cache
:set(cache_key
, item_count
+1);
122 function archive
:find(username
, query
)
123 local items
, err
= datamanager
.list_load(username
, host
, self
.store
);
128 if query
.before
or query
.after
then
129 return nil, "item-not-found";
132 return function () end, 0;
135 return function () end;
140 items
= array(items
);
142 items
:filter(function (item
)
143 return item
.key
== query
.key
;
147 items
:filter(function (item
)
148 return item
.with
== query
.with
;
152 items
:filter(function (item
)
153 return item
.when
>= query
.start
;
157 items
:filter(function (item
)
158 return item
.when
<= query
["end"];
164 if query
.reverse
then
169 if (items
[j
].key
or tostring(j
)) == query
.before
then
176 return nil, "item-not-found";
179 elseif query
.after
then
182 if (items
[j
].key
or tostring(j
)) == query
.after
then
189 return nil, "item-not-found";
192 if query
.limit
and #items
- i
> query
.limit
then
193 items
[i
+query
.limit
+1] = nil;
198 local item
= items
[i
];
199 if not item
then return; end
200 local key
= item
.key
or tostring(i
);
201 local when
= item
.when
or datetime
.parse(item
.attr
.stamp
);
202 local with
= item
.with
;
203 item
.key
, item
.when
, item
.with
= nil, nil, nil;
204 item
.attr
.stamp
= nil;
205 item
.attr
.stamp_legacy
= nil;
206 item
= st
.deserialize(item
);
207 return key
, item
, when
, with
;
211 function archive
:dates(username
)
212 local items
, err
= datamanager
.list_load(username
, host
, self
.store
);
213 if not items
then return items
, err
; end
214 return array(items
):pluck("when"):map(datetime
.date):unique();
217 function archive
:summary(username
, query
)
218 local iter
, err
= self
:find(username
, query
)
219 if not iter
then return iter
, err
; end
224 for _
, stanza
, when
, with
in iter
do
225 counts
[with
] = (counts
[with
] or 0) + 1;
226 if earliest
[with
] == nil then
227 earliest
[with
] = when
;
230 body
[with
] = stanza
:get_child_text("body") or body
[with
];
240 function archive
:users()
241 return datamanager
.users(host
, self
.store
, "list");
244 function archive
:delete(username
, query
)
245 local cache_key
= jid_join(username
, host
, self
.store
);
246 if not query
or next(query
) == nil then
247 archive_item_count_cache
:set(cache_key
, nil);
248 return datamanager
.list_store(username
, host
, self
.store
, nil);
250 local items
, err
= datamanager
.list_load(username
, host
, self
.store
);
255 archive_item_count_cache
:set(cache_key
, 0);
259 items
= array(items
);
260 local count_before
= #items
;
263 items
:filter(function (item
)
264 return item
.key
~= query
.key
;
268 items
:filter(function (item
)
269 return item
.with
~= query
.with
;
273 items
:filter(function (item
)
274 return item
.when
< query
.start
;
278 items
:filter(function (item
)
279 return item
.when
> query
["end"];
282 if query
.truncate
and #items
> query
.truncate
then
283 if query
.reverse
then
284 -- Before: { 1, 2, 3, 4, 5, }
285 -- After: { 1, 2, 3 }
286 for i
= #items
, query
.truncate
+ 1, -1 do
290 -- Before: { 1, 2, 3, 4, 5, }
291 -- After: { 3, 4, 5 }
292 local offset
= #items
- query
.truncate
;
294 items
[i
] = items
[i
+offset
];
299 local count
= count_before
- #items
;
301 return 0; -- No changes, skip write
303 local ok
, err
= datamanager
.list_store(username
, host
, self
.store
, items
);
304 if not ok
then return ok
, err
; end
305 archive_item_count_cache
:set(cache_key
, #items
);
309 module
:provides("storage", driver
);