util/datamanager.lua
author Kim Alvefur <zash@zash.se>
Sun, 16 Dec 2012 14:36:24 +0100
changeset 5250 6d8ec8c90240
parent 5244 775d98184acf
child 5440 a943e5cbf083
permissions -rw-r--r--
util.datamanager: Don't escape the name of a store
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
1523
841d61be198f Remove version number from copyright headers
Matthew Wild <mwild1@gmail.com>
parents: 1462
diff changeset
     1
-- Prosody IM
2923
b7049746bd29 Update copyright headers for 2010
Matthew Wild <mwild1@gmail.com>
parents: 2159
diff changeset
     2
-- Copyright (C) 2008-2010 Matthew Wild
b7049746bd29 Update copyright headers for 2010
Matthew Wild <mwild1@gmail.com>
parents: 2159
diff changeset
     3
-- Copyright (C) 2008-2010 Waqas Hussain
4452
7de17ca4de14 util/datamanager: Use package.config to figure out directory seperator
James Callahan <james@chatid.com>
parents: 4112
diff changeset
     4
--
758
b1885732e979 GPL->MIT!
Matthew Wild <mwild1@gmail.com>
parents: 732
diff changeset
     5
-- This project is MIT/X11 licensed. Please see the
b1885732e979 GPL->MIT!
Matthew Wild <mwild1@gmail.com>
parents: 732
diff changeset
     6
-- COPYING file in the source package for more information.
519
cccd610a0ef9 Insert copyright/license headers
Matthew Wild <mwild1@gmail.com>
parents: 456
diff changeset
     7
--
cccd610a0ef9 Insert copyright/license headers
Matthew Wild <mwild1@gmail.com>
parents: 456
diff changeset
     8
cccd610a0ef9 Insert copyright/license headers
Matthew Wild <mwild1@gmail.com>
parents: 456
diff changeset
     9
0
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    10
local format = string.format;
5051
71253db26fda util.datamanager: Remove a few unused imports
Kim Alvefur <zash@zash.se>
parents: 5049
diff changeset
    11
local setmetatable = setmetatable;
71253db26fda util.datamanager: Remove a few unused imports
Kim Alvefur <zash@zash.se>
parents: 5049
diff changeset
    12
local ipairs = ipairs;
0
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    13
local char = string.char;
5021
85b2689dbcfe Eliminate direct setfenv usage
Florian Zeitz <florob@babelmonkeys.de>
parents: 4452
diff changeset
    14
local pcall = pcall;
456
27cb85d4059e Fixed logging in datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 452
diff changeset
    15
local log = require "util.logger".init("datamanager");
0
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    16
local io_open = io.open;
206
e30d0e30a0ff Datamanager now deletes files with no data
Waqas Hussain <waqas20@gmail.com>
parents: 182
diff changeset
    17
local os_remove = os.remove;
5049
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
    18
local os_rename = os.rename;
5051
71253db26fda util.datamanager: Remove a few unused imports
Kim Alvefur <zash@zash.se>
parents: 5049
diff changeset
    19
local tonumber = tonumber;
206
e30d0e30a0ff Datamanager now deletes files with no data
Waqas Hussain <waqas20@gmail.com>
parents: 182
diff changeset
    20
local next = next;
247
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
    21
local t_insert = table.insert;
5049
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
    22
local t_concat = table.concat;
5021
85b2689dbcfe Eliminate direct setfenv usage
Florian Zeitz <florob@babelmonkeys.de>
parents: 4452
diff changeset
    23
local envloadfile = require"util.envload".envloadfile;
5045
4ba6940deed0 util.datamanager: Use pposix.fallocate() to make sure appends succeed. Also add a fallback fallocate()
Kim Alvefur <zash@zash.se>
parents: 5038
diff changeset
    24
local serialize = require "util.serialization".serialize;
4452
7de17ca4de14 util/datamanager: Use package.config to figure out directory seperator
James Callahan <james@chatid.com>
parents: 4112
diff changeset
    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)
3086
931acb1188b1 util.datamanager: When failing to load a file, and the file exists, return nil, error.
Waqas Hussain <waqas20@gmail.com>
parents: 2925
diff changeset
    26
local lfs = require "lfs";
4093
36555949bd16 util.datamanager: Use prosody.paths.data as the initial value for data_path
Matthew Wild <mwild1@gmail.com>
parents: 3723
diff changeset
    27
local prosody = prosody;
2444
267d6482bac6 util.datamanager: Use pposix.mkdir if available
Matthew Wild <mwild1@gmail.com>
parents: 2328
diff changeset
    28
5118
0dc9e6c128c3 util.datamanager: Make the util.pposix dependency optional.
Waqas Hussain <waqas20@gmail.com>
parents: 5103
diff changeset
    29
local raw_mkdir = lfs.mkdir;
0dc9e6c128c3 util.datamanager: Make the util.pposix dependency optional.
Waqas Hussain <waqas20@gmail.com>
parents: 5103
diff changeset
    30
local function fallocate(f, offset, len)
0dc9e6c128c3 util.datamanager: Make the util.pposix dependency optional.
Waqas Hussain <waqas20@gmail.com>
parents: 5103
diff changeset
    31
	-- This assumes that current position == offset
0dc9e6c128c3 util.datamanager: Make the util.pposix dependency optional.
Waqas Hussain <waqas20@gmail.com>
parents: 5103
diff changeset
    32
	local fake_data = (" "):rep(len);
0dc9e6c128c3 util.datamanager: Make the util.pposix dependency optional.
Waqas Hussain <waqas20@gmail.com>
parents: 5103
diff changeset
    33
	local ok, msg = f:write(fake_data);
