Comparison

mod_storage_s3/mod_storage_s3.lua @ 5759:ba731ff5b895

mod_storage_s3: Reorder path components (BC: invalidates any existing data) keyvalue: /bucket/hostname/username/store archive: /bucket/hostname/username/store/yyyy-mm-dd/with/key
author Kim Alvefur <zash@zash.se>
date Mon, 27 Nov 2023 09:30:04 +0100
parent 5758:9a1d8c39d0b0
child 5760:72b0fa7e36dc
comparison
equal deleted inserted replaced
5758:9a1d8c39d0b0 5759:ba731ff5b895
153 function keyval:_path(key) 153 function keyval:_path(key)
154 return url.build_path({ 154 return url.build_path({
155 is_absolute = true; 155 is_absolute = true;
156 bucket; 156 bucket;
157 jid.escape(module.host); 157 jid.escape(module.host);
158 jid.escape(key or "@");
158 jid.escape(self.store); 159 jid.escape(self.store);
159 jid.escape(key or "@");
160 }) 160 })
161 end 161 end
162 162
163 function keyval:get(user) 163 function keyval:get(user)
164 return async.wait_for(new_request(self, "GET", self:_path(user)):next(on_result)); 164 return async.wait_for(new_request(self, "GET", self:_path(user)):next(on_result));
173 return async.wait_for(new_request(self, "PUT", self:_path(user), nil, data)); 173 return async.wait_for(new_request(self, "PUT", self:_path(user), nil, data));
174 end 174 end
175 175
176 function keyval:users() 176 function keyval:users()
177 local bucket_path = url.build_path({ is_absolute = true; bucket; is_directory = true }); 177 local bucket_path = url.build_path({ is_absolute = true; bucket; is_directory = true });
178 local prefix = url.build_path({ jid.escape(module.host); jid.escape(self.store); is_directory = true }); 178 local prefix = url.build_path({ jid.escape(module.host); is_directory = true });
179 local list_result, err = async.wait_for(new_request(self, "GET", bucket_path, { prefix = prefix })) 179 local list_result, err = async.wait_for(new_request(self, "GET", bucket_path, { prefix = prefix }))
180 if err or list_result.code ~= 200 then 180 if err or list_result.code ~= 200 then
181 return nil, err; 181 return nil, err;
182 end 182 end
183 local list_bucket_result = xml.parse(list_result.body); 183 local list_bucket_result = xml.parse(list_result.body);
184 if list_bucket_result:get_child_text("IsTruncated") == "true" then 184 if list_bucket_result:get_child_text("IsTruncated") == "true" then
185 local max_keys = list_bucket_result:get_child_text("MaxKeys"); 185 local max_keys = list_bucket_result:get_child_text("MaxKeys");
186 module:log("warn", "Paging truncated results not implemented, max %s %s returned", max_keys, self.store); 186 module:log("warn", "Paging truncated results not implemented, max %s %s returned", max_keys, self.store);
187 end 187 end
188 local keys = array(); 188 local keys = array();
189 local store_part = jid.escape(self.store);
189 for content in list_bucket_result:childtags("Contents") do 190 for content in list_bucket_result:childtags("Contents") do
190 local key = url.parse_path(content:get_child_text("Key")); 191 local key = url.parse_path(content:get_child_text("Key"));
191 keys:push(jid.unescape(key[3])); 192 if key[3] == store_part then
193 keys:push(jid.unescape(key[2]));
194 end
192 end 195 end
193 return function() 196 return function()
194 return keys:pop(); 197 return keys:pop();
195 end 198 end
196 end 199 end
206 function archive:_path(username, date, when, with, key) 209 function archive:_path(username, date, when, with, key)
207 return url.build_path({ 210 return url.build_path({
208 is_absolute = true; 211 is_absolute = true;
209 bucket; 212 bucket;
210 jid.escape(module.host); 213 jid.escape(module.host);
214 jid.escape(username or "@");
211 jid.escape(self.store); 215 jid.escape(self.store);
212 jid.escape(username or "@"); 216 date or dt.date(when);
213 jid.escape(with and jid.prep(with) or "@"); 217 jid.escape(with and jid.prep(with) or "@");
214 date or dt.date(when);
215 key; 218 key;
216 }) 219 })
217 end 220 end
218 221
219 222
233 end)); 236 end));
234 end 237 end
235 238
236 function archive:find(username, query) 239 function archive:find(username, query)
237 local bucket_path = url.build_path({ is_absolute = true; bucket; is_directory = true }); 240 local bucket_path = url.build_path({ is_absolute = true; bucket; is_directory = true });
238 local prefix = { jid.escape(module.host); jid.escape(self.store); is_directory = true }; 241 local prefix = { jid.escape(module.host); jid.escape(username or "@"); jid.escape(self.store); is_directory = true };
239 table.insert(prefix, jid.escape(username or "@"));
240 if not query then 242 if not query then
241 query = {}; 243 query = {};
242 end 244 end
243 if query["with"] then 245
244 table.insert(prefix, jid.escape(jid.prep(query["with"]), true):sub(1,24)); 246 if query["start"] and query["end"] and dt.date(query["start"]) == dt.date(query["end"]) then
245 if query["start"] and query["end"] and dt.date(query["start"]) == dt.date(query["end"]) then 247 table.insert(prefix, dt.date(query["start"]));
246 table.insert(prefix, dt.date(query["start"])); 248 if query["with"] then
249 table.insert(prefix, jid.escape(query["with"]));
247 end 250 end
248 end 251 end
249 252
250 prefix = url.build_path(prefix); 253 prefix = url.build_path(prefix);
251 local list_result, err = async.wait_for(new_request(self, "GET", bucket_path, { 254 local list_result, err = async.wait_for(new_request(self, "GET", bucket_path, {
269 iterwrap = it.reverse; 272 iterwrap = it.reverse;
270 end 273 end
271 local ids = query["ids"] and set.new(query["ids"]); 274 local ids = query["ids"] and set.new(query["ids"]);
272 local found = not query["after"]; 275 local found = not query["after"];
273 for content in iterwrap(list_bucket_result:childtags("Contents")) do 276 for content in iterwrap(list_bucket_result:childtags("Contents")) do
274 local key = url.parse_path(content:get_child_text("Key")); 277 local when, with, id = table.unpack(url.parse_path(content:get_child_text("Key")), 4);
275 if found and query["before"] == key[6] then 278 with = jid.unescape(with);
279 if found and query["before"] == id then
276 break 280 break
277 end 281 end
278 if (not query["with"] or query["with"] == jid.unescape(key[5])) 282 if (not query["with"] or query["with"] == with)
279 and (not query["start"] or dt.date(query["start"]) >= key[6]) 283 and (not query["start"] or dt.date(query["start"]) >= when)
280 and (not query["end"] or dt.date(query["end"]) <= key[6]) 284 and (not query["end"] or dt.date(query["end"]) <= when)
281 and (not ids or ids:contains(key[6])) 285 and (not ids or ids:contains(id))
282 and found then 286 and found then
283 keys:push({ key = key[6]; date = key[5]; with = jid.unescape(key[4]) }); 287 keys:push({ key = id; date = when; with = with });
284 end 288 end
285 if not found and key[6] == query["after"] then 289 if not found and id == query["after"] then
286 found = not found 290 found = not found
287 end 291 end
288 end 292 end
289 local i = 0; 293 local i = 0;
290 local function get_next() 294 local function get_next()