changeset 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 648c24de9040
files mod_archive/mod_archive.lua
diffstat 1 files changed, 78 insertions(+), 34 deletions(-) [+]
line wrap: on
line diff
--- a/mod_archive/mod_archive.lua	Mon Jul 26 21:15:41 2010 +0800
+++ b/mod_archive/mod_archive.lua	Thu Jul 29 14:36:41 2010 +0800
@@ -38,9 +38,12 @@
     dm.store(node, host, PREFS_DIR, st.preserialize(data));
 end
 
-local function os_time()
-    -- return tostring(os.time(os.date('!*t')));
-    return datetime.datetime();
+local function os_date()
+    return os.date("!*t");
+end
+
+local function date_time(t)
+    return datetime.datetime(t);
 end
 
 local function date_parse(s)
@@ -48,46 +51,88 @@
 	return os.time({year=year, month=month, day=day, hour=hour, min=min, sec=sec});
 end
 
+-- local function list_push(node, host, collection)
+-- 	local data = dm.list_load(node, host, ARCHIVE_DIR);
+--     if data then
+--         table.insert(data, collection, 1);
+--         dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data));
+--     else
+--         dm.list_append(node, host, ARCHIVE_DIR, st.preserialize(collection));
+--     end
+-- end
+
+local function list_insert(node, host, collection)
+	local data = dm.list_load(node, host, ARCHIVE_DIR);
+    if data then
+        local s, e = 1, #data;
+        while true do
+            local c = st.deserialize(data[s]);
+            if collection.attr["start"] >= c.attr["start"] then
+                table.insert(data, collection, s);
+                break;
+            end
+            c = st.deserialize(data[e]);
+            if collection.attr["start"] <= c.attr["start"] then
+                table.insert(data, collection, e+1);
+                break;
+            end
+            local m = math.floor((s + e) / 2);
+            c = st.deserialize(data[m]);
+            if collection.attr["start"] > c.attr["start"] then
+                e = m - 1;
+            elseif collection.attr["start"] < c.attr["start"] then
+                s = m + 1;
+            else
+                table.insert(data, collection, m);
+                break;
+            end
+        end
+        dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data));
+    else
+        dm.list_append(node, host, ARCHIVE_DIR, st.preserialize(collection));
+    end
+end
+
 local function store_msg(msg, node, host, isfrom)
     local body = msg:child_with_name("body");
     local thread = msg:child_with_name("thread");
 	local data = dm.list_load(node, host, ARCHIVE_DIR);
-    local tag = (isfrom and "from") or "to";
-    local utc = os_time();
+    local tag = isfrom and "from" or "to";
+    local with = isfrom and msg.attr.to or msg.attr.from;
+    local utc = os_date();
+    local utc_secs = os.time(utc);
+    local utc_datetime = date_time(utc);
     if data then
-        if thread then
-            for k, v in ipairs(data) do
-                local collection = st.deserialize(v);
-                if collection.attr["thread"] == thread:get_text() then
-                    -- TODO figure out secs
-                    collection:tag(tag, {secs='1', utc=utc}):add_child(body);
-                    local ver = tonumber(collection.attr["version"]) + 1;
-                    collection.attr["version"] = tostring(ver);
-                    collection.attr["access"] = utc;
-                    data[k] = collection;
-                    dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data));
-                    return;
+        -- TODO assuming the collection list are in REVERSE chronological order 
+        for k, v in ipairs(data) do
+            local collection = st.deserialize(v);
+            if thread and collection.attr["thread"] == thread:get_text()
+                or
+                not thread
+                and collection.attr["with"] == with
+                and os.difftime(utc_secs, date_parse(collection.attr["start"])) < 14400 then
+                local dt = 1;
+                for i = #collection, 1, -1 do
+                    local s = collection[i].attr["utc_secs"];
+                    if s then
+                        dt = os.difftime(utc_secs, tonumber(s));
+                        break;
+                    end
                 end
-            end
-        else -- if the last collection occurs on the same day, then join it
-            -- TODO assuming the collection list are in chronological order 
-            local collection = st.deserialize(data[#data]);
-            local difftime = os.difftime(date_parse(utc), date_parse(collection.attr["start"]));
-            if difftime < 86400 then -- 60 * 60 * 24
-                collection:tag(tag, {secs='1', utc=utc}):add_child(body);
+                collection:tag(tag, {secs=dt, utc_secs=utc_secs}):add_child(body);
                 local ver = tonumber(collection.attr["version"]) + 1;
                 collection.attr["version"] = tostring(ver);
-                collection.attr["access"] = utc;
-                data[#data] = collection;
+                collection.attr["access"] = utc_datetime;
+                data[k] = collection;
                 dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data));
                 return;
             end
         end
     end
     -- not found, create new collection
-    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});
-    collection:tag(tag, {secs='0', utc=utc}):add_child(body);
-    dm.list_append(node, host, ARCHIVE_DIR, st.preserialize(collection));
+    local collection = st.stanza('chat', {with=with, start=utc_datetime, thread=thread and thread:get_text() or nil, version='0', access=utc_datetime});
+    collection:tag(tag, {secs='0', utc_secs=utc_secs}):add_child(body);
+    list_insert(node, host, collection);
 end
 
 local function save_result(collection)
@@ -157,7 +202,6 @@
         elseif elem.name == "item" then
             local found = false;
             for child in data:children() do
-                -- TODO bare JID or full JID?
                 if child.name == elem.name and child.attr["jid"] == elem.attr["jid"] then
                     for k, v in pairs(elem.attr) do
                         child.attr[k] = v;
@@ -341,7 +385,7 @@
                 local ver = tonumber(collection.attr["version"]) + 1;
                 collection.attr["version"] = tostring(ver);
                 collection.attr["subject"] = elem.attr["subject"];
-                collection.attr["access"] = os_time();
+                collection.attr["access"] = date_time();
                 origin.send(st.reply(stanza):add_child(save_result(collection)));
                 data[k] = collection;
                 dm.list_store(node, host, ARCHIVE_DIR, st.preserialize(data));
@@ -351,10 +395,10 @@
     end
     -- not found, create new collection
     elem.attr["version"] = "0";
-    elem.attr["access"] = os_time();
+    elem.attr["access"] = date_time();
     origin.send(st.reply(stanza):add_child(save_result(elem)));
     -- TODO check if elem is valid(?)
-    dm.list_append(node, host, ARCHIVE_DIR, st.preserialize(elem));
+    list_insert(node, host, elem);
     -- TODO unsuccessful reply
     return true;
 end
@@ -556,7 +600,7 @@
                 if res then
                     -- table.remove(data, i);
                     local temp = st.stanza('chat', collection.attr);
-                    temp.attr["access"] = os_time();
+                    temp.attr["access"] = date_time();
                     data[i] = temp;
                     found = true;
                 end