mod_storage_memory: Also merged into core
[prosody-modules.git] / mod_storage_appendmap / mod_storage_appendmap.lua
blobfc23b00d06390d2c0f72c2d755b45299e4e6eb1e
1 local dump = require "util.serialization".serialize;
2 local load = require "util.envload".envloadfile;
3 local dm = require "core.storagemanager".olddm;
5 local REMOVE = {}; -- Special value for removing keys
7 local driver = {};
10 local keywords = {
11 ["do"] = true; ["and"] = true; ["else"] = true; ["break"] = true;
12 ["if"] = true; ["end"] = true; ["goto"] = true; ["false"] = true;
13 ["in"] = true; ["for"] = true; ["then"] = true; ["local"] = true;
14 ["or"] = true; ["nil"] = true; ["true"] = true; ["until"] = true;
15 ["elseif"] = true; ["function"] = true; ["not"] = true;
16 ["repeat"] = true; ["return"] = true; ["while"] = true;
18 -- _ENV is not technically a keyword but we need to treat it as such
19 ["_ENV"] = true;
22 local function is_usable_identifier(s)
23 return type(s) == "string" and not keywords[s] and s:find("^[%a_][%w_]*$");
24 end
26 local function serialize_key(key)
27 if is_usable_identifier(key) then
28 return key;
29 else
30 return "_ENV[" .. dump(key) .. "]";
31 end
32 end
34 local function serialize_value(value)
35 if value == REMOVE then
36 return "nil";
37 else
38 return dump(value);
39 end
40 end
42 local function serialize_pair(key, value)
43 key = serialize_key(key);
44 value = serialize_value(value);
45 return key .. " = " .. value .. ";\n";
46 end
48 local function serialize_map(keyvalues)
49 local keys, values = {}, {};
50 for key, value in pairs(keyvalues) do
51 key = serialize_key(key);
52 value = serialize_value(value);
53 table.insert(keys, key);
54 table.insert(values, value);
55 end
56 return table.concat(keys, ", ") .. " = " .. table.concat(values, ", ") .. ";\n";
57 end
59 local map = { remove = REMOVE };
60 local map_mt = { __index = map };
62 function map:get(user, key)
63 module:log("debug", "map:get(%s, %s)", tostring(user), tostring(key))
64 local filename = dm.getpath(user, module.host, self.store, "map");
65 module:log("debug", "File is %s", filename);
66 local env = {};
67 if _VERSION == "Lua 5.1" then -- HACK
68 env._ENV = env; -- HACK
69 end -- SO MANY HACKS
70 local chunk, err, errno = load(filename, env);
71 if not chunk then if errno == 2 then return end return chunk, err; end
72 local ok, err = pcall(chunk);
73 if not ok then return ok, err; end
74 if _VERSION == "Lua 5.1" then -- HACK
75 env._ENV = nil; -- HACK
76 end -- HACKS EVERYWHERE
77 if key == nil then
78 return env;
79 end
80 return env[key];
81 end
83 function map:set_keys(user, keyvalues)
84 local data = serialize_map(keyvalues);
85 return dm.append_raw(user, module.host, self.store, "map", data);
86 end
88 function map:set(user, key, value)
89 if _VERSION == "Lua 5.1" then
90 assert(key ~= "_ENV", "'_ENV' is a restricted key");
91 end
92 if key == nil then
93 local filename = dm.getpath(user, module.host, self.store, "map");
94 return os.remove(filename);
95 end
96 local data = serialize_pair(key, value);
97 return dm.append_raw(user, module.host, self.store, "map", data);
98 end
100 local keyval = { remove = REMOVE };
101 local keyval_mt = { __index = keyval };
103 function keyval:get(user)
104 return map.get(self, user, nil);
107 function keyval:set(user, keyvalues)
108 local data = serialize_map(keyvalues);
109 return dm.store_raw(user, module.host, self.store, "map", data);
112 -- TODO some kind of periodic compaction thing?
113 function map:_compact(user)
114 local data = self:get(user);
115 return keyval.set(self, user, data);
118 function driver:open(store, typ)
119 if typ == "map" then
120 return setmetatable({ store = store, }, map_mt);
121 elseif typ == nil or typ == "keyval" then
122 return setmetatable({ store = store, }, keyval_mt);
124 return nil, "unsupported-store";
127 module:provides("storage", driver);