Merge presence/subscription support from waqas
[prosody.git] / util / datamanager.lua
1 local format = string.format;
2 local setmetatable, type = setmetatable, type;
3 local pairs = pairs;
4 local char = string.char;
5 local loadfile, setfenv, pcall = loadfile, setfenv, pcall;
6 local log = log;
7 local io_open = io.open;
8 local tostring = tostring;
9 local error = error;
10
11 module "datamanager"
12
13
14 ---- utils -----
15 local encode, decode;
16
17 local log = function (type, msg) return log(type, "datamanager", msg); end
18
19 do 
20         local urlcodes = setmetatable({}, { __index = function (t, k) t[k] = char(tonumber("0x"..k)); return t[k]; end });
21
22         decode = function (s)
23                 return s and (s:gsub("+", " "):gsub("%%([a-fA-F0-9][a-fA-F0-9])", urlcodes));
24         end
25
26         encode = function (s)
27                 return s and (s:gsub("%W", function (c) return format("%%%x", c:byte()); end));
28         end
29 end
30
31 local function basicSerialize (o)
32   if type(o) == "number" or type(o) == "boolean" then
33     return tostring(o)
34   else -- assume it is a string
35     return format("%q", tostring(o))
36   end
37 end
38
39
40 local function simplesave (f, o)
41       if type(o) == "number" then
42         f:write(o)
43       elseif type(o) == "string" then
44         f:write(format("%q", o))
45       elseif type(o) == "table" then
46         f:write("{\n")
47         for k,v in pairs(o) do
48           f:write(" [", basicSerialize(k), "] = ")
49           simplesave(f, v)
50           f:write(",\n")
51         end
52         f:write("}\n")
53       elseif type(o) == "boolean" then
54         f:write(o and "true" or "false");
55       else
56         error("cannot serialize a " .. type(o))
57       end
58     end
59   
60 ------- API -------------
61
62 function getpath(username, host, datastore)
63         if username then
64                 return format("data/%s/%s/%s.dat", encode(host), datastore, encode(username));
65         elseif host then
66                 return format("data/%s/%s.dat", encode(host), datastore);
67         else
68                 return format("data/%s.dat", datastore);
69         end
70 end
71
72 function load(username, host, datastore)
73         local data, ret = loadfile(getpath(username, host, datastore));
74         if not data then
75                 log("warn", "Failed to load "..datastore.." storage ('"..ret.."') for user: "..(username or nil).."@"..(host or nil));
76                 return nil;
77         end
78         setfenv(data, {});
79         local success, ret = pcall(data);
80         if not success then
81                 log("error", "Unable to load "..datastore.." storage ('"..ret.."') for user: "..(username or nil).."@"..(host or nil));
82                 return nil;
83         end
84         return ret;
85 end
86
87 function store(username, host, datastore, data)
88         local f, msg = io_open(getpath(username, host, datastore), "w+");
89         if not f then
90                 log("error", "Unable to write to "..datastore.." storage ('"..msg.."') for user: "..(username or nil).."@"..(host or nil));
91                 return nil;
92         end
93         f:write("return ");
94         simplesave(f, data);
95         f:close();
96         return true;
97 end
98
99 return _M;