Software / code / prosody-modules
Comparison
mod_http_upload/mod_http_upload.lua @ 2684:e491a15d7621
mod_http_upload: Switch to using a map store
| author | Kim Alvefur <zash@zash.se> |
|---|---|
| date | Thu, 13 Apr 2017 22:18:28 +0200 |
| parent | 2683:d0948bd96a7b |
| child | 2687:5f0b755b42a3 |
comparison
equal
deleted
inserted
replaced
| 2683:d0948bd96a7b | 2684:e491a15d7621 |
|---|---|
| 10 -- imports | 10 -- imports |
| 11 local st = require"util.stanza"; | 11 local st = require"util.stanza"; |
| 12 local lfs = require"lfs"; | 12 local lfs = require"lfs"; |
| 13 local url = require "socket.url"; | 13 local url = require "socket.url"; |
| 14 local dataform = require "util.dataforms".new; | 14 local dataform = require "util.dataforms".new; |
| 15 local datamanager = require "util.datamanager"; | |
| 16 local array = require "util.array"; | |
| 17 local t_concat = table.concat; | 15 local t_concat = table.concat; |
| 18 local t_insert = table.insert; | 16 local t_insert = table.insert; |
| 19 local s_upper = string.upper; | 17 local s_upper = string.upper; |
| 20 local have_id, id = pcall(require, "util.id"); -- Only available in 0.10+ | 18 local have_id, id = pcall(require, "util.id"); -- Only available in 0.10+ |
| 21 local uuid = require"util.uuid".generate; | 19 local uuid = require"util.uuid".generate; |
| 67 { name = "max-file-size", type = "text-single" }, | 65 { name = "max-file-size", type = "text-single" }, |
| 68 }:form({ ["max-file-size"] = tostring(file_size_limit) }, "result")); | 66 }:form({ ["max-file-size"] = tostring(file_size_limit) }, "result")); |
| 69 | 67 |
| 70 -- state | 68 -- state |
| 71 local pending_slots = module:shared("upload_slots"); | 69 local pending_slots = module:shared("upload_slots"); |
| 70 local used_slots = module:open_store(); | |
| 71 local slot_map = module:open_store(nil, "map"); | |
| 72 | 72 |
| 73 local storage_path = module:get_option_string(module.name .. "_path", join_path(prosody.paths.data, module.name)); | 73 local storage_path = module:get_option_string(module.name .. "_path", join_path(prosody.paths.data, module.name)); |
| 74 lfs.mkdir(storage_path); | 74 lfs.mkdir(storage_path); |
| 75 | 75 |
| 76 local function k(u, h) return h ~= module.host and u .. "@" .. h or u; end | |
| 77 | |
| 76 local function expire(username, host) | 78 local function expire(username, host) |
| 77 if not max_age then return true; end | 79 if not max_age then return true; end |
| 78 local uploads, err = datamanager.list_load(username, host, module.name); | 80 local uploads, err = used_slots:get(k(username, host)); |
| 79 if not uploads then return true; end | 81 if not uploads then return true; end |
| 80 uploads = array(uploads); | |
| 81 local expiry = os.time() - max_age; | 82 local expiry = os.time() - max_age; |
| 82 uploads:filter(function (item) | 83 local upload_window = os.time() - 900; |
| 84 for slot, item in pairs(uploads) do | |
| 85 local full_filename = join_path(storage_path, item.dir, item.filename); | |
| 83 if item.time < expiry then | 86 if item.time < expiry then |
| 84 local deleted, whynot = os.remove(item.filename); | 87 local deleted, whynot = os.remove(full_filename); |
| 85 if not deleted then | 88 if deleted then |
| 89 module:log("debug", "Deleted expired upload %s", item.filename); | |
| 90 else | |
| 86 module:log("warn", "Could not delete expired upload %s: %s", item.filename, whynot or "delete failed"); | 91 module:log("warn", "Could not delete expired upload %s: %s", item.filename, whynot or "delete failed"); |
| 87 end | 92 end |
| 88 return false; | 93 uploads[slot] = nil; |
| 94 elseif item.time < upload_window and not lfs.attributes(full_filename) then | |
| 95 pending_slots[slot] = nil; | |
| 96 uploads[slot] = nil; | |
| 89 end | 97 end |
| 90 return true; | 98 end |
| 91 end); | 99 return used_slots:set(k(username, host), uploads); |
| 92 return datamanager.list_store(username, host, module.name, uploads); | |
| 93 end | 100 end |
| 94 | 101 |
| 95 local function check_quota(username, host, does_it_fit) | 102 local function check_quota(username, host, does_it_fit) |
| 96 if not quota then return true; end | 103 if not quota then return true; end |
| 97 local uploads, err = datamanager.list_load(username, host, module.name); | 104 local uploads, err = used_slots:get(k(username, host)); |
| 98 if not uploads then return true; end | 105 if not uploads then return true; end |
| 99 local sum = does_it_fit or 0; | 106 local sum = does_it_fit or 0; |
| 100 for _, item in ipairs(uploads) do | 107 for _, item in pairs(uploads) do |
| 101 sum = sum + item.size; | 108 sum = sum + item.size; |
| 102 end | 109 end |
| 103 return sum < quota; | 110 return sum < quota; |
| 104 end | 111 end |
| 105 | 112 |
| 154 local random_dir; | 161 local random_dir; |
| 155 repeat random_dir = uuid(); | 162 repeat random_dir = uuid(); |
| 156 until lfs.mkdir(join_path(storage_path, random_dir)) | 163 until lfs.mkdir(join_path(storage_path, random_dir)) |
| 157 or not lfs.attributes(join_path(storage_path, random_dir, filename)) | 164 or not lfs.attributes(join_path(storage_path, random_dir, filename)) |
| 158 | 165 |
| 159 datamanager.list_append(origin.username, origin.host, module.name, { | 166 local key = k(origin.username, origin.host); |
| 160 filename = join_path(storage_path, random_dir, filename), size = filesize, time = os.time() }); | |
| 161 local slot = random_dir.."/"..filename; | 167 local slot = random_dir.."/"..filename; |
| 168 local ok = slot_map:set(key, slot, { | |
| 169 filename = filename, dir = random_dir, size = filesize, time = os.time() | |
| 170 }); | |
| 171 if not ok then | |
| 172 origin.send(st.error_reply(stanza, "wait", "internal-server-failure")); | |
| 173 return true; | |
| 174 end | |
| 162 pending_slots[slot] = origin.full_jid; | 175 pending_slots[slot] = origin.full_jid; |
| 163 | 176 |
| 164 module:add_timer(900, function() | 177 module:add_timer(900, function() |
| 165 pending_slots[slot] = nil; | 178 pending_slots[slot] = nil; |
| 179 if not lfs.attributes(join_path(storage_path, slot)) then | |
| 180 slot_map:set(key, slot, nil); | |
| 181 end | |
| 166 end); | 182 end); |
| 167 | 183 |
| 168 local base_url = module:http_url(); | 184 local base_url = module:http_url(); |
| 169 local slot_url = url.parse(base_url); | 185 local slot_url = url.parse(base_url); |
| 170 slot_url.path = url.parse_path(slot_url.path or "/"); | 186 slot_url.path = url.parse_path(slot_url.path or "/"); |
| 242 return 201; | 258 return 201; |
| 243 end | 259 end |
| 244 | 260 |
| 245 -- FIXME Duplicated from net.http.server | 261 -- FIXME Duplicated from net.http.server |
| 246 | 262 |
| 263 -- luacheck: ignore 431/k | |
| 247 local codes = require "net.http.codes"; | 264 local codes = require "net.http.codes"; |
| 248 local headerfix = setmetatable({}, { | 265 local headerfix = setmetatable({}, { |
| 249 __index = function(t, k) | 266 __index = function(t, k) |
| 250 local v = "\r\n"..k:gsub("_", "-"):gsub("%f[%w].", s_upper)..": "; | 267 local v = "\r\n"..k:gsub("_", "-"):gsub("%f[%w].", s_upper)..": "; |
| 251 t[k] = v; | 268 t[k] = v; |