lurkcoin/core.lua

203 lines
6.5 KiB
Lua
Raw Normal View History

2019-02-22 05:15:44 +01:00
--
-- Minetest lurkcoin mod - Core
--
-- © 2019 by luk3yx
--
lurkcoin.version = 0
lurkcoin.timeout = 10
lurkcoin.exchange_rate = 1
-- Do not allow other mods to modify this, or they may be able to bypass mod
-- security restrictions!
local baseurl = 'https://nz.xeroxirc.net:7000/v2'
-- Get the username and API token
lurkcoin.server_name = minetest.settings:get('lurkcoin.username')
local token = minetest.settings:get('lurkcoin.token')
2019-02-22 05:22:17 +01:00
-- Make sure lurkcoin.server_name exists
if not lurkcoin.server_name then
lurkcoin.server_name = '<unknown>'
minetest.log('warning', 'lurkcoin has no server name set!')
end
2019-02-22 05:15:44 +01:00
-- Make sure the HTTP API exists
local http = ...
if not http then
minetest.log('warning', 'lurkcoin is not allowed to use the HTTP API! ' ..
'Please add lurkcoin to secure.http_mods in minetest.conf.')
end
2019-09-19 08:48:39 +02:00
-- This user agent is not strictly required, however I might do something
-- with the lurkcoin mod version later.
2019-02-22 05:15:44 +01:00
lurkcoin.user_agent = 'Minetest ' .. minetest.get_version().string ..
' (with lurkcoin mod v' .. tostring(lurkcoin.version) .. ')'
2019-09-19 08:48:39 +02:00
-- Download functions
2019-02-22 05:15:44 +01:00
local function get(url, data, callback)
if not data then
data = {}
elseif not http then
return callback({
completed = true,
succeeded = false,
timeout = true,
code = 500,
data = 'ERROR: The lurkcoin mod is not in secure.http_mods!'
})
2019-02-22 05:22:17 +01:00
elseif not lurkcoin.server_name or not token then
2019-02-22 05:15:44 +01:00
return callback({
completed = true,
succeeded = false,
timeout = true,
code = 401,
data = 'ERROR: The lurkcoin mod does not have (correct) ' ..
'account credentials!'
})
end
data.name = lurkcoin.server_name
data.token = token
-- Minetest eats any non-200 code.
data.force_200 = '200'
http.fetch({
url = baseurl .. '/' .. url,
timeout = lurkcoin.timeout,
post_data = data,
user_agent = lurkcoin.user_agent,
}, function(res)
if res.timeout then
minetest.log('warning', '[lurkcoin] Could not connect to lurkcoin!')
res.code = 500
res.data = 'ERROR: Could not connect to lurkcoin!'
elseif res.code == 401 or res.code == 418 then
minetest.log('warning', '[lurkcoin] Invalid username or API token!')
2019-02-22 05:22:17 +01:00
lurkcoin.server_name, token = '<unknown>', nil
2019-02-22 05:15:44 +01:00
elseif res.code == 200 and res.data:sub(1, 7) == 'ERROR: ' then
res.code = 501
end
local success, msg = pcall(callback, res)
if not success then
minetest.log('error', '[lurkcoin] Error: ' .. msg)
end
end)
end
-- Process incoming transactions.
local handled_transactions = {}
local function _sync(res)
if res.code == 200 then
local data = minetest.parse_json(res.data)
-- Update the exchange rate
assert(type(data.exchange_rate) == 'number')
assert(data.exchange_rate == data.exchange_rate)
lurkcoin.exchange_rate = data.exchange_rate
-- Process any unprocessed transactions
for _, t in ipairs(data.transactions) do
assert(type(t[3]) == 'number')
local id = minetest.serialize(t)
if not handled_transactions[id] then
handled_transactions[id] = true
core.log('action', '[lurkcoin] ' .. t[4])
lurkcoin.bank.add(t[2], t[3])
end
end
-- Tell lurkcoin to remove processed transactions
if #data.transactions > 0 then
get('remove_transactions', {count = tostring(#data.transactions)},
function(res)
if res.code == 200 then
for _, t in ipairs(data.transactions) do
handled_transactions[minetest.serialize(t)] = nil
end
end
end)
end
end
end
-- Periodically sync with lurkcoin.
local function sync()
get('get_transactions', {as_object = 'true'}, _sync)
minetest.after(300, sync)
end
-- Start syncing once the game is loaded.
minetest.after(0, sync)
-- Get an exchange rate
function lurkcoin.get_exchange_rate(amount, to, callback)
assert(callback)
amount = amount and tonumber(amount)
if not amount or amount ~= amount then return callback(nil) end
get('exchange_rates', {
from = lurkcoin.server_name,
to = to or 'lurkcoin',
amount = tostring(amount),
}, function(res)
if res.code == 200 then
local amount = tonumber(res.data)
if amount == amount then return callback(amount) end
end
return callback(nil)
end)
end
2019-02-22 05:15:44 +01:00
-- Pay a user (cross-server)
function lurkcoin.pay(from, to, server, amount, callback)
assert(type(amount) == 'number' and callback)
-- Run lurkcoin.bank.pay() if this is not a cross-server transaction.
if not server or server == '' or server:lower() ==
2019-09-19 08:48:39 +02:00
lurkcoin.server_name:lower() then
2019-02-22 05:15:44 +01:00
return callback(lurkcoin.bank.pay(from, to, amount))
end
-- Sanity checks
amount = math.floor(amount * 100) / 100
if not lurkcoin.bank.user_exists(from) then
return callback(false, 'ERROR: The "from" user does not exist!')
elseif amount ~= amount or amount <= 0 then
return callback(false, 'ERROR: Invalid number!')
elseif lurkcoin.bank.getbal(from) - amount < 0 then
return callback(false, 'ERROR: You cannot afford to do that!')
end
if not lurkcoin.bank.subtract(from, amount, 'Transaction to "' .. to ..
'" on server "' .. server .. '".') then
return callback(false, 'ERROR: Transaction failed!')
end
-- Send the request
return get('pay', {
target = to,
server = server,
amount = tostring(amount),
local_currency = 'true'
2019-02-22 05:15:44 +01:00
}, function(res)
if res.code ~= 200 then
lurkcoin.bank.add(from, amount, 'Reverting failed transaction.')
if res.data == 'ERROR: You cannot afford to do that!' then
res.data = 'ERROR: This server cannot afford to do that!'
end
else
minetest.log('action', '[lurkcoin] User ' .. from .. ' paid ' ..
to .. ' (on server ' .. server .. ') ' .. tostring(amount) .. 'cr.')
end
return callback(res.code == 200, res.data or 'ERROR: Unknown error!')
end)
end
-- Nuke lurkcoin.modpath
lurkcoin.modpath = nil