Software /
code /
prosody-modules
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 |
parent | 2635:4548c3d685b4 |
child | 5061: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); |