Software /
code /
prosody
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 |
child | 9340: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); |