util/datamanager.lua
changeset 6780 5de6b93d0190
parent 6684 0217a04722c7
child 6995 0622f2820d1d
equal deleted inserted replaced
6777:3965662ae091 6780:5de6b93d0190
    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 };