10 local st = require"util.stanza"; |
10 local st = require"util.stanza"; |
11 local dt = require"util.datetime"; |
11 local dt = require"util.datetime"; |
12 local new_stream = require "util.xmppstream".new; |
12 local new_stream = require "util.xmppstream".new; |
13 local empty = {}; |
13 local empty = {}; |
14 |
14 |
15 local function fallocate(f, offset, len) |
|
16 -- This assumes that current position == offset |
|
17 local fake_data = (" "):rep(len); |
|
18 local ok, msg = f:write(fake_data); |
|
19 if not ok then |
|
20 return ok, msg; |
|
21 end |
|
22 return f:seek("set", offset); |
|
23 end; |
|
24 |
|
25 pcall(function() |
|
26 local pposix = require "util.pposix"; |
|
27 fallocate = pposix.fallocate or fallocate; |
|
28 end); |
|
29 |
|
30 local archive = {}; |
15 local archive = {}; |
31 local archive_mt = { __index = archive }; |
16 local archive_mt = { __index = archive }; |
32 |
17 |
33 function archive:append(username, _, data, when, with) |
18 function archive:append(username, _, data, when, with) |
34 if type(when) ~= "number" then |
19 if type(when) ~= "number" then |
41 |
26 |
42 username = username or "@"; |
27 username = username or "@"; |
43 data = tostring(data) .. "\n"; |
28 data = tostring(data) .. "\n"; |
44 |
29 |
45 local day = dt.date(when); |
30 local day = dt.date(when); |
46 local filename = dm.getpath(username.."@"..day, module.host, self.store, "xml", true); |
31 local ok, err = dm.append_raw(username.."@"..day, module.host, self.store, "xml", data); |
47 |
32 if not ok then |
48 local ok, err; |
33 return nil, err; |
49 local f = io.open(filename, "r+"); |
34 end |
50 if not f then |
35 |
51 f, err = io.open(filename, "w"); if not f then return nil, err; end |
36 local offset = ok and err; |
52 ok, err = dm.list_append(username, module.host, self.store, day); |
|
53 if not ok then return nil, err; end |
|
54 end |
|
55 |
|
56 local offset = f:seek("end"); -- Seek to the end and collect current file length |
|
57 -- then make sure there is enough free space for what we're about to add |
|
58 ok, err = fallocate(f, offset, #data); if not ok then return nil, err; end |
|
59 ok, err = f:write(data); if not ok then return nil, err; end |
|
60 ok, err = f:close(); if not ok then return nil, err; end |
|
61 |
37 |
62 local id = day .. "-" .. hmac_sha256(username.."@"..day.."+"..offset, data, true):sub(-16); |
38 local id = day .. "-" .. hmac_sha256(username.."@"..day.."+"..offset, data, true):sub(-16); |
63 ok, err = dm.list_append(username.."@"..day, module.host, self.store, { id = id, when = dt.datetime(when), with = with, offset = offset, length = #data }); |
39 ok, err = dm.list_append(username.."@"..day, module.host, self.store, { id = id, when = dt.datetime(when), with = with, offset = offset, length = #data }); |
64 if not ok then return nil, err; end |
40 if offset == 0 then |
|
41 -- means the message is at the beginnig of the file, so it's a new day |
|
42 -- so we add this new day to the "index" |
|
43 dm.list_append(username, module.host, self.store, day); |
|
44 end |
|
45 if not ok then |
|
46 return nil, err; |
|
47 end |
65 return id; |
48 return id; |
66 end |
49 end |
67 |
50 |
68 function archive:find(username, query) |
51 function archive:find(username, query) |
69 username = username or "@"; |
52 username = username or "@"; |