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://localhost:8080/start-transaction/"); listener.Start(); Console.WriteLine("Listening on http://localhost:8080/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>(); client.PerformStartTransaction(payload.amount, payload.transactionType); // Wait synchronously for result Dictionary 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 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 Items { get; set; } public SerializableKeyValueList() { } public SerializableKeyValueList(Dictionary dict) { Items = new List(); 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; } } }