Added transactions
This commit is contained in:
parent
d5b2016dc3
commit
ffd620f172
|
@ -9,6 +9,7 @@ local client = {}
|
||||||
client.state = {
|
client.state = {
|
||||||
auth = nil,
|
auth = nil,
|
||||||
hostId = nil,
|
hostId = nil,
|
||||||
|
securityKey = nil,
|
||||||
timeout = 3
|
timeout = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,18 +29,28 @@ local function request(command, data)
|
||||||
return requestRaw({command = command, data = data})
|
return requestRaw({command = command, data = data})
|
||||||
end
|
end
|
||||||
|
|
||||||
local function requestAuth(command, data)
|
local function requestAuth(command, data, secure)
|
||||||
|
secure = secure or false
|
||||||
if not client.loggedIn() then
|
if not client.loggedIn() then
|
||||||
return {success = false, error = "Client not logged in"}
|
return {success = false, error = "Client not logged in"}
|
||||||
end
|
end
|
||||||
return requestRaw({command = command, auth = client.state.auth, data = data})
|
local authInfo = {
|
||||||
|
username = client.state.auth.username,
|
||||||
|
password = client.state.auth.password
|
||||||
|
}
|
||||||
|
if secure and not client.state.securityKey then
|
||||||
|
return {success = false, error = "Missing security key for secure request."}
|
||||||
|
end
|
||||||
|
autInfo.key = client.state.securityKey
|
||||||
|
return requestRaw({command = command, auth = authInfo, data = data})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Base functions
|
-- Base functions
|
||||||
|
|
||||||
function client.init(modemName, host)
|
function client.init(modemName, host, securityKey)
|
||||||
rednet.open(modemName)
|
rednet.open(modemName)
|
||||||
client.state.hostId = rednet.lookup("BANK", host)
|
client.state.hostId = rednet.lookup("BANK", host)
|
||||||
|
client.state.securityKey = securityKey or nil
|
||||||
return client.state.hostId ~= nil
|
return client.state.hostId ~= nil
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -103,4 +114,12 @@ function client.renameAccount(accountId, newName)
|
||||||
return response.success, response.error
|
return response.success, response.error
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function client.recordTransaction(accountId, amount, description)
|
||||||
|
local response = requestAuth("RECORD_TRANSACTION", {accountId = accountId, amount = amount, description = description}, true)
|
||||||
|
if not response.success then
|
||||||
|
return nil, response.error
|
||||||
|
end
|
||||||
|
return response.data
|
||||||
|
end
|
||||||
|
|
||||||
return client
|
return client
|
||||||
|
|
80
bank.lua
80
bank.lua
|
@ -55,6 +55,10 @@ local function validateUsername(name)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function validateTransactionDescription(desc)
|
||||||
|
return string.find(desc, "^%w+[ !%.%w]*$") ~= nil and #desc <= 64
|
||||||
|
end
|
||||||
|
|
||||||
local function userDir(name)
|
local function userDir(name)
|
||||||
return fs.combine(USERS_DIR, name)
|
return fs.combine(USERS_DIR, name)
|
||||||
end
|
end
|
||||||
|
@ -102,12 +106,28 @@ local function saveAccounts(name, accounts)
|
||||||
writeJSON(userAccountsFile(name), accounts)
|
writeJSON(userAccountsFile(name), accounts)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function findAccountById(accounts, id)
|
||||||
|
for i, account in pairs(accounts) do
|
||||||
|
if account.id == id then
|
||||||
|
return account
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
local function findAccountByName(accounts, name)
|
||||||
|
for i, account in pairs(accounts) do
|
||||||
|
if account.name == name then
|
||||||
|
return account
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
local function createAccount(username, accountName)
|
local function createAccount(username, accountName)
|
||||||
local accounts = getAccounts(username)
|
local accounts = getAccounts(username)
|
||||||
for i, account in pairs(accounts) do
|
if findAccountByName(accounts, accountName) then
|
||||||
if account.name == accountName then
|
return false, "Duplicate account name"
|
||||||
return false, "Duplicate account name"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
local newAccount = {
|
local newAccount = {
|
||||||
id = randomAccountId(),
|
id = randomAccountId(),
|
||||||
|
@ -140,15 +160,11 @@ end
|
||||||
|
|
||||||
local function renameAccount(username, accountId, newName)
|
local function renameAccount(username, accountId, newName)
|
||||||
local accounts = getAccounts(username)
|
local accounts = getAccounts(username)
|
||||||
local targetAccount = nil
|
local targetAccount = findAccountById(accounts, accountId)
|
||||||
for i, account in pairs(accounts) do
|
|
||||||
if account.id == accountId then
|
|
||||||
targetAccount = account
|
|
||||||
elseif account.name == newName then
|
|
||||||
return false, "Duplicate account name"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if not targetAccount then return false, "Account not found" end
|
if not targetAccount then return false, "Account not found" end
|
||||||
|
if findAccountByName(accounts, newName) ~= nil then
|
||||||
|
return false, "Duplicate account name"
|
||||||
|
end
|
||||||
targetAccount.name = newName
|
targetAccount.name = newName
|
||||||
saveAccounts(accounts)
|
saveAccounts(accounts)
|
||||||
log("Renamed user " .. username .. " account " .. accountId .. " to " .. newName)
|
log("Renamed user " .. username .. " account " .. accountId .. " to " .. newName)
|
||||||
|
@ -188,6 +204,32 @@ local function renameUser(oldName, newName)
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function recordTransaction(username, accountId, amount, description)
|
||||||
|
if not validateTransactionDescription(description) then return false, "Invalid transaction description" end
|
||||||
|
if not userExists(username) then return false, "User doesn't exist" end
|
||||||
|
local accounts = getAccounts(username)
|
||||||
|
local account = findAccountById(accounts, accountId)
|
||||||
|
if account == nil then return false, "Account doesn't exist" end
|
||||||
|
if account.balance + amount < 0 then return false, "Insufficient funds" end
|
||||||
|
-- Everything is OK, record the transaction.
|
||||||
|
local tx = {
|
||||||
|
amount = amount,
|
||||||
|
description = description,
|
||||||
|
timestamp = os.epoch("utc")
|
||||||
|
}
|
||||||
|
local f = io.open(accountTransactionsFile(username, accountId), "a")
|
||||||
|
local txStr = tostring(tx.amount)..";"..tostring(tx.timestamp)..";"..tx.description
|
||||||
|
f:write(txStr .. string.rep(" ", 99 - #txStr) .. "\n")
|
||||||
|
f:close()
|
||||||
|
if fs.getSize(accountTransactionsFile(username, accountId)) % 100 ~= 0 then
|
||||||
|
log("WARNING! Transaction file for account " .. accountId .. " is not consistent!")
|
||||||
|
end
|
||||||
|
account.balance = account.balance + amount
|
||||||
|
saveAccounts(username, accounts)
|
||||||
|
os.queueEvent("bank_account_balance", username, accountId, account.balance)
|
||||||
|
return true, tx
|
||||||
|
end
|
||||||
|
|
||||||
local function initSecurityKey()
|
local function initSecurityKey()
|
||||||
-- Initialize security key
|
-- Initialize security key
|
||||||
local SECURITY_KEY_FILE = "key.txt"
|
local SECURITY_KEY_FILE = "key.txt"
|
||||||
|
@ -290,6 +332,17 @@ local function handleRenameUserAccount(msg)
|
||||||
return {success = success, error = errorMsg}
|
return {success = success, error = errorMsg}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function handleRecordTransactionToAccount(msg)
|
||||||
|
if not msg.data or not msg.data.amount or not msg.data.description or not msg.data.accountId then
|
||||||
|
return {success = false, error = "Invalid request. Requires data.amount and data.description and data.accountId."}
|
||||||
|
end
|
||||||
|
local success, errorMsgOrTx = recordTransaction(msg.auth.username, msg.data.accountId, msg.data.amount, msg.data.description)
|
||||||
|
if not success then
|
||||||
|
return {success = false, error = errorMsgOrTx}
|
||||||
|
end
|
||||||
|
return {success = true, data = errorMsgOrTx}
|
||||||
|
end
|
||||||
|
|
||||||
-- A registry of all possible BANK requests, and their handler functions.
|
-- A registry of all possible BANK requests, and their handler functions.
|
||||||
local BANK_REQUESTS = {
|
local BANK_REQUESTS = {
|
||||||
["STATUS"] = handleGetStatus,
|
["STATUS"] = handleGetStatus,
|
||||||
|
@ -299,7 +352,8 @@ local BANK_REQUESTS = {
|
||||||
["GET_ACCOUNTS"] = authProtect(handleGetUserAccounts),
|
["GET_ACCOUNTS"] = authProtect(handleGetUserAccounts),
|
||||||
["CREATE_ACCOUNT"] = authProtect(handleCreateUserAccount),
|
["CREATE_ACCOUNT"] = authProtect(handleCreateUserAccount),
|
||||||
["DELETE_ACCOUNT"] = authProtect(handleDeleteUserAccount),
|
["DELETE_ACCOUNT"] = authProtect(handleDeleteUserAccount),
|
||||||
["RENAME_ACCOUNT"] = authProtect(handleRenameUserAccount)
|
["RENAME_ACCOUNT"] = authProtect(handleRenameUserAccount),
|
||||||
|
["RECORD_TRANSACTION"] = authProtect(handleRecordTransactionToAccount, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
local function handleBankMessage(remoteId, msg)
|
local function handleBankMessage(remoteId, msg)
|
||||||
|
|
Loading…
Reference in New Issue