41 local pposix = require "util.pposix"; |
41 local pposix = require "util.pposix"; |
42 raw_mkdir = pposix.mkdir or raw_mkdir; -- Doesn't trample on umask |
42 raw_mkdir = pposix.mkdir or raw_mkdir; -- Doesn't trample on umask |
43 fallocate = pposix.fallocate or fallocate; |
43 fallocate = pposix.fallocate or fallocate; |
44 end); |
44 end); |
45 |
45 |
46 module "datamanager" |
46 local _ENV = nil; |
47 |
47 |
48 ---- utils ----- |
48 ---- utils ----- |
49 local encode, decode; |
49 local encode, decode; |
50 do |
50 do |
51 local urlcodes = setmetatable({}, { __index = function (t, k) t[k] = char(tonumber("0x"..k)); return t[k]; end }); |
51 local urlcodes = setmetatable({}, { __index = function (t, k) t[k] = char(tonumber("0x"..k)); return t[k]; end }); |
72 local data_path = (prosody and prosody.paths and prosody.paths.data) or "."; |
72 local data_path = (prosody and prosody.paths and prosody.paths.data) or "."; |
73 local callbacks = {}; |
73 local callbacks = {}; |
74 |
74 |
75 ------- API ------------- |
75 ------- API ------------- |
76 |
76 |
77 function set_data_path(path) |
77 local function set_data_path(path) |
78 log("debug", "Setting data path to: %s", path); |
78 log("debug", "Setting data path to: %s", path); |
79 data_path = path; |
79 data_path = path; |
80 end |
80 end |
81 |
81 |
82 local function callback(username, host, datastore, data) |
82 local function callback(username, host, datastore, data) |
85 if username == false then break; end |
85 if username == false then break; end |
86 end |
86 end |
87 |
87 |
88 return username, host, datastore, data; |
88 return username, host, datastore, data; |
89 end |
89 end |
90 function add_callback(func) |
90 local function add_callback(func) |
91 if not callbacks[func] then -- Would you really want to set the same callback more than once? |
91 if not callbacks[func] then -- Would you really want to set the same callback more than once? |
92 callbacks[func] = true; |
92 callbacks[func] = true; |
93 callbacks[#callbacks+1] = func; |
93 callbacks[#callbacks+1] = func; |
94 return true; |
94 return true; |
95 end |
95 end |
96 end |
96 end |
97 function remove_callback(func) |
97 local function remove_callback(func) |
98 if callbacks[func] then |
98 if callbacks[func] then |
99 for i, f in ipairs(callbacks) do |
99 for i, f in ipairs(callbacks) do |
100 if f == func then |
100 if f == func then |
101 callbacks[i] = nil; |
101 callbacks[i] = nil; |
102 callbacks[f] = nil; |
102 callbacks[f] = nil; |
104 end |
104 end |
105 end |
105 end |
106 end |
106 end |
107 end |
107 end |
108 |
108 |
109 function getpath(username, host, datastore, ext, create) |
109 local function getpath(username, host, datastore, ext, create) |
110 ext = ext or "dat"; |
110 ext = ext or "dat"; |
111 host = (host and encode(host)) or "_global"; |
111 host = (host and encode(host)) or "_global"; |
112 username = username and encode(username); |
112 username = username and encode(username); |
113 if username then |
113 if username then |
114 if create then mkdir(mkdir(mkdir(data_path).."/"..host).."/"..datastore); end |
114 if create then mkdir(mkdir(mkdir(data_path).."/"..host).."/"..datastore); end |
117 if create then mkdir(mkdir(data_path).."/"..host); end |
117 if create then mkdir(mkdir(data_path).."/"..host); end |
118 return format("%s/%s/%s.%s", data_path, host, datastore, ext); |
118 return format("%s/%s/%s.%s", data_path, host, datastore, ext); |
119 end |
119 end |
120 end |
120 end |
121 |
121 |
122 function load(username, host, datastore) |
122 local function load(username, host, datastore) |
123 local data, ret = envloadfile(getpath(username, host, datastore), {}); |
123 local data, ret = envloadfile(getpath(username, host, datastore), {}); |
124 if not data then |
124 if not data then |
125 local mode = lfs.attributes(getpath(username, host, datastore), "mode"); |
125 local mode = lfs.attributes(getpath(username, host, datastore), "mode"); |
126 if not mode then |
126 if not mode then |
127 log("debug", "Assuming empty %s storage ('%s') for user: %s@%s", datastore, ret, username or "nil", host or "nil"); |
127 log("debug", "Assuming empty %s storage ('%s') for user: %s@%s", datastore, ret, username or "nil", host or "nil"); |
173 if not ok then f:close(); return ok, msg; end |
173 if not ok then f:close(); return ok, msg; end |
174 return f:close(); |
174 return f:close(); |
175 end |
175 end |
176 end |
176 end |
177 |
177 |
178 function store(username, host, datastore, data) |
178 local function store(username, host, datastore, data) |
179 if not data then |
179 if not data then |
180 data = {}; |
180 data = {}; |
181 end |
181 end |
182 |
182 |
183 username, host, datastore, data = callback(username, host, datastore, data); |
183 username, host, datastore, data = callback(username, host, datastore, data); |
207 -- platform independent way of checking for non-exisitng files |
207 -- platform independent way of checking for non-exisitng files |
208 until ok; |
208 until ok; |
209 return true; |
209 return true; |
210 end |
210 end |
211 |
211 |
212 function list_append(username, host, datastore, data) |
212 local function list_append(username, host, datastore, data) |
213 if not data then return; end |
213 if not data then return; end |
214 if callback(username, host, datastore) == false then return true; end |
214 if callback(username, host, datastore) == false then return true; end |
215 -- save the datastore |
215 -- save the datastore |
216 local f, msg = io_open(getpath(username, host, datastore, "list", true), "r+"); |
216 local f, msg = io_open(getpath(username, host, datastore, "list", true), "r+"); |
217 if not f then |
217 if not f then |
233 end |
233 end |
234 f:close(); |
234 f:close(); |
235 return true; |
235 return true; |
236 end |
236 end |
237 |
237 |
238 function list_store(username, host, datastore, data) |
238 local function list_store(username, host, datastore, data) |
239 if not data then |
239 if not data then |
240 data = {}; |
240 data = {}; |
241 end |
241 end |
242 if callback(username, host, datastore) == false then return true; end |
242 if callback(username, host, datastore) == false then return true; end |
243 -- save the datastore |
243 -- save the datastore |
257 -- we write data even when we are deleting because lua doesn't have a |
257 -- we write data even when we are deleting because lua doesn't have a |
258 -- platform independent way of checking for non-exisitng files |
258 -- platform independent way of checking for non-exisitng files |
259 return true; |
259 return true; |
260 end |
260 end |
261 |
261 |
262 function list_load(username, host, datastore) |
262 local function list_load(username, host, datastore) |
263 local items = {}; |
263 local items = {}; |
264 local data, ret = envloadfile(getpath(username, host, datastore, "list"), {item = function(i) t_insert(items, i); end}); |
264 local data, ret = envloadfile(getpath(username, host, datastore, "list"), {item = function(i) t_insert(items, i); end}); |
265 if not data then |
265 if not data then |
266 local mode = lfs.attributes(getpath(username, host, datastore, "list"), "mode"); |
266 local mode = lfs.attributes(getpath(username, host, datastore, "list"), "mode"); |
267 if not mode then |
267 if not mode then |
285 local type_map = { |
285 local type_map = { |
286 keyval = "dat"; |
286 keyval = "dat"; |
287 list = "list"; |
287 list = "list"; |
288 } |
288 } |
289 |
289 |
290 function users(host, store, typ) |
290 local function users(host, store, typ) |
291 typ = type_map[typ or "keyval"]; |
291 typ = type_map[typ or "keyval"]; |
292 local store_dir = format("%s/%s/%s", data_path, encode(host), store); |
292 local store_dir = format("%s/%s/%s", data_path, encode(host), store); |
293 |
293 |
294 local mode, err = lfs.attributes(store_dir, "mode"); |
294 local mode, err = lfs.attributes(store_dir, "mode"); |
295 if not mode then |
295 if not mode then |
304 end |
304 end |
305 end |
305 end |
306 end, state; |
306 end, state; |
307 end |
307 end |
308 |
308 |
309 function stores(username, host, typ) |
309 local function stores(username, host, typ) |
310 typ = type_map[typ or "keyval"]; |
310 typ = type_map[typ or "keyval"]; |
311 local store_dir = format("%s/%s/", data_path, encode(host)); |
311 local store_dir = format("%s/%s/", data_path, encode(host)); |
312 |
312 |
313 local mode, err = lfs.attributes(store_dir, "mode"); |
313 local mode, err = lfs.attributes(store_dir, "mode"); |
314 if not mode then |
314 if not mode then |
344 return ok, err; |
344 return ok, err; |
345 end |
345 end |
346 return true |
346 return true |
347 end |
347 end |
348 |
348 |
349 function purge(username, host) |
349 local function purge(username, host) |
350 local host_dir = format("%s/%s/", data_path, encode(host)); |
350 local host_dir = format("%s/%s/", data_path, encode(host)); |
351 local ok, iter, state, var = pcall(lfs.dir, host_dir); |
351 local ok, iter, state, var = pcall(lfs.dir, host_dir); |
352 if not ok then |
352 if not ok then |
353 return ok, iter; |
353 return ok, iter; |
354 end |
354 end |
364 end |
364 end |
365 end |
365 end |
366 return #errs == 0, t_concat(errs, ", "); |
366 return #errs == 0, t_concat(errs, ", "); |
367 end |
367 end |
368 |
368 |
369 _M.path_decode = decode; |
369 return { |
370 _M.path_encode = encode; |
370 set_data_path = set_data_path; |
371 return _M; |
371 add_callback = add_callback; |
|
372 remove_callback = remove_callback; |
|
373 getpath = getpath; |
|
374 load = load; |
|
375 store = store; |
|
376 list_append = list_append; |
|
377 list_store = list_store; |
|
378 list_load = list_load; |
|
379 users = users; |
|
380 stores = stores; |
|
381 purge = purge; |
|
382 path_decode = decode; |
|
383 path_encode = encode; |
|
384 }; |