Mercurial > 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 |
| 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); |
