comparison mod_storage_appendmap/mod_storage_appendmap.lua @ 2796:6a7b7cb7148e

mod_storage_appendmap: Factor out serialization into reusable functions
author Kim Alvefur <zash@zash.se>
date Fri, 13 Oct 2017 00:31:40 +0200
parents 4548c3d685b4
children e44b868cc575
comparison
equal deleted inserted replaced
2795:226693a22fc9 2796:6a7b7cb7148e
1 local dump = require "util.serialization".serialize; 1 local dump = require "util.serialization".serialize;
2 local load = require "util.envload".envloadfile; 2 local load = require "util.envload".envloadfile;
3 local dm = require "core.storagemanager".olddm; 3 local dm = require "core.storagemanager".olddm;
4 4
5 local REMOVE = {}; -- Special value for removing keys
6
5 local driver = {}; 7 local driver = {};
6 8
7 local map = {}; 9
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;
17
18 -- _ENV is not technically a keyword but we need to treat it as such
19 ["_ENV"] = true;
20 };
21
22 local function is_usable_identifier(s)
23 return type(s) == "string" and not keywords[s] and s:find("^[%a_][%w_]*$");
24 end
25
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
33
34 local function serialize_value(value)
35 if value == REMOVE then
36 return "nil";
37 else
38 return dump(value);
39 end
40 end
41
42 local function serialize_pair(key, value)
43 key = serialize_key(key);
44 value = serialize_value(value);
45 return key .. " = " .. value .. ";\n";
46 end
47
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
58
59 local map = { remove = REMOVE };
8 local map_mt = { __index = map }; 60 local map_mt = { __index = map };
9 map.remove = {};
10 61
11 function map:get(user, key) 62 function map:get(user, key)
12 module:log("debug", "map:get(%s, %s)", tostring(user), tostring(key)) 63 module:log("debug", "map:get(%s, %s)", tostring(user), tostring(key))
13 local filename = dm.getpath(user, module.host, self.store, "map"); 64 local filename = dm.getpath(user, module.host, self.store, "map");
14 module:log("debug", "File is %s", filename); 65 module:log("debug", "File is %s", filename);
27 return env; 78 return env;
28 end 79 end
29 return env[key]; 80 return env[key];
30 end 81 end
31 82
32 local keywords = {
33 ["do"] = true; ["and"] = true; ["else"] = true; ["break"] = true;
34 ["if"] = true; ["end"] = true; ["goto"] = true; ["false"] = true;
35 ["in"] = true; ["for"] = true; ["then"] = true; ["local"] = true;
36 ["or"] = true; ["nil"] = true; ["true"] = true; ["until"] = true;
37 ["elseif"] = true; ["function"] = true; ["not"] = true;
38 ["repeat"] = true; ["return"] = true; ["while"] = true;
39
40 -- _ENV is not technically a keyword but we need to treat it as such
41 ["_ENV"] = true;
42 };
43
44 function map:set_keys(user, keyvalues) 83 function map:set_keys(user, keyvalues)
45 local keys, values = {}, {}; 84 local data = serialize_map(keyvalues);
46 if _VERSION == "Lua 5.1" then
47 assert(keyvalues._ENV == nil, "'_ENV' is a restricted key");
48 end
49 for key, value in pairs(keyvalues) do
50 module:log("debug", "user %s sets %q to %s", user, key, tostring(value))
51 if type(key) ~= "string" or not key:find("^[%a_][%w_]*$") or keywords[key] then
52 key = "_ENV[" .. dump(key) .. "]";
53 end
54 table.insert(keys, key);
55 if value == self.remove then
56 table.insert(values, "nil")
57 else
58 table.insert(values, dump(value))
59 end
60 end
61 local data = table.concat(keys, ", ") .. " = " .. table.concat(values, ", ") .. ";\n";
62 return dm.append_raw(user, module.host, self.store, "map", data); 85 return dm.append_raw(user, module.host, self.store, "map", data);
63 end 86 end
64 87
65 function map:set(user, key, value) 88 function map:set(user, key, value)
66 if _VERSION == "Lua 5.1" then 89 if _VERSION == "Lua 5.1" then
67 assert(key ~= "_ENV", "'_ENV' is a restricted key"); 90 assert(key ~= "_ENV", "'_ENV' is a restricted key");
68 end 91 end
69 if key == nil then 92 if key == nil then
70 local filename = dm.getpath(user, module.host, self.store, "map"); 93 local filename = dm.getpath(user, module.host, self.store, "map");
71 os.remove(filename); 94 return os.remove(filename);
72 return true;
73 end 95 end
74 if type(key) ~= "string" or not key:find("^[%w_][%w%d_]*$") or key == "_ENV" then 96 local data = serialize_pair(key, value);
75 key = "_ENV[" .. dump(key) .. "]";
76 end
77 local data = key .. " = " .. dump(value) .. ";\n";
78 return dm.append_raw(user, module.host, self.store, "map", data); 97 return dm.append_raw(user, module.host, self.store, "map", data);
79 end 98 end
80 99
81 local keyval = {}; 100 local keyval = { remove = REMOVE };
82 local keyval_mt = { __index = keyval }; 101 local keyval_mt = { __index = keyval };
83 102
84 function keyval:get(user) 103 function keyval:get(user)
85 return map.get(self, user); 104 return map.get(self, user, nil);
86 end 105 end
87 106
88 function keyval:set(user, data) 107 function keyval:set(user, keyvalues)
89 map.set(self, user); 108 local data = serialize_map(keyvalues);
90 if data then 109 return dm.store_raw(user, module.host, self.store, "map", data);
91 for k, v in pairs(data) do
92 map.set(self, user, k, v);
93 end
94 end
95 return true;
96 end 110 end
97 111
98 -- TODO some kind of periodic compaction thing? 112 -- TODO some kind of periodic compaction thing?
99 function map:_compact(user) 113 function map:_compact(user)
100 local data = self:get(user); 114 local data = self:get(user);