new storage and migration

This commit is contained in:
NatureFreshMilk 2019-02-27 08:20:09 +01:00
parent 2431495c99
commit 385d5cd4b7
8 changed files with 126 additions and 79 deletions

View File

@ -1,4 +1,3 @@
mail.messages = {}
mail.registered_on_receives = {} mail.registered_on_receives = {}
function mail.register_on_receive(func) function mail.register_on_receive(func)
@ -12,15 +11,16 @@ function mail.send(src, dst, subject, body)
minetest.log("action", "[mail] '" .. src .. "' sends mail to '" .. dst .. minetest.log("action", "[mail] '" .. src .. "' sends mail to '" .. dst ..
"' with subject '" .. subject .. "' and body: '" .. body .. "'") "' with subject '" .. subject .. "' and body: '" .. body .. "'")
mail.messages[dst] = mail.messages[dst] or {} local messages = mail.getMessages(dst)
table.insert(mail.messages[dst], 1, { table.insert(messages, 1, {
unread = true, unread = true,
sender = src, sender = src,
subject = subject, subject = subject,
body = body, body = body,
time = os.time(), time = os.time(),
}) })
mail.setMessages(dst, messages)
for _, player in ipairs(minetest.get_connected_players()) do for _, player in ipairs(minetest.get_connected_players()) do
local name = player:get_player_name() local name = player:get_player_name()

67
gui.lua
View File

