Software /
code /
prosody-modules
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 |