Mercurial > prosody-hg
comparison plugins/mod_storage_memory.lua @ 9293:0a751835627d
mod_storage_memory: Import from prosody-modules 4c3230c22c18
| author | Matthew Wild <mwild1@gmail.com> |
|---|---|
| date | Wed, 12 Sep 2018 13:44:03 +0100 |
| parents | |
| children | 368b092bf4bf |
comparison
equal
deleted
inserted
replaced
| 9292:d5f798efb1ba | 9293:0a751835627d |
|---|---|
| 1 local serialize = require "util.serialization".serialize; | |
| 2 local envload = require "util.envload".envload; | |
| 3 local st = require "util.stanza"; | |
| 4 local is_stanza = st.is_stanza or function (s) return getmetatable(s) == st.stanza_mt end | |
| 5 | |
| 6 local auto_purge_enabled = module:get_option_boolean("storage_memory_temporary", false); | |
| 7 local auto_purge_stores = module:get_option_set("storage_memory_temporary_stores", {}); | |
| 8 | |
| 9 local memory = setmetatable({}, { | |
| 10 __index = function(t, k) | |
| 11 local store = module:shared(k) | |
| 12 t[k] = store; | |
| 13 return store; | |
| 14 end | |
| 15 }); | |
| 16 | |
| 17 local function NULL() return nil end | |
| 18 | |
| 19 local function _purge_store(self, username) | |
| 20 self.store[username or NULL] = nil; | |
| 21 return true; | |
| 22 end | |
| 23 | |
| 24 local keyval_store = {}; | |
| 25 keyval_store.__index = keyval_store; | |
| 26 | |
| 27 function keyval_store:get(username) | |
| 28 return (self.store[username or NULL] or NULL)(); | |
| 29 end | |
| 30 | |
| 31 function keyval_store:set(username, data) | |
| 32 if data ~= nil then | |
| 33 data = envload("return "..serialize(data), "@data", {}); | |
| 34 end | |
| 35 self.store[username or NULL] = data; | |
| 36 return true; | |
| 37 end | |
| 38 | |
| 39 keyval_store.purge = _purge_store; | |
| 40 | |
| 41 local archive_store = {}; | |
| 42 archive_store.__index = archive_store; | |
| 43 | |
| 44 function archive_store:append(username, key, value, when, with) | |
| 45 if type(when) ~= "number" then | |
| 46 when, with, value = value, when, with; | |
| 47 end | |
| 48 if is_stanza(value) then | |
| 49 value = st.preserialize(value); | |
| 50 value = envload("return xml"..serialize(value), "@stanza", { xml = st.deserialize }) | |
| 51 else | |
| 52 value = envload("return "..serialize(value), "@data", {}); | |
| 53 end | |
| 54 local a = self.store[username or NULL]; | |
| 55 if not a then | |
| 56 a = {}; | |
| 57 self.store[username or NULL] = a; | |
| 58 end | |
| 59 local i = #a+1; | |
| 60 local v = { key = key, when = when, with = with, value = value }; | |
| 61 if not key then | |
| 62 key = tostring(a):match"%x+$"..tostring(v):match"%x+$"; | |
| 63 v.key = key; | |
| 64 end | |
| 65 if a[key] then | |
| 66 table.remove(a, a[key]); | |
| 67 end | |
| 68 a[i] = v; | |
| 69 a[key] = i; | |
| 70 return key; | |
| 71 end | |
| 72 | |
| 73 local function archive_iter (a, start, stop, step, limit, when_start, when_end, match_with) | |
| 74 local item, when, with; | |
| 75 local count = 0; | |
| 76 coroutine.yield(true); -- Ready | |
| 77 for i = start, stop, step do | |
| 78 item = a[i]; | |
| 79 when, with = item.when, item.with; | |
| 80 if when >= when_start and when_end >= when and (not match_with or match_with == with) then | |
| 81 coroutine.yield(item.key, item.value(), when, with); | |
| 82 count = count + 1; | |
| 83 if limit and count >= limit then return end | |
| 84 end | |
| 85 end | |
| 86 end | |
| 87 | |
| 88 function archive_store:find(username, query) | |
| 89 local a = self.store[username or NULL] or {}; | |
| 90 local start, stop, step = 1, #a, 1; | |
| 91 local qstart, qend, qwith = -math.huge, math.huge; | |
| 92 local limit; | |
| 93 if query then | |
| 94 module:log("debug", "query included") | |
| 95 if query.reverse then | |
| 96 start, stop, step = stop, start, -1; | |
| 97 if query.before then | |
| 98 start = a[query.before]; | |
| 99 end | |
| 100 elseif query.after then | |
| 101 start = a[query.after]; | |
| 102 end | |
| 103 limit = query.limit; | |
| 104 qstart = query.start or qstart; | |
| 105 qend = query["end"] or qend; | |
| 106 qwith = query.with; | |
| 107 end | |
| 108 if not start then return nil, "invalid-key"; end | |
| 109 local iter = coroutine.wrap(archive_iter); | |
| 110 iter(a, start, stop, step, limit, qstart, qend, qwith); | |
| 111 return iter; | |
| 112 end | |
| 113 | |
| 114 function archive_store:delete(username, query) | |
| 115 if not query or next(query) == nil then | |
| 116 self.store[username or NULL] = nil; | |
| 117 return true; | |
| 118 end | |
| 119 local old = self.store[username or NULL]; | |
| 120 if not old then return true; end | |
| 121 local qstart = query.start or -math.huge; | |
| 122 local qend = query["end"] or math.huge; | |
| 123 local qwith = query.with; | |
| 124 local new = {}; | |
| 125 self.store[username or NULL] = new; | |
| 126 local t; | |
| 127 for i = 1, #old do | |
| 128 i = old[i]; | |
| 129 t = i.when; | |
| 130 if not(qstart >= t and qend <= t and (not qwith or i.with == qwith)) then | |
| 131 self:append(username, i.key, i.value, t, i.with); | |
| 132 end | |
| 133 end | |
| 134 if #new == 0 then | |
| 135 self.store[username or NULL] = nil; | |
| 136 end | |
| 137 return true; | |
| 138 end | |
| 139 | |
| 140 archive_store.purge = _purge_store; | |
| 141 | |
| 142 local stores = { | |
| 143 keyval = keyval_store; | |
| 144 archive = archive_store; | |
| 145 } | |
| 146 | |
| 147 local driver = {}; | |
| 148 | |
| 149 function driver:open(store, typ) -- luacheck: ignore 212/self | |
| 150 local store_mt = stores[typ or "keyval"]; | |
| 151 if store_mt then | |
| 152 return setmetatable({ store = memory[store] }, store_mt); | |
| 153 end | |
| 154 return nil, "unsupported-store"; | |
| 155 end | |
| 156 | |
| 157 if auto_purge_enabled then | |
| 158 module:hook("resource-unbind", function (event) | |
| 159 local user_bare_jid = event.session.username.."@"..event.session.host; | |
| 160 if not prosody.bare_sessions[user_bare_jid] then -- User went offline | |
| 161 module:log("debug", "Clearing store for offline user %s", user_bare_jid); | |
| 162 local f, s, v; | |
| 163 if auto_purge_stores:empty() then | |
| 164 f, s, v = pairs(memory); | |
| 165 else | |
| 166 f, s, v = auto_purge_stores:items(); | |
| 167 end | |
| 168 | |
| 169 for store_name in f, s, v do | |
| 170 if memory[store_name] then | |
| 171 memory[store_name][event.session.username] = nil; | |
| 172 end | |
| 173 end | |
| 174 end | |
| 175 end); | |
| 176 end | |
| 177 | |
| 178 module:provides("storage", driver); |