@ -40,10 +40,10 @@ end
function mail.show_inbox(name) function mail.show_inbox(name)
local formspec = { mail.inbox_formspec } local formspec = { mail.inbox_formspec }
mail.messages[name] = mail.messages[name] or {} local messages = mail.getMessages(name)
if mail.messages[name][1] then if messages[1] then
for idx, message in ipairs(mail.messages[name]) do for idx, message in ipairs(messages) do
if message.unread then if message.unread then
formspec[#formspec + 1] = ",#FFD700" formspec[#formspec + 1] = ",#FFD700"
else else
@ -76,7 +76,8 @@ function mail.show_inbox(name)
end end
function mail.show_message(name, msgnumber) function mail.show_message(name, msgnumber)
local message = mail.messages[name][msgnumber] local messages = mail.getMessages(name)
local message = messages[msgnumber]
local formspec = [[ local formspec = [[
size[8,7.2] size[8,7.2]
button[7,0;1,0.5;back;X] button[7,0;1,0.5;back;X]
@ -124,78 +125,92 @@ function mail.handle_receivefields(player, formname, fields)
minetest.after(0.5, function() minetest.after(0.5, function()
mail.show_inbox(player:get_player_name()) mail.show_inbox(player:get_player_name())
end) end)
elseif formname == "mail:inbox" then elseif formname == "mail:inbox" then
local name = player:get_player_name() local name = player:get_player_name()
local messages = mail.getMessages(name)
if fields.messages then if fields.messages then
local evt = minetest.explode_table_event(fields.messages) local evt = minetest.explode_table_event(fields.messages)
selected_message_idxs[name] = evt.row - 1 selected_message_idxs[name] = evt.row - 1
if evt.type == "DCL" and mail.messages[name][selected_message_idxs[name]] then if evt.type == "DCL" and messages[selected_message_idxs[name]] then
mail.messages[name][selected_message_idxs[name]].unread = false messages[selected_message_idxs[name]].unread = false
mail.show_message(name, selected_message_idxs[name]) mail.show_message(name, selected_message_idxs[name])
end end
mail.setMessages(name, messages)
return true return true
end end
if fields.read then if fields.read then
if mail.messages[name][selected_message_idxs[name]] then if messages[selected_message_idxs[name]] then
mail.messages[name][selected_message_idxs[name]].unread = false messages[selected_message_idxs[name]].unread = false
mail.show_message(name, selected_message_idxs[name]) mail.show_message(name, selected_message_idxs[name])
end end
elseif fields.delete then elseif fields.delete then
if mail.messages[name][selected_message_idxs[name]] then if messages[[selected_message_idxs[name]] then
table.remove(mail.messages[name], selected_message_idxs[name]) table.remove(messages, selected_message_idxs[name])
end end
mail.show_inbox(name) mail.show_inbox(name)
mail.save() elseif fields.reply and messages[selected_message_idxs[name]] then
elseif fields.reply and mail.messages[name][selected_message_idxs[name]] then local message = messages[selected_message_idxs[name]]
local message = mail.messages[name][selected_message_idxs[name]]
local replyfooter = "Type your reply here.\n\n--Original message follows--\n" ..message.body local replyfooter = "Type your reply here.\n\n--Original message follows--\n" ..message.body
mail.show_compose(name, message.sender, "Re: "..message.subject,replyfooter) mail.show_compose(name, message.sender, "Re: "..message.subject,replyfooter)
elseif fields.forward and mail.messages[name][selected_message_idxs[name]] then
local message = mail.messages[name][selected_message_idxs[name]] elseif fields.forward and messages[selected_message_idxs[name]] then
local message = messages[selected_message_idxs[name]]
local fwfooter = "Type your message here.\n\n--Original message follows--\n" ..message.body local fwfooter = "Type your message here.\n\n--Original message follows--\n" ..message.body
mail.show_compose(name, "", "Fw: "..message.subject, fwfooter) mail.show_compose(name, "", "Fw: "..message.subject, fwfooter)
elseif fields.markread then elseif fields.markread then
if mail.messages[name][selected_message_idxs[name]] then if messages[selected_message_idxs[name]] then
mail.messages[name][selected_message_idxs[name]].unread = false messages[selected_message_idxs[name]].unread = false
end end
mail.show_inbox(name) mail.show_inbox(name)
mail.save()
elseif fields.markunread then elseif fields.markunread then
if mail.messages[name][selected_message_idxs[name]] then if messages[selected_message_idxs[name]] then
mail.messages[name][selected_message_idxs[name]].unread = true messages[selected_message_idxs[name]].unread = true
end end
mail.show_inbox(name) mail.show_inbox(name)
mail.save()
elseif fields.new then elseif fields.new then
mail.show_compose(name,"","","Type your message here.") mail.show_compose(name,"","","Type your message here.")
elseif fields.quit then elseif fields.quit then
if minetest.get_modpath("unified_inventory") then if minetest.get_modpath("unified_inventory") then
unified_inventory.set_inventory_formspec(player, "craft") unified_inventory.set_inventory_formspec(player, "craft")
end end
elseif fields.about then elseif fields.about then
mail.show_about(name) mail.show_about(name)
end end
mail.setMessages(name, messages)
return true return true
elseif formname == "mail:message" then elseif formname == "mail:message" then
local name = player:get_player_name() local name = player:get_player_name()
local messages = mail.getMessages(name)
if fields.back then if fields.back then
mail.show_inbox(name) mail.show_inbox(name)
elseif fields.reply then elseif fields.reply then
local message = mail.messages[name][selected_message_idxs[name]] local message = messages[selected_message_idxs[name]]
local replyfooter = "Type your reply here.\n\n--Original message follows--\n" ..message.body local replyfooter = "Type your reply here.\n\n--Original message follows--\n" ..message.body
mail.show_compose(name, message.sender, "Re: "..message.subject, replyfooter) mail.show_compose(name, message.sender, "Re: "..message.subject, replyfooter)
elseif fields.forward then elseif fields.forward then
local message = mail.messages[name][selected_message_idxs[name]] local message = messages[selected_message_idxs[name]]
local fwfooter = "Type your message here.\n\n--Original message follows--\n" ..message.body local fwfooter = "Type your message here.\n\n--Original message follows--\n" ..message.body
mail.show_compose(name, "", "Fw: "..message.subject, fwfooter) mail.show_compose(name, "", "Fw: "..message.subject, fwfooter)
elseif fields.delete then elseif fields.delete then
if mail.messages[name][selected_message_idxs[name]] then if messages[selected_message_idxs[name]] then
table.remove(mail.messages[name],selected_message_idxs[name]) table.remove(messages,selected_message_idxs[name])
end end
mail.show_inbox(name) mail.show_inbox(name)
mail.save()
end end
mail.setMessages(name, messages)
return true return true
elseif formname == "mail:compose" then elseif formname == "mail:compose" then
if fields.send then if fields.send then

View File

@ -1,9 +1,12 @@
mail = {} mail = {
maildir = minetest.get_worldpath().."/mails"
}
local MP = minetest.get_modpath(minetest.get_current_modname()) local MP = minetest.get_modpath(minetest.get_current_modname())
dofile(MP .. "/chatcommands.lua") dofile(MP .. "/chatcommands.lua")
dofile(MP .. "/persistence.lua") dofile(MP .. "/migrate.lua")
dofile(MP .. "/storage.lua")
dofile(MP .. "/api.lua") dofile(MP .. "/api.lua")
dofile(MP .. "/gui.lua") dofile(MP .. "/gui.lua")
@ -29,7 +32,5 @@ if http then
mail.webmail_init(http, webmail_url, webmail_key) mail.webmail_init(http, webmail_url, webmail_key)
end end
-- migrate storage
mail.migrate()
mail.load()

24
migrate.lua Normal file
View File

@ -0,0 +1,24 @@
-- migrate from mail.db to player-file-based mailbox
mail.migrate = function()
local file = io.open(minetest.get_worldpath().."/mail.db", "r")
if file then
print("[mail] migrating to new per-player storage")
minetest.mkdir(mail.maildir)
local data = file:read("*a")
local oldmails = minetest.deserialize(data)
file:close()
for name, oldmessages in pairs(oldmails)
mail.setMessages(name, oldmessages)
end
-- rename file
print("[mail] migration done, renaming old mail.db")
os.rename(minetest.get_worldpath().."/mail.db", minetest.get_worldpath().."/mail.db.old")
end
end

View File

@ -1,13 +1,14 @@
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
minetest.after(2, function(name) minetest.after(2, function(name)
local messages = mail.getMessages(name)
local unreadflag = false local unreadflag = false
if mail.messages[name] then
for _, message in ipairs(mail.messages[name]) do for _, message in ipairs(messages) do
if message.unread then if message.unread then
unreadflag = true unreadflag = true
end
end end
end end
if unreadflag then if unreadflag then
minetest.show_formspec(name, "mail:unreadnag", minetest.show_formspec(name, "mail:unreadnag",
"size[3,2]" .. "size[3,2]" ..

View File

@ -1,32 +0,0 @@
function mail.load()
local file = io.open(minetest.get_worldpath().."/mail.db", "r")
if file then
local data = file:read("*a")
mail.messages = minetest.deserialize(data)
file:close()
end
end
function mail.save()
local file = io.open(minetest.get_worldpath().."/mail.db","w")
if file and file:write(minetest.serialize(mail.messages)) and file:close() then
return true
else
minetest.log("error","[mail] Save failed - messages may be lost!")
return false
end
end
-- save periodically
local timer = 0
minetest.register_globalstep(function(dtime)
timer = timer + dtime
if timer < 30 then
return
end
timer = 0
mail.save()
end)

31
storage.lua Normal file
View File

@ -0,0 +1,31 @@
-- TODO: maybe local cache?
function getMailFile(playername)
return mail.maildir .. "/" .. playername .. ".json"
end
mail.getMessages = function(playername)
local file = io.open(getMailFile(playername),"w", "r")
local messages = {}
if file then
local json = file:read("*a")
messages = minetest.parse_json(json) or {}
file:close()
end
return messages
end
mail.setMessages = function(playername, messages)
local file = io.open(getMailFile(playername),"w")
local json = minetest.write_json(messages)
if file and file:write(json) and file:close() then
return true
else
minetest.log("error","[mail] Save failed - messages may be lost!")
return false
end
end

View File

@ -50,32 +50,39 @@ end
-- get player messages request from webmail -- get player messages request from webmail
local function get_player_messages_handler(playername) local function get_player_messages_handler(playername)
local messages = mail.getMessages(playername)
channel.send({ channel.send({
type = "player-messages", type = "player-messages",
playername = playername, playername = playername,
data = mail.messages[playername] data = messages
}) })
end end
-- remove mail -- remove mail
local function delete_mail_handler(playername, index) local function delete_mail_handler(playername, index)
if mail.messages[playername] and mail.messages[playername][index] then local messages = mail.getMessages(playername)
table.remove(mail.messages[playername], index) if messages[index] then
table.remove(messages, index)
end end
mail.setMessages(playername, messages)
end end
-- mark mail as read -- mark mail as read
local function mark_mail_read_handler(playername, index) local function mark_mail_read_handler(playername, index)
if mail.messages[playername] and mail.messages[playername][index] then local messages = mail.getMessages(playername)
mail.messages[playername][index].unread = false if messages[index] then
messages[index].unread = false
end end
mail.setMessages(playername, messages)
end end
-- mark mail as unread -- mark mail as unread
local function mark_mail_unread_handler(playername, index) local function mark_mail_unread_handler(playername, index)
if mail.messages[playername] and mail.messages[playername][index] then local messages = mail.getMessages(playername)
mail.messages[playername][index].unread = true if messages[index] then
messages[index].unread = true
end end
mail.setMessages(playername, messages)
end end
function mail.webmail_send_hook(src,dst,subject,body) function mail.webmail_send_hook(src,dst,subject,body)