0dc9e6c128c3 util.datamanager: Make the util.pposix dependency optional.
Waqas Hussain <waqas20@gmail.com>
parents: 5103
diff changeset
    34
	if not ok then
0dc9e6c128c3 util.datamanager: Make the util.pposix dependency optional.
Waqas Hussain <waqas20@gmail.com>
parents: 5103
diff changeset
    35
		return ok, msg;
5045
4ba6940deed0 util.datamanager: Use pposix.fallocate() to make sure appends succeed. Also add a fallback fallocate()
Kim Alvefur <zash@zash.se>
parents: 5038
diff changeset
    36
	end
5118
0dc9e6c128c3 util.datamanager: Make the util.pposix dependency optional.
Waqas Hussain <waqas20@gmail.com>
parents: 5103
diff changeset
    37
	f:seek("set", offset);
0dc9e6c128c3 util.datamanager: Make the util.pposix dependency optional.
Waqas Hussain <waqas20@gmail.com>
parents: 5103
diff changeset
    38
	return true;
0dc9e6c128c3 util.datamanager: Make the util.pposix dependency optional.
Waqas Hussain <waqas20@gmail.com>
parents: 5103
diff changeset
    39
end;
0dc9e6c128c3 util.datamanager: Make the util.pposix dependency optional.
Waqas Hussain <waqas20@gmail.com>
parents: 5103
diff changeset
    40
pcall(function()
0dc9e6c128c3 util.datamanager: Make the util.pposix dependency optional.
Waqas Hussain <waqas20@gmail.com>
parents: 5103
diff changeset
    41
	local pposix = require "util.pposix";
0dc9e6c128c3 util.datamanager: Make the util.pposix dependency optional.
Waqas Hussain <waqas20@gmail.com>
parents: 5103
diff changeset
    42
	raw_mkdir = pposix.mkdir or raw_mkdir; -- Doesn't trample on umask
0dc9e6c128c3 util.datamanager: Make the util.pposix dependency optional.
Waqas Hussain <waqas20@gmail.com>
parents: 5103
diff changeset
    43
	fallocate = pposix.fallocate or fallocate;
0dc9e6c128c3 util.datamanager: Make the util.pposix dependency optional.
Waqas Hussain <waqas20@gmail.com>
parents: 5103
diff changeset
    44
end);
5045
4ba6940deed0 util.datamanager: Use pposix.fallocate() to make sure appends succeed. Also add a fallback fallocate()
Kim Alvefur <zash@zash.se>
parents: 5038
diff changeset
    45
0
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    46
module "datamanager"
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    47
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    48
---- utils -----
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    49
local encode, decode;
2444
267d6482bac6 util.datamanager: Use pposix.mkdir if available
Matthew Wild <mwild1@gmail.com>
parents: 2328
diff changeset
    50
do
0
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    51
	local urlcodes = setmetatable({}, { __index = function (t, k) t[k] = char(tonumber("0x"..k)); return t[k]; end });
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    52
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    53
	decode = function (s)
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    54
		return s and (s:gsub("+", " "):gsub("%%([a-fA-F0-9][a-fA-F0-9])", urlcodes));
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    55
	end
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    56
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    57
	encode = function (s)
628
3712d36b6d25 Fixed URL encoding to generate %0x instead of %x
Waqas Hussain <waqas20@gmail.com>
parents: 615
diff changeset
    58
		return s and (s:gsub("%W", function (c) return format("%%%02x", c:byte()); end));
0
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    59
	end
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    60
end
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    61
643
8ff454831f7d Moved directory auto-creation to datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 628
diff changeset
    62
local _mkdir = {};
8ff454831f7d Moved directory auto-creation to datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 628
diff changeset
    63
local function mkdir(path)
8ff454831f7d Moved directory auto-creation to datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 628
diff changeset
    64
	path = path:gsub("/", path_separator); -- TODO as an optimization, do this during path creation rather than here
8ff454831f7d Moved directory auto-creation to datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 628
diff changeset
    65
	if not _mkdir[path] then
2444
267d6482bac6 util.datamanager: Use pposix.mkdir if available
Matthew Wild <mwild1@gmail.com>
parents: 2328
diff changeset
    66
		raw_mkdir(path);
643
8ff454831f7d Moved directory auto-creation to datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 628
diff changeset
    67
		_mkdir[path] = true;
8ff454831f7d Moved directory auto-creation to datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 628
diff changeset
    68
	end
8ff454831f7d Moved directory auto-creation to datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 628
diff changeset
    69
	return path;
8ff454831f7d Moved directory auto-creation to datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 628
diff changeset
    70
end
8ff454831f7d Moved directory auto-creation to datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 628
diff changeset
    71
4108
e3e3aa286334 util.datamanager: Handle gracefully the lack of prosody.paths.data
Matthew Wild <mwild1@gmail.com>
parents: 4093
diff changeset
    72
local data_path = (prosody and prosody.paths and prosody.paths.data) or ".";
1381
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    73
local callbacks = {};
643
8ff454831f7d Moved directory auto-creation to datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 628
diff changeset
    74
0
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    75
------- API -------------
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
    76
452
613c5c6bdce4 Added option core.data_path
Waqas Hussain <waqas20@gmail.com>
parents: 267
diff changeset
    77
function set_data_path(path)
1097
c5b33640a5f0 util.datamanager: Lower log level of 'Setting data path' to 'debug'
Matthew Wild <mwild1@gmail.com>
parents: 932
diff changeset
    78
	log("debug", "Setting data path to: %s", path);
