Fixed how iteration through database is handled

Fixed command error styling
Added callback to flush database when server window is closed
This commit is contained in:
Gabriel Tofvesson 2018-05-04 16:04:58 +02:00
parent eeaf8c708f
commit f6c7fa83bb
3 changed files with 95 additions and 2 deletions

View File

@ -142,7 +142,7 @@ namespace Server
return true;
}
public void ShowError() => Output.Error($"Usage: {CommandString}");
public void ShowError() => Output.Error($"Usage: {CommandString}", true, false);
}
public static class Commands

View File

@ -252,7 +252,7 @@ namespace Server
using (var reader = XmlReader.Create(DatabaseName))
{
if (!Traverse(reader, MasterEntry)) return null;
while (reader.Read() && reader.NodeType != XmlNodeType.EndElement)
while ((reader.Name.Equals("User") && reader.NodeType != XmlNodeType.EndElement) || (reader.Read() && reader.NodeType != XmlNodeType.EndElement))
{
if (reader.Name.Equals("User"))
{
@ -308,6 +308,7 @@ namespace Server
if (!l.Contains(entry) && p(entry))
l.Add(entry);
/*
using (var reader = XmlReader.Create(DatabaseName))
{
if (!Traverse(reader, MasterEntry)) return null;
@ -319,6 +320,24 @@ namespace Server
if (e!=null && !l.Contains(e = FromEncoded(e)) && p(e)) l.Add(e);
}
}
*/
using (var reader = XmlReader.Create(DatabaseName))
{
if (!Traverse(reader, MasterEntry)) return null;
while ((reader.Name.Equals("User") && reader.NodeType != XmlNodeType.EndElement) || (reader.Read() && reader.NodeType != XmlNodeType.EndElement))
{
if (reader.Name.Equals("User"))
{
User n = FromEncoded(User.Parse(ReadEntry(reader), this));
if (n != null && p(n))
{
if (!l.Contains(n)) l.Add(n);
}
}
}
}
return l.ToArray();
}
@ -362,6 +381,7 @@ namespace Server
private static User FromEncoded(User entry)
{
if (entry == null) return null;
User u = new User(entry);
u.Name = Decode(u.Name);
foreach (var account in u.accounts)
@ -468,6 +488,28 @@ namespace Server
History.Add(tx);
return this;
}
public override string ToString()
{
StringBuilder builder = new StringBuilder(balance.ToString());
foreach (var tx in History)
{
builder
.Append('{')
.Append(tx.from.ToBase64String())
.Append('&')
.Append(tx.fromAccount.ToBase64String())
.Append('&')
.Append(tx.to.ToBase64String())
.Append('&')
.Append(tx.toAccount.ToBase64String())
.Append('&')
.Append(tx.amount.ToString());
if (tx.meta != null) builder.Append('&').Append(tx.meta.ToBase64String());
builder.Append('}');
}
return builder.ToString();
}
}
public class User
@ -539,6 +581,9 @@ namespace Server
{
if (!e.Name.Equals("User")) return null;
User user = new User();
foreach (var attribute in e.Attributes)
if (attribute.Key.Equals("admin") && attribute.Value.Equals("true"))
user.IsAdministrator = true;
foreach (var entry in e.NestedEntries)
{
if (entry.Name.Equals("Name")) user.Name = entry.Text;

View File

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
using Tofvesson.Common;
@ -22,6 +23,10 @@ namespace Server
// Initialize the database
Database db = new Database("BankDB", "Resources");
SetConsoleCtrlHandler(i => {
if (i == 2) db.Flush(); // Ensures that the database is flushed before the program exits
return false;
}, true);
// Create a secure random provider and start getting RSA stuff
CryptoRandomProvider random = new CryptoRandomProvider();
@ -246,8 +251,46 @@ namespace Server
// Possible errors: bad session id, bad account name, balance in account isn't 0
return ErrorResponse(id, (user==null? "badsession" : account==null? "badacc" : "hasbal"));
}
user.accounts.Remove(account);
db.UpdateUser(user); // Update user info
break;
}
case "Account_Get":
{
Database.User user = null;
Database.Account account = null;
if (!ParseDataPair(cmd[1], out string session, out string name) || // Get session id and account name
!GetUser(session, out user) || // Get user associated with session id
!GetAccount(name, user, out account) ||
account.balance != 0)
{
// Don't print input data to output in case sensitive information was included
Output.Error($"Recieved problematic session id or account name!");
// Possible errors: bad session id, bad account name, balance in account isn't 0
return ErrorResponse(id, (user == null ? "badsession" : account == null ? "badacc" : "hasbal"));
}
// Response example: "123.45{Sm9obiBEb2U=&Sm9obnMgQWNjb3VudA==&SmFuZSBEb2U=&SmFuZXMgQWNjb3VudA==&123.45&SGV5IHRoZXJlIQ==}"
// Exmaple data: balance=123.45, Transaction{to="John Doe", toAccount="Johns Account", from="Jane Doe", fromAccount="Janes Account", amount=123.45, meta="Hey there!"}
return GenerateResponse(id, account.ToString());
}
case "Account_List":
{
// Get user
Database.User user = db.GetUser(cmd[1]);
if (user == null) return ErrorResponse(id, "baduser");
// Serialize account names
StringBuilder builder = new StringBuilder();
// Account names are serialized as base64 to prevent potential &'s in the names from causing unintended behaviour
foreach (var account in user.accounts) builder.Append(account.name.ToBase64String()).Append('&');
if (builder.Length != 0) --builder.Length;
// Return accounts
return GenerateResponse(id, builder);
}
case "Reg":
{
if (!ParseDataPair(cmd[1], out string user, out string pass))
@ -374,5 +417,10 @@ namespace Server
server.StopRunning();
}
// Handles unexpected console close events
private delegate bool EventHandler(int eventType);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool SetConsoleCtrlHandler(EventHandler callback, bool add);
}
}