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 |