Refactor mod to use the new HTTPS API.
This commit makes several changes: ¤ The mod (finally) uses the lurkcoinV3 API. ¤ Transactions to non-existent users are reverted (provided both servers are using the updated mod) · There is a small processing fee on transactions to invalid users (definitely not a bug) ¤ Fix non-minetest_game formspec prepends on ATM formspecs. ¤ Stop overriding minetest.log. ¤ Add luacheck workflow based on the one at https://github.com/BlockySurvival/bls_custom ¤ Fix errors reported by luacheck.
This commit is contained in:
parent
640fbae0b3
commit
50f5b41ccd
|
@ -0,0 +1,13 @@
|
|||
name: luacheck
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
luacheck:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@master
|
||||
- name: Run luacheck
|
||||
uses: Roang-zero1/factorio-mod-luacheck@master
|
||||
with:
|
||||
luacheckrc_url: https://raw.githubusercontent.com/luk3yx/minetest-lurkcoin/master/.luacheckrc
|
|
@ -0,0 +1,19 @@
|
|||
-- Originally from bls_custom
|
||||
|
||||
max_line_length = 80
|
||||
|
||||
globals = {
|
||||
'atm',
|
||||
'accounts',
|
||||
'default',
|
||||
'economy',
|
||||
'lurkcoin',
|
||||
'minetest',
|
||||
'money',
|
||||
'ItemStack'
|
||||
}
|
||||
|
||||
read_globals = {
|
||||
string = {fields = {'split', 'trim'}},
|
||||
table = {fields = {'copy'}},
|
||||
}
|
90
atm-core.lua
90
atm-core.lua
|
@ -14,30 +14,34 @@ local formspecs = {}
|
|||
|
||||
-- 0.4 compatibility
|
||||
lurkcoin.formspec_prepend = ''
|
||||
if minetest.get_modpath('default') and rawget(_G, 'default') and
|
||||
default.gui_bg and default.gui_bg_img and default.gui_slots then
|
||||
if minetest.global_exists('default') and default.gui_bg and
|
||||
default.gui_bg_img and default.gui_slots then
|
||||
lurkcoin.formspec_prepend = default.gui_bg .. default.gui_bg_img ..
|
||||
default.gui_slots
|
||||
end
|
||||
|
||||
-- The formspec code is based on something random I did in 2017(?) for
|
||||
-- lurkcoinV1, formspecs are weird and I somehow got it right™ then.
|
||||
local function centre_label(pos, label)
|
||||
return 'image_button[' .. pos .. ';blank.png;;' .. e(label) ..
|
||||
';true;false;]'
|
||||
end
|
||||
|
||||
-- The formspec code is based on something I did in 2017(?) for lurkcoinV1,
|
||||
-- formspecs are weird and I somehow got it right then.
|
||||
local function get_formspec(name, page, params)
|
||||
-- The formspec template
|
||||
local formspec = 'size[8,9;]' .. lurkcoin.formspec_prepend ..
|
||||
local formspec = 'size[8,9]' .. lurkcoin.formspec_prepend ..
|
||||
'label[0.5,1.75;Your balance: ' ..
|
||||
e(lurkcoin.bank.getbal(name)) .. 'cr.]' ..
|
||||
'image_button[2,0.55;4,0.5;default_dirt.png^\\[colorize:#343434;y;' ..
|
||||
'Welcome to a ' .. e(lurkcoin.server_name) .. ' ATM!]' ..
|
||||
'label[0.5,2.25;Exchange rate: \194\1641.00 is equal to ' ..
|
||||
e(lurkcoin.exchange_rate) .. 'cr.]' ..
|
||||
'image_button[1.75,1.05;4.5,0.5;default_dirt.png^\\[colorize:' ..
|
||||
'#343434;y; Your account: ' .. e(name) .. ']' ..
|
||||
'image[0.5,0.5;1,1;default_mese_crystal.png]' ..
|
||||
centre_label('1,0.55;6,0.5', 'Welcome to a ' .. lurkcoin.server_name ..
|
||||
'ATM!') ..
|
||||
'label[0.5,2.25;Exchange rate: \194\1641.00 is equal to ' ..
|
||||
e(lurkcoin.exchange_rate) .. 'cr.]' ..
|
||||
centre_label('1.75,1.05;4.5,0.5', 'Your account: ' .. name) ..
|
||||
'image[0.5,0.5;1,1;default_mese_crystal.png]' ..
|
||||
'image[6.5,0.5;1,1;default_mese_crystal.png]'
|
||||
|
||||
-- Get the page formspec
|
||||
local page = formspecs[page] or formspecs.main
|
||||
page = formspecs[page] or formspecs.main
|
||||
if type(page) == 'string' then
|
||||
formspec = formspec .. page
|
||||
elseif type(page) == 'function' then
|
||||
|
@ -52,7 +56,7 @@ end
|
|||
local withdrawls = false
|
||||
|
||||
-- Payment screen
|
||||
function formspecs.pay(name, fields, guessed_amount)
|
||||
function formspecs.pay(name, fields)
|
||||
fields = fields or {}
|
||||
local formspec =
|
||||
'field[0.8,3.5;7,1;user;User to pay;' .. e(fields.user or '') .. ']' ..
|
||||
|
@ -93,7 +97,7 @@ function formspecs.pay(name, fields, guessed_amount)
|
|||
|
||||
exc = tostring(math.floor(exc * 100) / 100)
|
||||
formspec = formspec .. '\n' .. fields.amount .. 'cr is ' ..
|
||||
'equal to \194\164' .. exc .. '.'
|
||||
'equal to ' .. exc .. '.'
|
||||
end
|
||||
formspec = formspec .. ']' ..
|
||||
'button[0.5,8;3.5,1;payuser;Cancel]' ..
|
||||
|
@ -140,16 +144,20 @@ if minetest.get_modpath('currency') then
|
|||
}
|
||||
|
||||
-- Remove non-registered notes
|
||||
local remove = {}
|
||||
for id, note in pairs(withdrawls) do
|
||||
if not minetest.registered_items[note] then
|
||||
withdrawls[id] = nil
|
||||
table.insert(remove, id)
|
||||
end
|
||||
end
|
||||
for _, id in ipairs(remove) do
|
||||
withdrawls[id] = nil
|
||||
end
|
||||
assert(#withdrawls > 0, 'The "currency" mod did not register any notes!')
|
||||
|
||||
-- Create a detached inventory for depositing
|
||||
local inv = minetest.create_detached_inventory('lurkcoin:atm_deposit', {
|
||||
on_put = function(inv, listname, index, stack, player)
|
||||
on_put = function(inv, listname, _, stack, player)
|
||||
local name = stack:get_name()
|
||||
if name:sub(1, 17) == 'currency:minegeld' then
|
||||
local m = name:sub(19)
|
||||
|
@ -157,6 +165,8 @@ if minetest.get_modpath('currency') then
|
|||
if m:sub(1, 5) == 'cent_' then
|
||||
m = tonumber(m:sub(6))
|
||||
if m then m = m / 100 end
|
||||
elseif m == 'bundle' then
|
||||
m = 0.05 * 9
|
||||
else
|
||||
m = tonumber(m)
|
||||
end
|
||||
|
@ -170,16 +180,16 @@ if minetest.get_modpath('currency') then
|
|||
if not lurkcoin.bank.add(pname, m, 'Deposit') then
|
||||
player:get_inventory():add_item('main', stack)
|
||||
end
|
||||
core.log('action', 'Player ' .. pname .. ' deposits ' ..
|
||||
tostring(m) .. 'Mg (' .. stack:to_string() ..
|
||||
') into a lurkcoin ATM.')
|
||||
minetest.log('action', 'Player ' .. pname ..
|
||||
' deposits ' .. tostring(m) .. 'Mg (' ..
|
||||
stack:to_string() .. ') into a lurkcoin ATM.')
|
||||
end
|
||||
end
|
||||
inv:set_list(listname, {})
|
||||
lurkcoin.show_atm(player:get_player_name(), 'deposit')
|
||||
end,
|
||||
|
||||
allow_put = function(inv, listname, index, stack, player)
|
||||
allow_put = function(_, _, _, stack, _)
|
||||
local name = stack:get_name()
|
||||
if name:sub(1, 17) == 'currency:minegeld' then
|
||||
return stack:get_count()
|
||||
|
@ -198,8 +208,7 @@ if minetest.get_modpath('currency') then
|
|||
'list[current_player;main;0,6.08;8,3;8]' ..
|
||||
'list[detached:lurkcoin:atm_deposit;lurkcoin;3.5,3;1,1;]' ..
|
||||
'listring[]' ..
|
||||
'image_button[0,3;3.5,1;default_dirt.png^\\[colorize:#343434;' ..
|
||||
'ignore;Deposit money here →]' ..
|
||||
centre_label('0,3;3.5,1', 'Deposit money here →') ..
|
||||
'button[5.25,3;2,1;home;Finish]'
|
||||
else
|
||||
-- When there is no physical currency, the only thing you can do is pay
|
||||
|
@ -208,19 +217,17 @@ else
|
|||
end
|
||||
|
||||
-- "Transaction accepted" screen
|
||||
function formspecs.success(name, text)
|
||||
function formspecs.success(_, text)
|
||||
return 'image[2.1,3;4.5,4.5;lurkcoin_success.png]' ..
|
||||
'image_button[1,7;6,1;default_dirt.png^\\[colorize:#343434;' ..
|
||||
'ignore;' .. e(text or 'Transaction sent!') .. ']' ..
|
||||
centre_label('1,7;6,1', text or 'Transaction sent!') ..
|
||||
'button[0.5,8;3.5,1;home;Go back]' ..
|
||||
'button_exit[4,8;3.5,1;quit;Quit]'
|
||||
end
|
||||
|
||||
-- "Transaction failed" screen
|
||||
function formspecs.error(name, text)
|
||||
function formspecs.error(_, text)
|
||||
return 'image[2.1,3;4.5,4.5;lurkcoin_error.png]' ..
|
||||
'image_button[1,7;6,1;default_dirt.png^\\[colorize:#343434;' ..
|
||||
'ignore;' .. e(text or 'An error has occurred!') .. ']' ..
|
||||
centre_label('1,7;6,1', text or 'An error has occurred!') ..
|
||||
'button[0.5,8;3.5,1;home;Go back]' ..
|
||||
'button_exit[4,8;3.5,1;quit;Quit]'
|
||||
end
|
||||
|
@ -228,10 +235,8 @@ end
|
|||
-- Processing screen
|
||||
formspecs.processing =
|
||||
'image[2.1,3;4.5,4.5;lurkcoin_processing.png]' ..
|
||||
'image_button[1,7;6,1;default_dirt.png^\\[colorize:#343434;' ..
|
||||
'ignore;Processing your transaction...]' ..
|
||||
'image_button[1,8;6,1;default_dirt.png^\\[colorize:#343434;' ..
|
||||
'ignore;This should only take a few seconds.]'
|
||||
centre_label('1,7;6,1', 'Processing your transaction...') ..
|
||||
centre_label('1,8;6,1', 'This should only take a few seconds.')
|
||||
|
||||
-- A wrapper function
|
||||
function lurkcoin.show_atm(name, page, params)
|
||||
|
@ -267,10 +272,12 @@ minetest.register_on_player_receive_fields(function(player, formname, raw)
|
|||
'ERROR: You cannot afford to do that!')
|
||||
end
|
||||
|
||||
local note = false
|
||||
local note
|
||||
for id, item in pairs(withdrawls) do
|
||||
-- HACK: Multiply both amount and id by 1000 to avoid
|
||||
-- floating-point bugs.
|
||||
if (not note or id > note) and
|
||||
math.floor(amount / id) * id == amount then
|
||||
(amount * 1000) % (id * 1000) == 0 then
|
||||
local def = minetest.registered_items[item]
|
||||
if def and amount / id <= (def.stack_max or 99) then
|
||||
note = id
|
||||
|
@ -286,7 +293,7 @@ minetest.register_on_player_receive_fields(function(player, formname, raw)
|
|||
|
||||
local stack = ItemStack({
|
||||
name = withdrawls[note],
|
||||
count = amount / note,
|
||||
count = (amount * 1000) / (note * 1000),
|
||||
})
|
||||
local inv = player:get_inventory()
|
||||
if not inv:room_for_item('main', stack) then
|
||||
|
@ -372,14 +379,5 @@ minetest.register_on_player_receive_fields(function(player, formname, raw)
|
|||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
-- TODO: I forgot what one register_on_leaveplayer uses and am too lazy to
|
||||
-- check.
|
||||
local name
|
||||
if type(player) == 'string' then
|
||||
name = player
|
||||
else
|
||||
name = player:get_player_name()
|
||||
end
|
||||
|
||||
open_atms[name] = nil
|
||||
open_atms[player:get_player_name()] = nil
|
||||
end)
|
||||
|
|
|
@ -22,7 +22,7 @@ minetest.register_node('lurkcoin:atm', {
|
|||
end
|
||||
end,
|
||||
|
||||
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
||||
on_rightclick = function(_, _, clicker, _, _)
|
||||
return lurkcoin.show_atm(clicker:get_player_name())
|
||||
end,
|
||||
})
|
||||
|
|
254
core.lua
254
core.lua
|
@ -4,28 +4,40 @@
|
|||
-- © 2019 by luk3yx
|
||||
--
|
||||
|
||||
lurkcoin.version = 0
|
||||
-- Change this if you are hosting your own lurkcoin-core instance
|
||||
local baseurl = 'https://us.xeroxirc.net:7000'
|
||||
|
||||
lurkcoin.version = 3
|
||||
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://us.xeroxirc.net:7000/v2'
|
||||
local function log(level, text)
|
||||
if text then
|
||||
text = text:gsub('[\r\n]', ' ')
|
||||
else
|
||||
level, text = 'action', level:gsub('[\r\n]', ' ')
|
||||
end
|
||||
return minetest.log(level, '[lurkcoin] ' .. text)
|
||||
end
|
||||
|
||||
local function logf(text, ...)
|
||||
return log(text:format(...))
|
||||
end
|
||||
|
||||
-- Get the username and API token
|
||||
lurkcoin.server_name = minetest.settings:get('lurkcoin.username')
|
||||
local token = minetest.settings:get('lurkcoin.token')
|
||||
local token = minetest.settings:get('lurkcoin.token')
|
||||
|
||||
-- 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!')
|
||||
log('warning', 'lurkcoin.server_name is not set!')
|
||||
end
|
||||
|
||||
-- Make sure the HTTP API exists
|
||||
local http = ...
|
||||
if not http then
|
||||
minetest.log('warning', 'lurkcoin is not allowed to use the HTTP API! ' ..
|
||||
log('warning', 'lurkcoin is not allowed to use the HTTP API! ' ..
|
||||
'Please add lurkcoin to secure.http_mods in minetest.conf.')
|
||||
end
|
||||
|
||||
|
@ -34,177 +46,185 @@ end
|
|||
lurkcoin.user_agent = 'Minetest ' .. minetest.get_version().string ..
|
||||
' (with lurkcoin mod v' .. tostring(lurkcoin.version) .. ')'
|
||||
|
||||
-- Create the HTTP header list
|
||||
local headers
|
||||
if token then
|
||||
local raw = lurkcoin.server_name:gsub(':', '_') .. ':' .. token
|
||||
local auth = minetest.encode_base64(raw)
|
||||
headers = {
|
||||
-- minetest.encode_base64() doesn't add padding
|
||||
'Authorization: Basic ' .. auth .. ('='):rep(4 - #auth % 4),
|
||||
'Content-Type: application/json',
|
||||
'X-Force-OK: true'
|
||||
}
|
||||
end
|
||||
|
||||
local function E(code, msg)
|
||||
return {sucess = false, error = code, message = msg}
|
||||
end
|
||||
|
||||
-- Download functions
|
||||
local function get(url, data, callback)
|
||||
-- To prevent race conditions, these callbacks wait until at least the next
|
||||
-- globalstep.
|
||||
if not data then
|
||||
data = {}
|
||||
elseif not http then
|
||||
minetest.after(0, callback, {
|
||||
completed = true,
|
||||
succeeded = false,
|
||||
timeout = true,
|
||||
code = 500,
|
||||
data = 'ERROR: The lurkcoin mod is not in secure.http_mods!'
|
||||
})
|
||||
if not http then
|
||||
minetest.after(0, callback, E('ERR_CONNECTIONFAILED',
|
||||
'The lurkcoin mod is not in secure.http_mods!'))
|
||||
return
|
||||
elseif not lurkcoin.server_name or not token then
|
||||
minetest.after(0, callback, {
|
||||
completed = true,
|
||||
succeeded = false,
|
||||
timeout = true,
|
||||
code = 401,
|
||||
data = 'ERROR: The lurkcoin mod does not have (correct) ' ..
|
||||
'account credentials!'
|
||||
})
|
||||
elseif not headers then
|
||||
minetest.after(0, callback, E('ERR_INVALIDLOGIN',
|
||||
'The lurkcoin mod does not have (correct) credentials!'))
|
||||
return
|
||||
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!')
|
||||
lurkcoin.server_name, token = '<unknown>', nil
|
||||
elseif res.code == 200 and res.data:sub(1, 7) == 'ERROR: ' then
|
||||
res.code = 501
|
||||
url = baseurl .. '/v3/' .. url,
|
||||
timeout = lurkcoin.timeout,
|
||||
post_data = data and minetest.write_json(data),
|
||||
user_agent = lurkcoin.user_agent,
|
||||
extra_headers = headers
|
||||
}, function(http_res)
|
||||
local res
|
||||
if http_res.timeout then
|
||||
log('warning', 'Could not connect to lurkcoin!')
|
||||
res = E('ERR_CONNECTIONFAILED', 'Could not connect to lurkcoin!')
|
||||
else
|
||||
res = minetest.parse_json(http_res.data)
|
||||
if type(data) ~= 'table' then data = nil end
|
||||
end
|
||||
|
||||
local success, msg = pcall(callback, res)
|
||||
if not success then
|
||||
minetest.log('error', '[lurkcoin] Error: ' .. msg)
|
||||
local ok, msg = pcall(callback, res or E('ERR_UNKNOWNERROR', '???'))
|
||||
if not ok then
|
||||
log('error', msg)
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- Process incoming transactions.
|
||||
local handled_transactions = {}
|
||||
local acknowledged_transactions = {}
|
||||
|
||||
local function _sync(res)
|
||||
if res.code == 200 then
|
||||
local data = minetest.parse_json(res.data)
|
||||
local function sync_callback(res)
|
||||
if not res.success then return end
|
||||
|
||||
-- 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])
|
||||
-- Process any unprocessed transactions
|
||||
local reject = {}
|
||||
for _, t in ipairs(res.result) do
|
||||
local id = t.id
|
||||
if not acknowledged_transactions[id] then
|
||||
if lurkcoin.bank.user_exists(t.target) then
|
||||
acknowledged_transactions[id] = true
|
||||
logf('[%s] \194\164%s (sent %s, received %scr) - ' ..
|
||||
'Transaction from %q on %q to %q.',
|
||||
t.id, t.amount, t.sent_amount, t.received_amount, t.source,
|
||||
t.source_server, t.target)
|
||||
lurkcoin.bank.add(t.target, t.received_amount)
|
||||
else
|
||||
logf('Rejecting transaction %s, user %q does not exist.',
|
||||
t.id, t.target)
|
||||
table.insert(reject, t.id)
|
||||
end
|
||||
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)
|
||||
-- Acknowledge transactions (if any)
|
||||
if next(acknowledged_transactions) then
|
||||
local ack = {}
|
||||
for id, _ in pairs(acknowledged_transactions) do
|
||||
table.insert(ack, id)
|
||||
end
|
||||
get('acknowledge_transactions', {transactions = ack}, function(res2)
|
||||
if res2.success then
|
||||
for _, id in ipairs(ack) do
|
||||
acknowledged_transactions[id] = nil
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
-- Reject transactions (if any)
|
||||
if #reject > 0 then
|
||||
get('reject_transactions', {transactions = reject}, function() end)
|
||||
end
|
||||
end
|
||||
|
||||
-- Periodically sync with lurkcoin.
|
||||
local function sync()
|
||||
get('get_transactions', {as_object = 'true'}, _sync)
|
||||
get('pending_transactions', nil, sync_callback)
|
||||
|
||||
-- Only set lurkcoin.exchange_rate once
|
||||
if not lurkcoin.exchange_rate then
|
||||
get('exchange_rates', {source = lurkcoin.server_name, target = '',
|
||||
amount = 1}, function(res)
|
||||
if res.success and type(res.result) == 'number' then
|
||||
lurkcoin.exchange_rate = res.result
|
||||
end
|
||||
end)
|
||||
end
|
||||
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)
|
||||
function lurkcoin.get_exchange_rate(amount, target, 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),
|
||||
source = lurkcoin.server_name,
|
||||
target = target or '',
|
||||
amount = amount,
|
||||
}, function(res)
|
||||
if res.code == 200 then
|
||||
local amount = tonumber(res.data)
|
||||
if amount == amount then return callback(amount, nil) end
|
||||
end
|
||||
local msg
|
||||
if res.code == 502 then
|
||||
msg = 'That server does not exist!'
|
||||
if res.success then
|
||||
callback(res.result, nil)
|
||||
elseif res.error == 'ERR_TARGETSERVERNOTFOUND' then
|
||||
callback(nil, 'That server does not exist!')
|
||||
else
|
||||
msg = res.data
|
||||
callback(nil, tostring(res.message))
|
||||
end
|
||||
return callback(nil, tostring(msg))
|
||||
end)
|
||||
end
|
||||
|
||||
-- Pay a user (cross-server)
|
||||
function lurkcoin.pay(from, to, server, amount, callback)
|
||||
function lurkcoin.pay(source, target, target_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() ==
|
||||
lurkcoin.server_name:lower() then
|
||||
return callback(lurkcoin.bank.pay(from, to, amount))
|
||||
if not target_server or target_server == '' or
|
||||
target_server:lower() == lurkcoin.server_name:lower() then
|
||||
return callback(lurkcoin.bank.pay(source, target, amount))
|
||||
end
|
||||
|
||||
-- Sanity checks
|
||||
amount = math.floor(amount * 100) / 100
|
||||
if not lurkcoin.bank.user_exists(from) then
|
||||
if not lurkcoin.bank.user_exists(source) 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
|
||||
elseif amount > lurkcoin.bank.getbal(source) 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
|
||||
if not lurkcoin.bank.subtract(source, amount, 'Transaction to "' ..
|
||||
source .. '" on server "' .. target_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'
|
||||
source = source,
|
||||
target = target,
|
||||
target_server = target_server,
|
||||
amount = amount,
|
||||
local_currency = true
|
||||
}, 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.')
|
||||
if res.success then
|
||||
logf('User %q paid %q (on server %q) %scr.', source, target,
|
||||
target_server, amount)
|
||||
return callback(true, 'Transaction sent!')
|
||||
end
|
||||
|
||||
return callback(res.code == 200, res.data or 'ERROR: Unknown error!')
|
||||
lurkcoin.bank.add(source, amount, 'Reverting failed transaction.')
|
||||
if res.code == 'ERR_CANNOTAFFORD' then
|
||||
res.message = 'This server cannot afford to do that!'
|
||||
end
|
||||
return callback(false, 'ERROR: ' .. tostring(res.message))
|
||||
end)
|
||||
end
|
||||
|
||||
|
|
24
init.lua
24
init.lua
|
@ -26,30 +26,6 @@ dofile(modpath .. '/atm-core.lua')
|
|||
-- Load the ATM blocks
|
||||
dofile(modpath .. '/atm-nodes.lua')
|
||||
|
||||
-- Backport https://github.com/minetest/minetest/pull/8420 if required
|
||||
if not minetest.get_modpath('cloaking') or not cloaking.hide_player then
|
||||
table.insert(minetest.registered_on_chat_messages, 1, function(name, msg)
|
||||
if msg:find('[\r\n]') then
|
||||
minetest.chat_send_player(name,
|
||||
'New lines are not permitted in chat messages')
|
||||
return true
|
||||
end
|
||||
end)
|
||||
|
||||
-- Also tweak minetest.log because of paranoia.
|
||||
local log = minetest.log
|
||||
function minetest.log(level, text)
|
||||
level = level:gsub('[\r\n]', ' ')
|
||||
if text then
|
||||
text = text:gsub('[\r\n]', ' ')
|
||||
else
|
||||
text = level
|
||||
level = 'none'
|
||||
end
|
||||
return log(level, text)
|
||||
end
|
||||
end
|
||||
|
||||
-- Display loaded message
|
||||
minetest.log('action', '[lurkcoin] Loaded on server "' ..
|
||||
lurkcoin.server_name .. '".')
|
||||
|
|
Loading…
Reference in New Issue