Mercurial > prosody-modules
comparison mod_archive/mod_archive.lua @ 225:95d4d53f09a1
mod_archive: keep collections in REVERSE chronological order(not tested).
| author | shinysky<shinysky1986(AT)gmail.com> |
|---|---|
| date | Thu, 29 Jul 2010 14:36:41 +0800 |
| parents | 96e29ff5fa07 |
| children | 7fe326037070 |
comparison
equal
deleted
inserted
replaced
| 224:96e29ff5fa07 | 225:95d4d53f09a1 |
|---|---|
| 36 | 36 |
| 37 local function store_prefs(data, node, host) | 37 local function store_prefs(data, node, host) |
| 38 dm.store(node, host, PREFS_DIR, st.preserialize(data)); | 38 dm.store(node, host, PREFS_DIR, st.preserialize(data)); |
| 39 end | 39 end |
| 40 | 40 |
| 41 local function os_time() | 41 local function os_date() |
| 42 -- return tostring(os.time(os.date('!*t'))); | 42 return os.date("!*t"); |
| 43 return datetime.datetime(); | 43 end |
| 44 | |
| 45 local function date_time(t) | |
| 46 return datetime.datetime(t); | |
| 44 end | 47 end |
| 45 | 48 |
| 46 local function date_parse(s) | 49 local function date_parse(s) |
| 47 local year, month, day, hour, min, sec = s:match("(....)-?(..)-?(..)T(..):(..):(..)Z"); | 50 local year, month, day, hour, min, sec = s:match("(....)-?(..)-?(..)T(..):(..):(..)Z"); |
| 48 return os.time({year=year, month=month, day=day, hour=hour, min=min, sec=sec}); | 51 return os.time({year=year, month=month, day=day, hour=hour, min=min, sec=sec}); |
| 52 end | |
| 53 | |
| 54 -- local function list_push(node, host, collection) | |
| 55 -- local data = dm.list_load(node, host, ARCHIVE_DIR); | |
| 56 -- if data then | |
| 57 -- table.insert(data, collection, 1); | |
| 58 -- dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data)); | |
| 59 -- else | |
| 60 -- dm.list_append(node, host, ARCHIVE_DIR, st.preserialize(collection)); | |
| 61 -- end | |
| 62 -- end | |
| 63 | |
| 64 local function list_insert(node, host, collection) | |
| 65 local data = dm.list_load(node, host, ARCHIVE_DIR); | |
| 66 if data then | |
| 67 local s, e = 1, #data; | |
| 68 while true do | |
| 69 local c = st.deserialize(data[s]); | |
| 70 if collection.attr["start"] >= c.attr["start"] then | |
| 71 table.insert(data, collection, s); | |
| 72 break; | |
| 73 end | |
| 74 c = st.deserialize(data[e]); | |
| 75 if collection.attr["start"] <= c.attr["start"] then | |
| 76 table.insert(data, collection, e+1); | |
| 77 break; | |
| 78 end | |
| 79 local m = math.floor((s + e) / 2); | |
| 80 c = st.deserialize(data[m]); | |
| 81 if collection.attr["start"] > c.attr["start"] then | |
| 82 e = m - 1; | |
| 83 elseif collection.attr["start"] < c.attr["start"] then | |
| 84 s = m + 1; | |
| 85 else | |
| 86 table.insert(data, collection, m); | |
| 87 break; | |
| 88 end | |
| 89 end | |
| 90 dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data)); | |
| 91 else | |
| 92 dm.list_append(node, host, ARCHIVE_DIR, st.preserialize(collection)); | |
| 93 end | |
| 49 end | 94 end |
| 50 | 95 |
| 51 local function store_msg(msg, node, host, isfrom) | 96 local function store_msg(msg, node, host, isfrom) |
| 52 local body = msg:child_with_name("body"); | 97 local body = msg:child_with_name("body"); |
| 53 local thread = msg:child_with_name("thread"); | 98 local thread = msg:child_with_name("thread"); |
| 54 local data = dm.list_load(node, host, ARCHIVE_DIR); | 99 local data = dm.list_load(node, host, ARCHIVE_DIR); |
| 55 local tag = (isfrom and "from") or "to"; | 100 local tag = isfrom and "from" or "to"; |
| 56 local utc = os_time(); | 101 local with = isfrom and msg.attr.to or msg.attr.from; |
| 102 local utc = os_date(); | |
| 103 local utc_secs = os.time(utc); | |
| 104 local utc_datetime = date_time(utc); | |
| 57 if data then | 105 if data then |
| 58 if thread then | 106 -- TODO assuming the collection list are in REVERSE chronological order |
| 59 for k, v in ipairs(data) do | 107 for k, v in ipairs(data) do |
| 60 local collection = st.deserialize(v); | 108 local collection = st.deserialize(v); |
| 61 if collection.attr["thread"] == thread:get_text() then | 109 if thread and collection.attr["thread"] == thread:get_text() |
| 62 -- TODO figure out secs | 110 or |
| 63 collection:tag(tag, {secs='1', utc=utc}):add_child(body); | 111 not thread |
| 64 local ver = tonumber(collection.attr["version"]) + 1; | 112 and collection.attr["with"] == with |
| 65 collection.attr["version"] = tostring(ver); | 113 and os.difftime(utc_secs, date_parse(collection.attr["start"])) < 14400 then |
| 66 collection.attr["access"] = utc; | 114 local dt = 1; |
| 67 data[k] = collection; | 115 for i = #collection, 1, -1 do |
| 68 dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data)); | 116 local s = collection[i].attr["utc_secs"]; |
| 69 return; | 117 if s then |
| 70 end | 118 dt = os.difftime(utc_secs, tonumber(s)); |
| 71 end | 119 break; |
| 72 else -- if the last collection occurs on the same day, then join it | 120 end |
| 73 -- TODO assuming the collection list are in chronological order | 121 end |
| 74 local collection = st.deserialize(data[#data]); | 122 collection:tag(tag, {secs=dt, utc_secs=utc_secs}):add_child(body); |
| 75 local difftime = os.difftime(date_parse(utc), date_parse(collection.attr["start"])); | |
| 76 if difftime < 86400 then -- 60 * 60 * 24 | |
| 77 collection:tag(tag, {secs='1', utc=utc}):add_child(body); | |
| 78 local ver = tonumber(collection.attr["version"]) + 1; | 123 local ver = tonumber(collection.attr["version"]) + 1; |
| 79 collection.attr["version"] = tostring(ver); | 124 collection.attr["version"] = tostring(ver); |
| 80 collection.attr["access"] = utc; | 125 collection.attr["access"] = utc_datetime; |
| 81 data[#data] = collection; | 126 data[k] = collection; |
| 82 dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data)); | 127 dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data)); |
| 83 return; | 128 return; |
| 84 end | 129 end |
| 85 end | 130 end |
| 86 end | 131 end |
| 87 -- not found, create new collection | 132 -- not found, create new collection |
| 88 local collection = st.stanza('chat', {with = isfrom and msg.attr.to or msg.attr.from, start=utc, thread=thread:get_text(), version='0', access=utc}); | 133 local collection = st.stanza('chat', {with=with, start=utc_datetime, thread=thread and thread:get_text() or nil, version='0', access=utc_datetime}); |
| 89 collection:tag(tag, {secs='0', utc=utc}):add_child(body); | 134 collection:tag(tag, {secs='0', utc_secs=utc_secs}):add_child(body); |
| 90 dm.list_append(node, host, ARCHIVE_DIR, st.preserialize(collection)); | 135 list_insert(node, host, collection); |
| 91 end | 136 end |
| 92 | 137 |
| 93 local function save_result(collection) | 138 local function save_result(collection) |
| 94 local save = st.stanza('save', {xmlns='urn:xmpp:archive'}); | 139 local save = st.stanza('save', {xmlns='urn:xmpp:archive'}); |
| 95 local chat = st.stanza('chat', collection.attr); | 140 local chat = st.stanza('chat', collection.attr); |
| 155 end | 200 end |
| 156 -- setting.attr["unset"] = nil | 201 -- setting.attr["unset"] = nil |
| 157 elseif elem.name == "item" then | 202 elseif elem.name == "item" then |
| 158 local found = false; | 203 local found = false; |
| 159 for child in data:children() do | 204 for child in data:children() do |
| 160 -- TODO bare JID or full JID? | |
| 161 if child.name == elem.name and child.attr["jid"] == elem.attr["jid"] then | 205 if child.name == elem.name and child.attr["jid"] == elem.attr["jid"] then |
| 162 for k, v in pairs(elem.attr) do | 206 for k, v in pairs(elem.attr) do |
| 163 child.attr[k] = v; | 207 child.attr[k] = v; |
| 164 end | 208 end |
| 165 found = true; | 209 found = true; |
| 339 end | 383 end |
| 340 end | 384 end |
| 341 local ver = tonumber(collection.attr["version"]) + 1; | 385 local ver = tonumber(collection.attr["version"]) + 1; |
| 342 collection.attr["version"] = tostring(ver); | 386 collection.attr["version"] = tostring(ver); |
| 343 collection.attr["subject"] = elem.attr["subject"]; | 387 collection.attr["subject"] = elem.attr["subject"]; |
| 344 collection.attr["access"] = os_time(); | 388 collection.attr["access"] = date_time(); |
| 345 origin.send(st.reply(stanza):add_child(save_result(collection))); | 389 origin.send(st.reply(stanza):add_child(save_result(collection))); |
| 346 data[k] = collection; | 390 data[k] = collection; |
| 347 dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data)); | 391 dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data)); |
| 348 return true; | 392 return true; |
| 349 end | 393 end |
| 350 end | 394 end |
| 351 end | 395 end |
| 352 -- not found, create new collection | 396 -- not found, create new collection |
| 353 elem.attr["version"] = "0"; | 397 elem.attr["version"] = "0"; |
| 354 elem.attr["access"] = os_time(); | 398 elem.attr["access"] = date_time(); |
| 355 origin.send(st.reply(stanza):add_child(save_result(elem))); | 399 origin.send(st.reply(stanza):add_child(save_result(elem))); |
| 356 -- TODO check if elem is valid(?) | 400 -- TODO check if elem is valid(?) |
| 357 dm.list_append(node, host, ARCHIVE_DIR, st.preserialize(elem)); | 401 list_insert(node, host, elem); |
| 358 -- TODO unsuccessful reply | 402 -- TODO unsuccessful reply |
| 359 return true; | 403 return true; |
| 360 end | 404 end |
| 361 | 405 |
| 362 ------------------------------------------------------------ | 406 ------------------------------------------------------------ |
| 554 res = res and filter_start(elem.attr["start"], collection.attr["start"]); | 598 res = res and filter_start(elem.attr["start"], collection.attr["start"]); |
| 555 res = res and filter_end(elem.attr["end"], collection.attr["start"]); | 599 res = res and filter_end(elem.attr["end"], collection.attr["start"]); |
| 556 if res then | 600 if res then |
| 557 -- table.remove(data, i); | 601 -- table.remove(data, i); |
| 558 local temp = st.stanza('chat', collection.attr); | 602 local temp = st.stanza('chat', collection.attr); |
| 559 temp.attr["access"] = os_time(); | 603 temp.attr["access"] = date_time(); |
| 560 data[i] = temp; | 604 data[i] = temp; |
| 561 found = true; | 605 found = true; |
| 562 end | 606 end |
| 563 end | 607 end |
| 564 end | 608 end |
