Comparison

mod_archive/mod_archive.lua @ 193:18a0e5c0bb62

mod_archive: Archive Management - Retrieving a List of Collections
author shinysky<shinysky1986(AT)gmail.com>
date Mon, 05 Jul 2010 14:27:39 +0800
parent 188:5e8ea3733dc6
child 195:4d9ed6374a1f
comparison
equal deleted inserted replaced
192:12d6316d9eab 193:18a0e5c0bb62
6 -- 6 --
7 7
8 local st = require "util.stanza"; 8 local st = require "util.stanza";
9 local dm = require "util.datamanager"; 9 local dm = require "util.datamanager";
10 local jid = require "util.jid"; 10 local jid = require "util.jid";
11 local datetime = require "util.datetime";
11 12
12 local PREFS_DIR = "archive_prefs"; 13 local PREFS_DIR = "archive_prefs";
13 local ARCHIVE_DIR = "archive"; 14 local ARCHIVE_DIR = "archive";
14 15
15 module:add_feature("urn:xmpp:archive"); 16 module:add_feature("urn:xmpp:archive");
25 return st.deserialize(dm.load(node, host, PREFS_DIR)); 26 return st.deserialize(dm.load(node, host, PREFS_DIR));
26 end 27 end
27 28
28 local function store_prefs(data, node, host) 29 local function store_prefs(data, node, host)
29 dm.store(node, host, PREFS_DIR, st.preserialize(data)); 30 dm.store(node, host, PREFS_DIR, st.preserialize(data));
31 end
32
33 local function os_time()
34 -- return tostring(os.time(os.date('!*t')));
35 return datetime.datetime();
36 end
37
38 local function date_parse(s)
39 local year, month, day, hour, min, sec = s:match("(....)-?(..)-?(..)T(..):(..):(..)Z");
40 return os.time({year=year, month=month, day=day, hour=hour, min=min, sec=sec});
30 end 41 end
31 42
32 local function store_msg(msg, node, host, isfrom) 43 local function store_msg(msg, node, host, isfrom)
33 local body = msg:child_with_name("body"); 44 local body = msg:child_with_name("body");
34 local thread = msg:child_with_name("thread"); 45 local thread = msg:child_with_name("thread");
35 local data = dm.list_load(node, host, ARCHIVE_DIR); 46 local data = dm.list_load(node, host, ARCHIVE_DIR);
36 local tag = (isfrom and "from") or "to"; 47 local tag = (isfrom and "from") or "to";
37 if data then 48 if data then
38 for k, v in ipairs(data) do 49 for k, v in ipairs(data) do
39 -- <chat with='juliet@capulet.com/chamber'
40 -- start='1469-07-21T02:56:15Z'
41 -- thread='damduoeg08'
42 -- subject='She speaks!'
43 -- version='1'>
44 -- <from secs='0'><body>Art thou not Romeo, and a Montague?</body></from>
45 -- <to secs='11'><body>Neither, fair saint, if either thee dislike.</body></to>
46 -- <from secs='7'><body>How cam'st thou hither, tell me, and wherefore?</body></from>
47 -- <note utc='1469-07-21T03:04:35Z'>I think she might fancy me.</note>
48 -- </chat>
49 local collection = st.deserialize(v); 50 local collection = st.deserialize(v);
50 if collection.attr["thread"] == thread:get_text() then 51 if collection.attr["thread"] == thread:get_text() then
51 -- TODO figure out secs 52 -- TODO figure out secs
52 collection:tag(tag, {secs='1'}):add_child(body); 53 collection:tag(tag, {secs='1', utc=os_time()}):add_child(body);
53 local ver = tonumber(collection.attr["version"]) + 1; 54 local ver = tonumber(collection.attr["version"]) + 1;
54 collection.attr["version"] = tostring(ver); 55 collection.attr["version"] = tostring(ver);
55 data[k] = collection; 56 data[k] = collection;
56 dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data)); 57 dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data));
57 return; 58 return;
58 end 59 end
59 end 60 end
60 end 61 end
61 -- not found, create new collection 62 -- not found, create new collection
62 -- TODO figure out start time 63 local utc = os_time();
63 local collection = st.stanza('chat', {with = isfrom and msg.attr.to or msg.attr.from, start='2010-06-01T09:56:15Z', thread=thread:get_text(), version='0'}); 64 local collection = st.stanza('chat', {with = isfrom and msg.attr.to or msg.attr.from, start=utc, thread=thread:get_text(), version='0'});
64 collection:tag(tag, {secs='0'}):add_child(body); 65 collection:tag(tag, {secs='0', utc=utc}):add_child(body);
65 dm.list_append(node, host, ARCHIVE_DIR, st.preserialize(collection)); 66 dm.list_append(node, host, ARCHIVE_DIR, st.preserialize(collection));
66 end 67 end
67 68
68 local function save_result(collection) 69 local function save_result(collection)
69 local save = st.stanza('save', {xmlns='urn:xmpp:archive'}); 70 local save = st.stanza('save', {xmlns='urn:xmpp:archive'});
183 end 184 end
184 return true; 185 return true;
185 end 186 end
186 187
187 local function itemremove_handler(event) 188 local function itemremove_handler(event)
188 -- TODO use 'assert' to check imcoming stanza? 189 -- TODO use 'assert' to check incoming stanza?
189 -- or use pcall() to catch exceptions? 190 -- or use pcall() to catch exceptions?
190 local origin, stanza = event.origin, event.stanza; 191 local origin, stanza = event.origin, event.stanza;
191 if stanza.attr.type ~= "set" then 192 if stanza.attr.type ~= "set" then
192 return false; 193 return false;
193 end 194 end
255 store_prefs(data, node, host); 256 store_prefs(data, node, host);
256 origin.send(st.reply(stanza)); 257 origin.send(st.reply(stanza));
257 return true; 258 return true;
258 end 259 end
259 260
260 local function chat_handler(event) 261 ------------------------------------------------------------
261 module:log("debug", "-- stanza:\n%s", tostring(event.stanza)); 262 -- Manual Archiving
262 return true; 263 ------------------------------------------------------------
263 end
264
265 local function list_handler(event)
266 module:log("debug", "-- stanza:\n%s", tostring(event.stanza));
267 return true;
268 end
269
270 local function modified_handler(event)
271 module:log("debug", "-- stanza:\n%s", tostring(event.stanza));
272 return true;
273 end
274
275 local function remove_handler(event)
276 module:log("debug", "-- stanza:\n%s", tostring(event.stanza));
277 return true;
278 end
279
280 local function retrieve_handler(event)
281 module:log("debug", "-- stanza:\n%s", tostring(event.stanza));
282 return true;
283 end
284
285 local function save_handler(event) 264 local function save_handler(event)
286 local origin, stanza = event.origin, event.stanza; 265 local origin, stanza = event.origin, event.stanza;
287 if stanza.attr.type ~= "set" then 266 if stanza.attr.type ~= "set" then
288 return false; 267 return false;
289 end 268 end
301 -- TODO check if there're duplicates 280 -- TODO check if there're duplicates
302 for newchild in elem:children() do 281 for newchild in elem:children() do
303 if type(newchild) == "table" then 282 if type(newchild) == "table" then
304 if newchild.name == "from" or newchild.name == "to" then 283 if newchild.name == "from" or newchild.name == "to" then
305 collection:add_child(newchild); 284 collection:add_child(newchild);
306 elseif newchild.name == "note" or newchild.name == "previous" or newchild.name == "next" or newchild.name == "x" then 285 elseif newchild.name == "note" or newchild.name == "previous"
286 or newchild.name == "next" or newchild.name == "x" then
307 local found = false; 287 local found = false;
308 for i, c in ipairs(collection) do 288 for i, c in ipairs(collection) do
309 if c.name == newchild.name then 289 if c.name == newchild.name then
310 found = true; 290 found = true;
311 collection[i] = newchild; 291 collection[i] = newchild;
332 elem.attr["version"] = "0"; 312 elem.attr["version"] = "0";
333 origin.send(st.reply(stanza):add_child(save_result(elem))); 313 origin.send(st.reply(stanza):add_child(save_result(elem)));
334 -- TODO check if elem is valid(?) 314 -- TODO check if elem is valid(?)
335 dm.list_append(node, host, ARCHIVE_DIR, st.preserialize(elem)); 315 dm.list_append(node, host, ARCHIVE_DIR, st.preserialize(elem));
336 -- TODO unsuccessful reply 316 -- TODO unsuccessful reply
317 return true;
318 end
319
320 ------------------------------------------------------------
321 -- Archive Management
322 ------------------------------------------------------------
323 local function filter_with(with, coll_with)
324 return not with or coll_with:find(with);
325 end
326
327 local function filter_start(start, coll_start)
328 return not start or start <= coll_start;
329 end
330
331 local function filter_end(endtime, coll_start)
332 return not endtime or endtime >= coll_start;
333 end
334
335 local function list_handler(event)
336 local origin, stanza = event.origin, event.stanza;
337 local node, host = origin.username, origin.host;
338 local data = dm.list_load(node, host, ARCHIVE_DIR);
339 local elem = stanza.tags[1];
340 local resset = {}
341 if data then
342 for k, v in ipairs(data) do
343 local collection = st.deserialize(v);
344 local res = filter_with(elem.attr["with"], collection.attr["with"]);
345 res = res and filter_start(elem.attr["start"], collection.attr["start"]);
346 res = res and filter_end(elem.attr["end"], collection.attr["start"]);
347 if res then
348 table.insert(resset, collection);
349 end
350 end
351 end
352 local reply = st.reply(stanza):tag('list', {xmlns='urn:xmpp:archive'});
353 if table.getn(resset) > 0 then
354 local max = tonumber(elem.tags[1].tags[1]:get_text());
355 -- Assuming result set is sorted.
356 for i, c in ipairs(resset) do
357 if i <= max then
358 local chat = st.stanza('chat', c.attr);
359 reply:add_child(chat);
360 else break; end
361 end
362 end
363 origin.send(reply);
364 return true;
365 end
366
367 local function retrieve_handler(event)
368 module:log("debug", "-- stanza:\n%s", tostring(event.stanza));
369 return true;
370 end
371
372 local function remove_handler(event)
373 module:log("debug", "-- stanza:\n%s", tostring(event.stanza));
374 return true;
375 end
376
377 ------------------------------------------------------------
378 -- Replication
379 ------------------------------------------------------------
380 local function modified_handler(event)
381 module:log("debug", "-- stanza:\n%s", tostring(event.stanza));
337 return true; 382 return true;
338 end 383 end
339 384
340 ------------------------------------------------------------ 385 ------------------------------------------------------------
341 -- Message Handler 386 -- Message Handler
365 end 410 end
366 end 411 end
367 return nil; 412 return nil;
368 end 413 end
369 414
415 -- Preferences
370 module:hook("iq/self/urn:xmpp:archive:pref", preferences_handler); 416 module:hook("iq/self/urn:xmpp:archive:pref", preferences_handler);
371 module:hook("iq/self/urn:xmpp:archive:itemremove", itemremove_handler); 417 module:hook("iq/self/urn:xmpp:archive:itemremove", itemremove_handler);
372 module:hook("iq/self/urn:xmpp:archive:sessionremove", sessionremove_handler); 418 module:hook("iq/self/urn:xmpp:archive:sessionremove", sessionremove_handler);
373 module:hook("iq/self/urn:xmpp:archive:auto", auto_handler); 419 module:hook("iq/self/urn:xmpp:archive:auto", auto_handler);
374 -- module:hook("iq/self/urn:xmpp:archive:chat", chat_handler); 420 -- Manual archiving
421 module:hook("iq/self/urn:xmpp:archive:save", save_handler);
422 -- Archive management
375 module:hook("iq/self/urn:xmpp:archive:list", list_handler); 423 module:hook("iq/self/urn:xmpp:archive:list", list_handler);
424 module:hook("iq/self/urn:xmpp:archive:retrieve", retrieve_handler);
425 module:hook("iq/self/urn:xmpp:archive:remove", remove_handler);
426 -- Replication
376 module:hook("iq/self/urn:xmpp:archive:modified", modified_handler); 427 module:hook("iq/self/urn:xmpp:archive:modified", modified_handler);
377 module:hook("iq/self/urn:xmpp:archive:remove", remove_handler);
378 module:hook("iq/self/urn:xmpp:archive:retrieve", retrieve_handler);
379 module:hook("iq/self/urn:xmpp:archive:save", save_handler);
380 428
381 module:hook("message/full", msg_handler, 10); 429 module:hook("message/full", msg_handler, 10);
382 module:hook("message/bare", msg_handler, 10); 430 module:hook("message/bare", msg_handler, 10);
383 431
432 -- FIXME sort collections
433