ChipDNAClientCLI/ClientApp.cs

195 lines
6.5 KiB
C#

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using System.Xml.Serialization;
namespace Creditcall.ChipDna.Client
{
class ClientApp
{
private const int ErrorExit = 1;
private const int SuccessExit = 0;
private const string ConfigFilename = "client.config.xml";
private const int DefaultPort = 1869;
private const string DefaultIpAddress = "127.0.0.1";
private const bool DefaultSaveReceipt = false;
private static Client client;
private static int Main()
{
try
{
var settings = new ConfigFileParser(GetAbsolutePath(ConfigFilename));
string tid = settings.TerminalId;
string apiKey = settings.ApiKey;
string posId = settings.PosId;
string address = settings.ConnectAddress ?? DefaultIpAddress;
string sslHost = settings.SslHostName;
bool saveReceipt = settings.SaveReceipt ?? DefaultSaveReceipt;
int port = DefaultPort;
if (!string.IsNullOrEmpty(settings.ConnectionPort))
{
if (!int.TryParse(settings.ConnectionPort, out port))
{
Console.WriteLine("Invalid port number in config.");
return ErrorExit;
}
}
string identifier = !string.IsNullOrEmpty(tid) ? tid :
!string.IsNullOrEmpty(posId) ? posId : null;
if (identifier == null || (string.IsNullOrEmpty(apiKey) && string.IsNullOrEmpty(tid)))
{
Console.WriteLine("Missing valid credentials.");
return ErrorExit;
}
Console.WriteLine($"Starting ChipDNAClient with ID={identifier}, Address={address}:{port}");
client = new Client(identifier, address, port, sslHost, saveReceipt, settings);
StartHttpServer();
return SuccessExit;
}
catch (Exception ex)
{
Console.WriteLine("Startup failed: " + ex.Message);
return ErrorExit;
}
}
private static void StartHttpServer()
{
HttpListener listener = new HttpListener();
listener.Prefixes.Add("http://127.0.0.1:18181/start-transaction/");
listener.Start();
Console.WriteLine("Listening on http://127.0.0.1:18181/start-transaction/");
while (true)
{
HttpListenerContext context = listener.GetContext();
HttpListenerRequest request = context.Request;
if (request.HttpMethod == "POST")
{
try
{
var serializer = new XmlSerializer(typeof(TransactionPayload));
TransactionPayload payload = (TransactionPayload)serializer.Deserialize(request.InputStream);
Console.WriteLine($"Received transaction request: Amount={payload.amount}, Type={payload.transactionType}");
client.TransactionCompletionSource = new TaskCompletionSource<Dictionary<string, string>>();
client.PerformStartTransaction(payload.amount, payload.transactionType);
// Wait synchronously for result
Dictionary<string, string> transactionResult = client.TransactionCompletionSource.Task.Result;
var responseSerializer = new XmlSerializer(typeof(SerializableKeyValueList));
context.Response.ContentType = "application/xml";
var wrappedResult = new SerializableKeyValueList(transactionResult);
responseSerializer.Serialize(context.Response.OutputStream, wrappedResult);
}
catch (Exception ex)
{
Console.WriteLine("Error handling request: " + ex.Message);
context.Response.StatusCode = 500;
}
finally
{
// Remove this line if you're already writing to the stream above
// Otherwise keep it if no other usage of OutputStream occurs
context.Response.OutputStream.Close();
}
}
else
{
context.Response.StatusCode = 405;
context.Response.Close();
}
}
}
private static string GetAbsolutePath(string fileName)
{
var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
return Path.Combine(path ?? "", fileName);
}
private static string EscapeForJson(string input)
{
return input?.Replace("\\", "\\\\")
.Replace("\"", "\\\"")
.Replace("\n", "\\n")
.Replace("\r", "\\r");
}
private static string SerializeToJson(Dictionary<string, string> dict)
{
var sb = new StringBuilder();
sb.Append("{");
foreach (var kv in dict)
{
sb.Append($"\"{EscapeForJson(kv.Key)}\":\"{EscapeForJson(kv.Value)}\",");
}
if (sb.Length > 1)
sb.Length--; // remove last comma
sb.Append("}");
return sb.ToString();
}
}
[XmlRoot("TransactionResult")]
public class SerializableKeyValueList
{
[XmlElement("Entry")]
public List<Entry> Items { get; set; }
public SerializableKeyValueList() { }
public SerializableKeyValueList(Dictionary<string, string> dict)
{
Items = new List<Entry>();
foreach (var kv in dict)
{
Items.Add(new Entry { Key = kv.Key, Value = kv.Value });
}
}
}
public class Entry
{
[XmlElement("Key")]
public string Key { get; set; }
[XmlElement("Value")]
public string Value { get; set; }
}
[XmlRoot("TransactionPayload")]
public class TransactionPayload
{
public string amount { get; set; }
public string transactionType { get; set; }
}
}