Mercurial > prosody-modules
comparison mod_storage_muc_log/mod_storage_muc_log.lua @ 1566:9158882dd9a1
mod_storage_muc_log: Provides an archive API to mod_muc_log data
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Mon, 10 Nov 2014 14:41:01 +0100 |
parents | |
children | c357039c1ab1 |
comparison
equal
deleted
inserted
replaced
1565:f9cb09d451c7 | 1566:9158882dd9a1 |
---|---|
1 | |
2 local datamanager = require"core.storagemanager".olddm; | |
3 local xml_parse = require"util.xml".parse; | |
4 local data_load, data_store = datamanager.load, datamanager.store; | |
5 local datastore = "muc_log"; | |
6 local datetime = require"util.datetime" | |
7 local lfs = require"lfs"; | |
8 local noop = function () end; | |
9 local os_date = os.date; | |
10 | |
11 local timef, datef = "!%X", "!%y%m%d"; | |
12 local host = module.host; | |
13 | |
14 local driver = {}; | |
15 local driver_mt = { __index = driver }; | |
16 | |
17 do | |
18 -- Sanity check | |
19 -- Fun fact: 09:00 and 21:00 en_HK are both "09:00:00 UTC" | |
20 local t = os_date("!*t"); | |
21 t.hour = 9; | |
22 local am = os_date(timef, os.time(t)); | |
23 t.hour = 21; | |
24 local pm = os_date(timef, os.time(t)); | |
25 if am == pm then | |
26 module:log("warn", "Timestamps in AM and PM are identical in your locale, expect timestamps to be wrong"); | |
27 end | |
28 end | |
29 | |
30 local function parse_silly(date, time) | |
31 local year, month, day = date:match("^(%d%d)(%d%d)(%d%d)"); | |
32 year = "20"..year; | |
33 -- year = (year < "70" and "20" or "19") .. year; | |
34 local hour, min, sec = time:match("(%d%d)%D+(%d%d)%D+(%d%d)"); | |
35 if hour == "12" and time:find("[Aa][Mm]") then | |
36 hour = "00"; | |
37 elseif hour < "12" and time:find("[Pp][Mm]") then | |
38 hour = tostring(tonumber(hour) % 12 + 12); | |
39 end | |
40 return datetime.parse(("%s-%s-%sT%s:%s:%sZ"):format(year, month, day, hour or "00", min or "00", sec or "00")); | |
41 end | |
42 | |
43 local function st_with(tag) | |
44 local with = tag.attr.type; | |
45 return with and tag.name .. "<" .. with or tag.name; | |
46 end | |
47 | |
48 function driver:append(node, key, when, with, stanza) | |
49 local today = os_date(datef, when); | |
50 local now = os_date(timef, when); | |
51 local data = data_load(node, host, datastore .. "/" .. today) or {}; | |
52 data[#data + 1] = "<stanza time=\"".. now .. "\">" .. tostring(stanza) .. "</stanza>\n"; | |
53 datamanager.getpath(node, host, datastore, nil, true); -- create the datastore dir | |
54 local ok, err = data_store(node, host, datastore .. "/" .. today, data); | |
55 if not ok then | |
56 return ok, err; | |
57 end | |
58 return today .. "_" .. #data; | |
59 end | |
60 | |
61 function driver:find(node, query) | |
62 local path = datamanager.getpath(node, host, datastore):match("(.*)/"); | |
63 | |
64 local ok, iter, state, var = pcall(lfs.dir, path); | |
65 if not ok then | |
66 module:log("warn", iter); | |
67 return nil, iter; | |
68 end | |
69 | |
70 local dates, i = {}, 1; | |
71 for dir in iter, state, var do | |
72 if lfs.attributes(datamanager.getpath(node, host, datastore .. "/" .. dir), "mode") == "file" then | |
73 dates[i], i = dir, i+1; | |
74 end | |
75 end | |
76 if dates[1] == nil then return noop, 0; end | |
77 table.sort(dates); | |
78 | |
79 return coroutine.wrap(function () | |
80 local query = query; | |
81 local dates = dates; | |
82 local start_date = query and query.start and os_date(datef, query.start) or dates[1]; | |
83 local end_date = query and query["end"] and os_date(datef, query["end"]) or dates[#dates]; | |
84 local start_time = query and query.start and os_date(timef, query.start) or dates[1]; | |
85 local end_time = query and query["end"] and os_date(timef, query["end"]) or dates[#dates]; | |
86 local query_with = query and query.with; | |
87 local query_limit = query and query.limit; | |
88 local seek_once = query and query.after; | |
89 | |
90 local today, time, data, err, item; | |
91 local inner_start, inner_stop, inner_step; | |
92 local outer_start, outer_stop, outer_step = 1, #dates, 1; | |
93 if query and query.reverse then | |
94 outer_start, outer_stop, outer_step = outer_stop, outer_start, -outer_step; | |
95 seek_once = query.before; | |
96 if seek_once then | |
97 end_date = seek_once:match"^(%d+)_%d"; | |
98 end | |
99 elseif seek_once then | |
100 start_date = seek_once:match"^(%d+)_%d"; | |
101 end | |
102 local matches = 0; | |
103 for i = outer_start, outer_stop, outer_step do | |
104 today = dates[i]; | |
105 if today >= start_date and today <= end_date then | |
106 data, err = data_load(node, host, datastore .. "/" .. today); | |
107 if data then | |
108 inner_start, inner_stop, inner_step = 1, #data, 1; | |
109 if query and query.reverse then | |
110 inner_start, inner_stop, inner_step = inner_stop, inner_start, -inner_step; | |
111 end | |
112 if seek_once then | |
113 inner_start = tonumber(seek_once:match("_(%d+)$")); | |
114 inner_start = inner_start + (query and query.reverse and -1 or 1); | |
115 seek_once = nil; | |
116 end | |
117 for i = inner_start, inner_stop, inner_step do | |
118 item, err = data[i]; | |
119 if item then | |
120 item, err = xml_parse(item); | |
121 end | |
122 if item then | |
123 time = item.attr.time; | |
124 item = item.tags[1]; | |
125 if (today >= start_date or time >= start_time) and | |
126 (today <= end_date or time <= end_time) and | |
127 (not query_with or query_with == st_with(item)) and | |
128 item:get_child_text("alreadyJoined") ~= "true" then | |
129 matches = matches + 1; | |
130 coroutine.yield(today.."_"..i, item, parse_silly(today, time)); | |
131 if query_limit and matches >= query_limit then | |
132 return; | |
133 end | |
134 end | |
135 elseif err then | |
136 module:log("warn", err); | |
137 end | |
138 end | |
139 elseif err then | |
140 module:log("warn", err); | |
141 end | |
142 end | |
143 end | |
144 end); | |
145 end | |
146 | |
147 function open(_, store, typ) | |
148 if typ ~= "archive" then | |
149 return nil, "unsupported-store"; | |
150 end | |
151 return setmetatable({ store = store, type = typ }, driver_mt); | |
152 end | |
153 | |
154 module:provides "storage"; |