util/datamanager.lua
changeset 5049 5d685f123332
parent 5045 4ba6940deed0
child 5051 71253db26fda
equal deleted inserted replaced
5048:e02161ba20e0 5049:5d685f123332
    13 local char = string.char;
    13 local char = string.char;
    14 local pcall = pcall;
    14 local pcall = pcall;
    15 local log = require "util.logger".init("datamanager");
    15 local log = require "util.logger".init("datamanager");
    16 local io_open = io.open;
    16 local io_open = io.open;
    17 local os_remove = os.remove;
    17 local os_remove = os.remove;
       
    18 local os_rename = os.rename;
    18 local tostring, tonumber = tostring, tonumber;
    19 local tostring, tonumber = tostring, tonumber;
    19 local error = error;
    20 local error = error;
    20 local next = next;
    21 local next = next;
    21 local t_insert = table.insert;
    22 local t_insert = table.insert;
    22 local append = require "util.serialization".append;
    23 local t_concat = table.concat;
    23 local envloadfile = require"util.envload".envloadfile;
    24 local envloadfile = require"util.envload".envloadfile;
    24 local serialize = require "util.serialization".serialize;
    25 local serialize = require "util.serialization".serialize;
    25 local path_separator = assert ( package.config:match ( "^([^\n]+)" ) , "package.config not in standard form" ) -- Extract directory seperator from package.config (an undocumented string that comes with lua)
    26 local path_separator = assert ( package.config:match ( "^([^\n]+)" ) , "package.config not in standard form" ) -- Extract directory seperator from package.config (an undocumented string that comes with lua)
    26 local lfs = require "lfs";
    27 local lfs = require "lfs";
    27 local prosody = prosody;
    28 local prosody = prosody;
   147 		return nil, "Error reading storage";
   148 		return nil, "Error reading storage";
   148 	end
   149 	end
   149 	return ret;
   150 	return ret;
   150 end
   151 end
   151 
   152 
       
   153 local function atomic_store(filename, data)
       
   154 	local scratch = filename.."~";
       
   155 	local f, ok, msg;
       
   156 	repeat
       
   157 		f, msg = io_open(scratch, "w");
       
   158 		if not f then break end
       
   159 
       
   160 		ok, msg = f:write(data);
       
   161 		if not ok then break end
       
   162 
       
   163 		ok, msg = f:close();
       
   164 		if not ok then break end
       
   165 
       
   166 		return os_rename(scratch, filename);
       
   167 	until false;
       
   168 
       
   169 	-- Cleanup
       
   170 	if f then f:close(); end
       
   171 	os_remove(scratch);
       
   172 	return nil, msg;
       
   173 end
       
   174 
   152 function store(username, host, datastore, data)
   175 function store(username, host, datastore, data)
   153 	if not data then
   176 	if not data then
   154 		data = {};
   177 		data = {};
   155 	end
   178 	end
   156 
   179 
   158 	if username == false then
   181 	if username == false then
   159 		return true; -- Don't save this data at all
   182 		return true; -- Don't save this data at all
   160 	end
   183 	end
   161 
   184 
   162 	-- save the datastore
   185 	-- save the datastore
   163 	local f, msg = io_open(getpath(username, host, datastore, nil, true), "w+");
   186 	local d = "return " .. serialize(data) .. ";\n";
   164 	if not f then
   187 	local ok, msg = atomic_store(getpath(username, host, datastore, nil, true), d);
       
   188 	if not ok then
   165 		log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil");
   189 		log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil");
   166 		return nil, "Error saving to storage";
   190 		return nil, "Error saving to storage";
   167 	end
   191 	end
   168 	f:write("return ");
       
   169 	append(f, data);
       
   170 	f:close();
       
   171 	if next(data) == nil then -- try to delete empty datastore
   192 	if next(data) == nil then -- try to delete empty datastore
   172 		log("debug", "Removing empty %s datastore for user %s@%s", datastore, username or "nil", host or "nil");
   193 		log("debug", "Removing empty %s datastore for user %s@%s", datastore, username or "nil", host or "nil");
   173 		os_remove(getpath(username, host, datastore));
   194 		os_remove(getpath(username, host, datastore));
   174 	end
   195 	end
   175 	-- we write data even when we are deleting because lua doesn't have a
   196 	-- we write data even when we are deleting because lua doesn't have a
   204 	if not data then
   225 	if not data then
   205 		data = {};
   226 		data = {};
   206 	end
   227 	end
   207 	if callback(username, host, datastore) == false then return true; end
   228 	if callback(username, host, datastore) == false then return true; end
   208 	-- save the datastore
   229 	-- save the datastore
   209 	local f, msg = io_open(getpath(username, host, datastore, "list", true), "w+");
   230 	local d = {};
   210 	if not f then
   231 	for _, item in ipairs(data) do
       
   232 		d[#d+1] = "item(" .. serialize(item) .. ");\n";
       
   233 	end
       
   234 	local ok, msg = atomic_store(getpath(username, host, datastore, "list", true), t_concat(d));
       
   235 	if not ok then
   211 		log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil");
   236 		log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil");
   212 		return;
   237 		return;
   213 	end
   238 	end
   214 	for _, d in ipairs(data) do
       
   215 		f:write("item(");
       
   216 		append(f, d);
       
   217 		f:write(");\n");
       
   218 	end
       
   219 	f:close();
       
   220 	if next(data) == nil then -- try to delete empty datastore
   239 	if next(data) == nil then -- try to delete empty datastore
   221 		log("debug", "Removing empty %s datastore for user %s@%s", datastore, username or "nil", host or "nil");
   240 		log("debug", "Removing empty %s datastore for user %s@%s", datastore, username or "nil", host or "nil");
   222 		os_remove(getpath(username, host, datastore, "list"));
   241 		os_remove(getpath(username, host, datastore, "list"));
   223 	end
   242 	end
   224 	-- we write data even when we are deleting because lua doesn't have a
   243 	-- we write data even when we are deleting because lua doesn't have a