452
613c5c6bdce4 Added option core.data_path
Waqas Hussain <waqas20@gmail.com>
parents: 267
diff changeset
    79
	data_path = path;
613c5c6bdce4 Added option core.data_path
Waqas Hussain <waqas20@gmail.com>
parents: 267
diff changeset
    80
end
1381
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    81
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    82
local function callback(username, host, datastore, data)
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    83
	for _, f in ipairs(callbacks) do
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    84
		username, host, datastore, data = f(username, host, datastore, data);
1462
44780b856ce7 datamanager: Fixed incorrect callback result checking
Waqas Hussain <waqas20@gmail.com>
parents: 1381
diff changeset
    85
		if username == false then break; end
1381
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    86
	end
4452
7de17ca4de14 util/datamanager: Use package.config to figure out directory seperator
James Callahan <james@chatid.com>
parents: 4112
diff changeset
    87
1381
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    88
	return username, host, datastore, data;
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    89
end
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    90
function add_callback(func)
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    91
	if not callbacks[func] then -- Would you really want to set the same callback more than once?
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    92
		callbacks[func] = true;
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    93
		callbacks[#callbacks+1] = func;
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    94
		return true;
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    95
	end
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    96
end
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    97
function remove_callback(func)
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    98
	if callbacks[func] then
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
    99
		for i, f in ipairs(callbacks) do
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
   100
			if f == func then
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
   101
				callbacks[i] = nil;
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
   102
				callbacks[f] = nil;
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
   103
				return true;
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
   104
			end
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
   105
		end
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
   106
	end
932
1ed3e5fe165a Added: datamanager: Allow a callback to be installed which selectively prevents disk writes
Waqas Hussain <waqas20@gmail.com>
parents: 915
diff changeset
   107
end
452
613c5c6bdce4 Added option core.data_path
Waqas Hussain <waqas20@gmail.com>
parents: 267
diff changeset
   108
643
8ff454831f7d Moved directory auto-creation to datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 628
diff changeset
   109
function getpath(username, host, datastore, ext, create)
247
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   110
	ext = ext or "dat";
2328
2804d81206d8 util.datamanager: Store data stores with no host in '_global' folder
Matthew Wild <mwild1@gmail.com>
parents: 2159
diff changeset
   111
	host = (host and encode(host)) or "_global";
643
8ff454831f7d Moved directory auto-creation to datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 628
diff changeset
   112
	username = username and encode(username);
84
d0a0bac6815e Added: Datastore support for hosts and global data in addition to users
Waqas Hussain <waqas20@gmail.com>
parents: 0
diff changeset
   113
	if username then
643
8ff454831f7d Moved directory auto-creation to datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 628
diff changeset
   114
		if create then mkdir(mkdir(mkdir(data_path).."/"..host).."/"..datastore); end
8ff454831f7d Moved directory auto-creation to datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 628
diff changeset
   115
		return format("%s/%s/%s/%s.%s", data_path, host, datastore, username, ext);
5243
07e8256efcda util.datamanager: Remove dead code path
Kim Alvefur <zash@zash.se>
parents: 5153
diff changeset
   116
	else
643
8ff454831f7d Moved directory auto-creation to datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 628
diff changeset
   117
		if create then mkdir(mkdir(data_path).."/"..host); end
8ff454831f7d Moved directory auto-creation to datamanager
Waqas Hussain <waqas20@gmail.com>
parents: 628
diff changeset
   118
		return format("%s/%s/%s.%s", data_path, host, datastore, ext);
84
d0a0bac6815e Added: Datastore support for hosts and global data in addition to users
Waqas Hussain <waqas20@gmail.com>
parents: 0
diff changeset
   119
	end
0
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
   120
end
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
   121
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
   122
function load(username, host, datastore)
5021
85b2689dbcfe Eliminate direct setfenv usage
Florian Zeitz <florob@babelmonkeys.de>
parents: 4452
diff changeset
   123
	local data, ret = envloadfile(getpath(username, host, datastore), {});
117
8e5c5e6a3240 Fixed: datamanager.store and datamanager.load could crash when username or host arguments were nil. (useful for server specific and global data).
Waqas Hussain <waqas20@gmail.com>
parents: 88
diff changeset
   124
	if not data then
3086
931acb1188b1 util.datamanager: When failing to load a file, and the file exists, return nil, error.
Waqas Hussain <waqas20@gmail.com>
parents: 2925
diff changeset
   125
		local mode = lfs.attributes(getpath(username, host, datastore), "mode");
931acb1188b1 util.datamanager: When failing to load a file, and the file exists, return nil, error.
Waqas Hussain <waqas20@gmail.com>
parents: 2925
diff changeset
   126
		if not mode then
4993
5243b74a4cbb Hopefully inert commit to clean up logging across a number of modules, removing all cases of concatenation when building log messages
Matthew Wild <mwild1@gmail.com>
parents: 4452
diff changeset
   127
			log("debug", "Assuming empty %s storage ('%s') for user: %s@%s", datastore, ret, username or "nil", host or "nil");
3086
931acb1188b1 util.datamanager: When failing to load a file, and the file exists, return nil, error.
Waqas Hussain <waqas20@gmail.com>
parents: 2925
diff changeset
   128
			return nil;
931acb1188b1 util.datamanager: When failing to load a file, and the file exists, return nil, error.
Waqas Hussain <waqas20@gmail.com>
parents: 2925
diff changeset
   129
		else -- file exists, but can't be read
931acb1188b1 util.datamanager: When failing to load a file, and the file exists, return nil, error.
Waqas Hussain <waqas20@gmail.com>
parents: 2925
diff changeset
   130
			-- TODO more detailed error checking and logging?
4993
5243b74a4cbb Hopefully inert commit to clean up logging across a number of modules, removing all cases of concatenation when building log messages
Matthew Wild <mwild1@gmail.com>
parents: 4452
diff changeset
   131
			log("error", "Failed to load %s storage ('%s') for user: %s@%s", datastore, ret, username or "nil", host or "nil");
3086
931acb1188b1 util.datamanager: When failing to load a file, and the file exists, return nil, error.
Waqas Hussain <waqas20@gmail.com>
parents: 2925
diff changeset
   132
			return nil, "Error reading storage";
931acb1188b1 util.datamanager: When failing to load a file, and the file exists, return nil, error.
Waqas Hussain <waqas20@gmail.com>
parents: 2925
diff changeset
   133
		end
117
8e5c5e6a3240 Fixed: datamanager.store and datamanager.load could crash when username or host arguments were nil. (useful for server specific and global data).
Waqas Hussain <waqas20@gmail.com>
parents: 88
diff changeset
   134
	end
5021
85b2689dbcfe Eliminate direct setfenv usage
Florian Zeitz <florob@babelmonkeys.de>
parents: 4452
diff changeset
   135
0
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
   136
	local success, ret = pcall(data);
117
8e5c5e6a3240 Fixed: datamanager.store and datamanager.load could crash when username or host arguments were nil. (useful for server specific and global data).
Waqas Hussain <waqas20@gmail.com>
parents: 88
diff changeset
   137
	if not success then
4993
5243b74a4cbb Hopefully inert commit to clean up logging across a number of modules, removing all cases of concatenation when building log messages
Matthew Wild <mwild1@gmail.com>
parents: 4452
diff changeset
   138
		log("error", "Unable to load %s storage ('%s') for user: %s@%s", datastore, ret, username or "nil", host or "nil");
3086
931acb1188b1 util.datamanager: When failing to load a file, and the file exists, return nil, error.
Waqas Hussain <waqas20@gmail.com>
parents: 2925
diff changeset
   139
		return nil, "Error reading storage";
117
8e5c5e6a3240 Fixed: datamanager.store and datamanager.load could crash when username or host arguments were nil. (useful for server specific and global data).
Waqas Hussain <waqas20@gmail.com>
parents: 88
diff changeset
   140
	end
0
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
   141
	return ret;
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
   142
end
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
   143
5049
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   144
local function atomic_store(filename, data)
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   145
	local scratch = filename.."~";
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   146
	local f, ok, msg;
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   147
	repeat
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   148
		f, msg = io_open(scratch, "w");
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   149
		if not f then break end
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   150
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   151
		ok, msg = f:write(data);
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   152
		if not ok then break end
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   153
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   154
		ok, msg = f:close();
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   155
		if not ok then break end
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   156
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   157
		return os_rename(scratch, filename);
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   158
	until false;
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   159
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   160
	-- Cleanup
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   161
	if f then f:close(); end
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   162
	os_remove(scratch);
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   163
	return nil, msg;
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   164
end
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   165
5065
acfaf771f10e util.datamanager: Don't use os.rename on non-POSIX. It doesn't overwrite exisitng files on Windows.
Waqas Hussain <waqas20@gmail.com>
parents: 5057
diff changeset
   166
if prosody.platform ~= "posix" then
acfaf771f10e util.datamanager: Don't use os.rename on non-POSIX. It doesn't overwrite exisitng files on Windows.
Waqas Hussain <waqas20@gmail.com>
parents: 5057
diff changeset
   167
	-- os.rename does not overwrite existing files on Windows
acfaf771f10e util.datamanager: Don't use os.rename on non-POSIX. It doesn't overwrite exisitng files on Windows.
Waqas Hussain <waqas20@gmail.com>
parents: 5057
diff changeset
   168
	-- TODO We could use Transactional NTFS on Vista and above
acfaf771f10e util.datamanager: Don't use os.rename on non-POSIX. It doesn't overwrite exisitng files on Windows.
Waqas Hussain <waqas20@gmail.com>
parents: 5057
diff changeset
   169
	function atomic_store(filename, data)
acfaf771f10e util.datamanager: Don't use os.rename on non-POSIX. It doesn't overwrite exisitng files on Windows.
Waqas Hussain <waqas20@gmail.com>
parents: 5057
diff changeset
   170
		local f, err = io_open(filename, "w");
acfaf771f10e util.datamanager: Don't use os.rename on non-POSIX. It doesn't overwrite exisitng files on Windows.
Waqas Hussain <waqas20@gmail.com>
parents: 5057
diff changeset
   171
		if not f then return f, err; end
acfaf771f10e util.datamanager: Don't use os.rename on non-POSIX. It doesn't overwrite exisitng files on Windows.
Waqas Hussain <waqas20@gmail.com>
parents: 5057
diff changeset
   172
		local ok, msg = f:write(data);
acfaf771f10e util.datamanager: Don't use os.rename on non-POSIX. It doesn't overwrite exisitng files on Windows.
Waqas Hussain <waqas20@gmail.com>
parents: 5057
diff changeset
   173
		if not ok then f:close(); return ok, msg; end
acfaf771f10e util.datamanager: Don't use os.rename on non-POSIX. It doesn't overwrite exisitng files on Windows.
Waqas Hussain <waqas20@gmail.com>
parents: 5057
diff changeset
   174
		return f:close();
acfaf771f10e util.datamanager: Don't use os.rename on non-POSIX. It doesn't overwrite exisitng files on Windows.
Waqas Hussain <waqas20@gmail.com>
parents: 5057
diff changeset
   175
	end
acfaf771f10e util.datamanager: Don't use os.rename on non-POSIX. It doesn't overwrite exisitng files on Windows.
Waqas Hussain <waqas20@gmail.com>
parents: 5057
diff changeset
   176
end
acfaf771f10e util.datamanager: Don't use os.rename on non-POSIX. It doesn't overwrite exisitng files on Windows.
Waqas Hussain <waqas20@gmail.com>
parents: 5057
diff changeset
   177
0
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
   178
function store(username, host, datastore, data)
206
e30d0e30a0ff Datamanager now deletes files with no data
Waqas Hussain <waqas20@gmail.com>
parents: 182
diff changeset
   179
	if not data then
e30d0e30a0ff Datamanager now deletes files with no data
Waqas Hussain <waqas20@gmail.com>
parents: 182
diff changeset
   180
		data = {};
e30d0e30a0ff Datamanager now deletes files with no data
Waqas Hussain <waqas20@gmail.com>
parents: 182
diff changeset
   181
	end
1381
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
   182
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
   183
	username, host, datastore, data = callback(username, host, datastore, data);
1462
44780b856ce7 datamanager: Fixed incorrect callback result checking
Waqas Hussain <waqas20@gmail.com>
parents: 1381
diff changeset
   184
	if username == false then
1381
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
   185
		return true; -- Don't save this data at all
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
   186
	end
46a58df8557d util.datamanager: Allow multiple data storage callbacks, and allow them to modify parameters
Matthew Wild <mwild1@gmail.com>
parents: 1097
diff changeset
   187
206
e30d0e30a0ff Datamanager now deletes files with no data
Waqas Hussain <waqas20@gmail.com>
parents: 182
diff changeset
   188
	-- save the datastore
5049
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   189
	local d = "return " .. serialize(data) .. ";\n";
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   190
	local ok, msg = atomic_store(getpath(username, host, datastore, nil, true), d);
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   191
	if not ok then
4993
5243b74a4cbb Hopefully inert commit to clean up logging across a number of modules, removing all cases of concatenation when building log messages
Matthew Wild <mwild1@gmail.com>
parents: 4452
diff changeset
   192
		log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil");
3108
df0df92dd58a util.datamanager: Return an error string when failing to save.
Waqas Hussain <waqas20@gmail.com>
parents: 3086
diff changeset
   193
		return nil, "Error saving to storage";
117
8e5c5e6a3240 Fixed: datamanager.store and datamanager.load could crash when username or host arguments were nil. (useful for server specific and global data).
Waqas Hussain <waqas20@gmail.com>
parents: 88
diff changeset
   194
	end
915
0fe5bf7ab81d util.datamanager: Don't delete data when first entry in table is 'false'. My favourite bug so far.
Matthew Wild <mwild1@gmail.com>
parents: 896
diff changeset
   195
	if next(data) == nil then -- try to delete empty datastore
1732
f1282fad2f99 datamanager: Fixed logging errors on deletion of datastores not owned by a user@host
Waqas Hussain <waqas20@gmail.com>
parents: 1523
diff changeset
   196
		log("debug", "Removing empty %s datastore for user %s@%s", datastore, username or "nil", host or "nil");
206
e30d0e30a0ff Datamanager now deletes files with no data
Waqas Hussain <waqas20@gmail.com>
parents: 182
diff changeset
   197
		os_remove(getpath(username, host, datastore));
e30d0e30a0ff Datamanager now deletes files with no data
Waqas Hussain <waqas20@gmail.com>
parents: 182
diff changeset
   198
	end
e30d0e30a0ff Datamanager now deletes files with no data
Waqas Hussain <waqas20@gmail.com>
parents: 182
diff changeset
   199
	-- we write data even when we are deleting because lua doesn't have a
e30d0e30a0ff Datamanager now deletes files with no data
Waqas Hussain <waqas20@gmail.com>
parents: 182
diff changeset
   200
	-- platform independent way of checking for non-exisitng files
0
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
   201
	return true;
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
   202
end
3e3171b59028 First commit, where do you want to go tomorrow?
matthew
parents:
diff changeset
   203
247
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   204
function list_append(username, host, datastore, data)
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   205
	if not data then return; end
1462
44780b856ce7 datamanager: Fixed incorrect callback result checking
Waqas Hussain <waqas20@gmail.com>
parents: 1381
diff changeset
   206
	if callback(username, host, datastore) == false then return true; end
247
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   207
	-- save the datastore
5066
4be7093edde9 util.datamanager: Try to open in read+write mode, then retry with write mode if that fails (usually because it doesn't exist)
Kim Alvefur <zash@zash.se>
parents: 5057
diff changeset
   208
	local f, msg = io_open(getpath(username, host, datastore, "list", true), "r+");
4be7093edde9 util.datamanager: Try to open in read+write mode, then retry with write mode if that fails (usually because it doesn't exist)
Kim Alvefur <zash@zash.se>
parents: 5057
diff changeset
   209
	if not f then
4be7093edde9 util.datamanager: Try to open in read+write mode, then retry with write mode if that fails (usually because it doesn't exist)
Kim Alvefur <zash@zash.se>
parents: 5057
diff changeset
   210
		f, msg = io_open(getpath(username, host, datastore, "list", true), "w");
4be7093edde9 util.datamanager: Try to open in read+write mode, then retry with write mode if that fails (usually because it doesn't exist)
Kim Alvefur <zash@zash.se>
parents: 5057
diff changeset
   211
	end
247
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   212
	if not f then
4993
5243b74a4cbb Hopefully inert commit to clean up logging across a number of modules, removing all cases of concatenation when building log messages
Matthew Wild <mwild1@gmail.com>
parents: 4452
diff changeset
   213
		log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil");
247
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   214
		return;
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   215
	end
5045
4ba6940deed0 util.datamanager: Use pposix.fallocate() to make sure appends succeed. Also add a fallback fallocate()
Kim Alvefur <zash@zash.se>
parents: 5038
diff changeset
   216
	local data = "item(" ..  serialize(data) .. ");\n";
4ba6940deed0 util.datamanager: Use pposix.fallocate() to make sure appends succeed. Also add a fallback fallocate()
Kim Alvefur <zash@zash.se>
parents: 5038
diff changeset
   217
	local pos = f:seek("end");
4ba6940deed0 util.datamanager: Use pposix.fallocate() to make sure appends succeed. Also add a fallback fallocate()
Kim Alvefur <zash@zash.se>
parents: 5038
diff changeset
   218
	local ok, msg = fallocate(f, pos, #data);
4ba6940deed0 util.datamanager: Use pposix.fallocate() to make sure appends succeed. Also add a fallback fallocate()
Kim Alvefur <zash@zash.se>
parents: 5038
diff changeset
   219
	f:seek("set", pos);
4ba6940deed0 util.datamanager: Use pposix.fallocate() to make sure appends succeed. Also add a fallback fallocate()
Kim Alvefur <zash@zash.se>
parents: 5038
diff changeset
   220
	if ok then
4ba6940deed0 util.datamanager: Use pposix.fallocate() to make sure appends succeed. Also add a fallback fallocate()
Kim Alvefur <zash@zash.se>
parents: 5038
diff changeset
   221
		f:write(data);
4ba6940deed0 util.datamanager: Use pposix.fallocate() to make sure appends succeed. Also add a fallback fallocate()
Kim Alvefur <zash@zash.se>
parents: 5038
diff changeset
   222
	else
4ba6940deed0 util.datamanager: Use pposix.fallocate() to make sure appends succeed. Also add a fallback fallocate()
Kim Alvefur <zash@zash.se>
parents: 5038
diff changeset
   223
		log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil");
4ba6940deed0 util.datamanager: Use pposix.fallocate() to make sure appends succeed. Also add a fallback fallocate()
Kim Alvefur <zash@zash.se>
parents: 5038
diff changeset
   224
		return ok, msg;
4ba6940deed0 util.datamanager: Use pposix.fallocate() to make sure appends succeed. Also add a fallback fallocate()
Kim Alvefur <zash@zash.se>
parents: 5038
diff changeset
   225
	end
247
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   226
	f:close();
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   227
	return true;
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   228
end
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   229
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   230
function list_store(username, host, datastore, data)
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   231
	if not data then
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   232
		data = {};
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   233
	end
1462
44780b856ce7 datamanager: Fixed incorrect callback result checking
Waqas Hussain <waqas20@gmail.com>
parents: 1381
diff changeset
   234
	if callback(username, host, datastore) == false then return true; end
247
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   235
	-- save the datastore
5049
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   236
	local d = {};
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   237
	for _, item in ipairs(data) do
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   238
		d[#d+1] = "item(" .. serialize(item) .. ");\n";
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   239
	end
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   240
	local ok, msg = atomic_store(getpath(username, host, datastore, "list", true), t_concat(d));
5d685f123332 util.datamanager: Write to a temporary file and atomically move it into place
Kim Alvefur <zash@zash.se>
parents: 5045
diff changeset
   241
	if not ok then
4993
5243b74a4cbb Hopefully inert commit to clean up logging across a number of modules, removing all cases of concatenation when building log messages
Matthew Wild <mwild1@gmail.com>
parents: 4452
diff changeset
   242
		log("error", "Unable to write to %s storage ('%s') for user: %s@%s", datastore, msg, username or "nil", host or "nil");
247
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   243
		return;
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   244
	end
915
0fe5bf7ab81d util.datamanager: Don't delete data when first entry in table is 'false'. My favourite bug so far.
Matthew Wild <mwild1@gmail.com>
parents: 896
diff changeset
   245
	if next(data) == nil then -- try to delete empty datastore
1732
f1282fad2f99 datamanager: Fixed logging errors on deletion of datastores not owned by a user@host
Waqas Hussain <waqas20@gmail.com>
parents: 1523
diff changeset
   246
		log("debug", "Removing empty %s datastore for user %s@%s", datastore, username or "nil", host or "nil");
247
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   247
		os_remove(getpath(username, host, datastore, "list"));
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   248
	end
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   249
	-- we write data even when we are deleting because lua doesn't have a
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   250
	-- platform independent way of checking for non-exisitng files
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   251
	return true;
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   252
end
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   253
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   254
function list_load(username, host, datastore)
5021
85b2689dbcfe Eliminate direct setfenv usage
Florian Zeitz <florob@babelmonkeys.de>
parents: 4452
diff changeset
   255
	local items = {};
85b2689dbcfe Eliminate direct setfenv usage
Florian Zeitz <florob@babelmonkeys.de>
parents: 4452
diff changeset
   256
	local data, ret = envloadfile(getpath(username, host, datastore, "list"), {item = function(i) t_insert(items, i); end});
247
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   257
	if not data then
3722
f15b6ed967b7 util.datamanager: When failing to load a list file, and the file exists, log an error, and return nil, error.
Waqas Hussain <waqas20@gmail.com>
parents: 3108
diff changeset
   258
		local mode = lfs.attributes(getpath(username, host, datastore, "list"), "mode");
f15b6ed967b7 util.datamanager: When failing to load a list file, and the file exists, log an error, and return nil, error.
Waqas Hussain <waqas20@gmail.com>
parents: 3108
diff changeset
   259
		if not mode then
4993
5243b74a4cbb Hopefully inert commit to clean up logging across a number of modules, removing all cases of concatenation when building log messages
Matthew Wild <mwild1@gmail.com>
parents: 4452
diff changeset
   260
			log("debug", "Assuming empty %s storage ('%s') for user: %s@%s", datastore, ret, username or "nil", host or "nil");
3722
f15b6ed967b7 util.datamanager: When failing to load a list file, and the file exists, log an error, and return nil, error.
Waqas Hussain <waqas20@gmail.com>
parents: 3108
diff changeset
   261
			return nil;
f15b6ed967b7 util.datamanager: When failing to load a list file, and the file exists, log an error, and return nil, error.
Waqas Hussain <waqas20@gmail.com>
parents: 3108
diff changeset
   262
		else -- file exists, but can't be read
f15b6ed967b7 util.datamanager: When failing to load a list file, and the file exists, log an error, and return nil, error.
Waqas Hussain <waqas20@gmail.com>
parents: 3108
diff changeset
   263
			-- TODO more detailed error checking and logging?
4993
5243b74a4cbb Hopefully inert commit to clean up logging across a number of modules, removing all cases of concatenation when building log messages
Matthew Wild <mwild1@gmail.com>
parents: 4452
diff changeset
   264
			log("error", "Failed to load %s storage ('%s') for user: %s@%s", datastore, ret, username or "nil", host or "nil");
3722
f15b6ed967b7 util.datamanager: When failing to load a list file, and the file exists, log an error, and return nil, error.
Waqas Hussain <waqas20@gmail.com>
parents: 3108
diff changeset
   265
			return nil, "Error reading storage";
f15b6ed967b7 util.datamanager: When failing to load a list file, and the file exists, log an error, and return nil, error.
Waqas Hussain <waqas20@gmail.com>
parents: 3108
diff changeset
   266
		end
247
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   267
	end
5021
85b2689dbcfe Eliminate direct setfenv usage
Florian Zeitz <florob@babelmonkeys.de>
parents: 4452
diff changeset
   268
247
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   269
	local success, ret = pcall(data);
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   270
	if not success then
4993
5243b74a4cbb Hopefully inert commit to clean up logging across a number of modules, removing all cases of concatenation when building log messages
Matthew Wild <mwild1@gmail.com>
parents: 4452
diff changeset
   271
		log("error", "Unable to load %s storage ('%s') for user: %s@%s", datastore, ret, username or "nil", host or "nil");
3723
72a917d910a4 util.datamanager: Return an error string when pcall fails on a loaded list file.
Waqas Hussain <waqas20@gmail.com>
parents: 3722
diff changeset
   272
		return nil, "Error reading storage";
247
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   273
	end
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   274
	return items;
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   275
end
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   276
5130
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   277
local type_map = {
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   278
	keyval = "dat";
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   279
	list = "list";
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   280
}
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   281
5153
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   282
function users(host, store, typ)
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   283
	typ = type_map[typ or "keyval"];
5250
6d8ec8c90240 util.datamanager: Don't escape the name of a store
Kim Alvefur <zash@zash.se>
parents: 5244
diff changeset
   284
	local store_dir = format("%s/%s/%s", data_path, encode(host), store);
5153
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   285
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   286
	local mode, err = lfs.attributes(store_dir, "mode");
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   287
	if not mode then
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   288
		return function() log("debug", err or (store_dir .. " does not exist")) end
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   289
	end
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   290
	local next, state = lfs.dir(store_dir);
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   291
	return function(state)
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   292
		for node in next, state do
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   293
			local file, ext = node:match("^(.*)%.([dalist]+)$");
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   294
			if file and ext == typ then
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   295
				return decode(file);
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   296
			end
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   297
		end
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   298
	end, state;
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   299
end
688aeac0012a mod_storage_internal, datamanager: Add support for iterating over users with data in a store
Kim Alvefur <zash@zash.se>
parents: 5130
diff changeset
   300
5130
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   301
function stores(username, host, typ)
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   302
	typ = type_map[typ or "keyval"];
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   303
	local store_dir = format("%s/%s/", data_path, encode(host));
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   304
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   305
	local mode, err = lfs.attributes(store_dir, "mode");
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   306
	if not mode then
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   307
		return function() log("debug", err or (store_dir .. " does not exist")) end
5032
c40ea227f8af util.datamanager: Add function for listing stores
Kim Alvefur <zash@zash.se>
parents: 5024
diff changeset
   308
	end
5130
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   309
	local next, state = lfs.dir(store_dir);
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   310
	return function(state)
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   311
		for node in next, state do
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   312
			if not node:match"^%." then
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   313
				if username == true then
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   314
					if lfs.attributes(store_dir..node, "mode") == "directory" then
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   315
						return decode(node);
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   316
					end
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   317
				elseif username then
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   318
					local store = decode(node)
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   319
					if lfs.attributes(getpath(username, host, store, typ), "mode") then
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   320
						return store;
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   321
					end
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   322
				elseif lfs.attributes(node, "mode") == "file" then
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   323
					local file, ext = node:match("^(.*)%.([dalist]+)$");
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   324
					if ext == typ then
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   325
						return decode(file)
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   326
					end
5032
c40ea227f8af util.datamanager: Add function for listing stores
Kim Alvefur <zash@zash.se>
parents: 5024
diff changeset
   327
				end
c40ea227f8af util.datamanager: Add function for listing stores
Kim Alvefur <zash@zash.se>
parents: 5024
diff changeset
   328
			end
c40ea227f8af util.datamanager: Add function for listing stores
Kim Alvefur <zash@zash.se>
parents: 5024
diff changeset
   329
		end
5130
051d352ed03c storagemanager, datamanager, mod_storage_{internal,sql}: Replace list_stores() with an iterator version
Kim Alvefur <zash@zash.se>
parents: 5118
diff changeset
   330
	end, state;
5032
c40ea227f8af util.datamanager: Add function for listing stores
Kim Alvefur <zash@zash.se>
parents: 5024
diff changeset
   331
end
c40ea227f8af util.datamanager: Add function for listing stores
Kim Alvefur <zash@zash.se>
parents: 5024
diff changeset
   332
5103
5a1488369c35 util.datamanager: Ignore errors if the file is gone after removing it
Kim Alvefur <zash@zash.se>
parents: 5095
diff changeset
   333
local function do_remove(path)
5a1488369c35 util.datamanager: Ignore errors if the file is gone after removing it
Kim Alvefur <zash@zash.se>
parents: 5095
diff changeset
   334
	local ok, err = os_remove(path);
5a1488369c35 util.datamanager: Ignore errors if the file is gone after removing it
Kim Alvefur <zash@zash.se>
parents: 5095
diff changeset
   335
	if not ok and lfs.attributes(path, "mode") then
5a1488369c35 util.datamanager: Ignore errors if the file is gone after removing it
Kim Alvefur <zash@zash.se>
parents: 5095
diff changeset
   336
		return ok, err;
5a1488369c35 util.datamanager: Ignore errors if the file is gone after removing it
Kim Alvefur <zash@zash.se>
parents: 5095
diff changeset
   337
	end
5a1488369c35 util.datamanager: Ignore errors if the file is gone after removing it
Kim Alvefur <zash@zash.se>
parents: 5095
diff changeset
   338
	return true
5a1488369c35 util.datamanager: Ignore errors if the file is gone after removing it
Kim Alvefur <zash@zash.se>
parents: 5095
diff changeset
   339
end
5a1488369c35 util.datamanager: Ignore errors if the file is gone after removing it
Kim Alvefur <zash@zash.se>
parents: 5095
diff changeset
   340
5038
242c62ff8e77 util.datamanager: Add function for removing all data belonging to a user
Kim Alvefur <zash@zash.se>
parents: 5032
diff changeset
   341
function purge(username, host)
242c62ff8e77 util.datamanager: Add function for removing all data belonging to a user
Kim Alvefur <zash@zash.se>
parents: 5032
diff changeset
   342
	local host_dir = format("%s/%s/", data_path, encode(host));
5095
dddbcd62183a util.datamanager: Collect errors when deleting all stores of a user, but ignore "no such file"
Kim Alvefur <zash@zash.se>
parents: 5069
diff changeset
   343
	local errs = {};
5038
242c62ff8e77 util.datamanager: Add function for removing all data belonging to a user
Kim Alvefur <zash@zash.se>
parents: 5032
diff changeset
   344
	for file in lfs.dir(host_dir) do
242c62ff8e77 util.datamanager: Add function for removing all data belonging to a user
Kim Alvefur <zash@zash.se>
parents: 5032
diff changeset
   345
		if lfs.attributes(host_dir..file, "mode") == "directory" then
242c62ff8e77 util.datamanager: Add function for removing all data belonging to a user
Kim Alvefur <zash@zash.se>
parents: 5032
diff changeset
   346
			local store = decode(file);
5103
5a1488369c35 util.datamanager: Ignore errors if the file is gone after removing it
Kim Alvefur <zash@zash.se>
parents: 5095
diff changeset
   347
			local ok, err = do_remove(getpath(username, host, store));
5a1488369c35 util.datamanager: Ignore errors if the file is gone after removing it
Kim Alvefur <zash@zash.se>
parents: 5095
diff changeset
   348
			if not ok then errs[#errs+1] = err; end
5a1488369c35 util.datamanager: Ignore errors if the file is gone after removing it
Kim Alvefur <zash@zash.se>
parents: 5095
diff changeset
   349
5a1488369c35 util.datamanager: Ignore errors if the file is gone after removing it
Kim Alvefur <zash@zash.se>
parents: 5095
diff changeset
   350
			local ok, err = do_remove(getpath(username, host, store, "list"));
5a1488369c35 util.datamanager: Ignore errors if the file is gone after removing it
Kim Alvefur <zash@zash.se>
parents: 5095
diff changeset
   351
			if not ok then errs[#errs+1] = err; end
5038
242c62ff8e77 util.datamanager: Add function for removing all data belonging to a user
Kim Alvefur <zash@zash.se>
parents: 5032
diff changeset
   352
		end
242c62ff8e77 util.datamanager: Add function for removing all data belonging to a user
Kim Alvefur <zash@zash.se>
parents: 5032
diff changeset
   353
	end
5095
dddbcd62183a util.datamanager: Collect errors when deleting all stores of a user, but ignore "no such file"
Kim Alvefur <zash@zash.se>
parents: 5069
diff changeset
   354
	return #errs == 0, t_concat(errs, ", ");
5038
242c62ff8e77 util.datamanager: Add function for removing all data belonging to a user
Kim Alvefur <zash@zash.se>
parents: 5032
diff changeset
   355
end
242c62ff8e77 util.datamanager: Add function for removing all data belonging to a user
Kim Alvefur <zash@zash.se>
parents: 5032
diff changeset
   356
247
681b29aa134f Added support for storing (and removing), loading and appending to lists of data to datamanager (for supporting offline messages)
Waqas Hussain <waqas20@gmail.com>
parents: 206
diff changeset
   357
return _M;