diff --git a/Client.cs b/Client.cs index b6682e6..e610b7b 100644 --- a/Client.cs +++ b/Client.cs @@ -249,7 +249,6 @@ namespace Creditcall.ChipDna.Client { { ParameterKeys.Errors, errors }, { ParameterKeys.Reference, reference }, - { ParameterKeys.TransactionResult, "ERROR" } }; if (TransactionCompletionSource != null && !TransactionCompletionSource.Task.IsCompleted) diff --git a/ClientApp.cs b/ClientApp.cs index 99f5cc5..2e84270 100644 --- a/ClientApp.cs +++ b/ClientApp.cs @@ -19,6 +19,7 @@ namespace Creditcall.ChipDna.Client private const int DefaultPort = 1869; private const string DefaultIpAddress = "127.0.0.1"; private const bool DefaultSaveReceipt = false; + private const int transactionTimeoutSeconds = 300; private static Client client; @@ -72,10 +73,14 @@ namespace Creditcall.ChipDna.Client { HttpListener listener = new HttpListener(); listener.Prefixes.Add("http://127.0.0.1:18181/start-transaction/"); + listener.Prefixes.Add("http://127.0.0.1:18181/start-and-confirm-transaction/"); + listener.Prefixes.Add("http://127.0.0.1:18181/void-transaction/"); listener.Start(); Console.WriteLine("Listening on:"); Console.WriteLine(" http://127.0.0.1:18181/start-transaction/"); + Console.WriteLine(" http://127.0.0.1:18181/start-and-confirm-transaction/"); + //Console.WriteLine(" http://127.0.0.1:18181/void-transaction/"); while (true) { @@ -95,6 +100,9 @@ namespace Creditcall.ChipDna.Client if (rawUrl.StartsWith("/start-transaction", StringComparison.OrdinalIgnoreCase)) { HandleStartTransaction(context); + } else if (rawUrl.StartsWith("/start-and-confirm-transaction", StringComparison.OrdinalIgnoreCase)) + { + HandleStartAndConfirmTransaction(context); } else { @@ -115,10 +123,8 @@ namespace Creditcall.ChipDna.Client } } - private static void HandleStartTransaction(HttpListenerContext context) + private static void HandleStartAndConfirmTransaction(HttpListenerContext context) { - const int transactionTimeoutSeconds = 300; - try { var serializer = new XmlSerializer(typeof(TransactionPayload)); @@ -214,7 +220,7 @@ namespace Creditcall.ChipDna.Client } catch (Exception ex) { - Console.WriteLine("Error in start-transaction: " + ex.Message); + Console.WriteLine("Error in start-and-confirm-transaction: " + ex.Message); context.Response.StatusCode = 500; } finally @@ -223,6 +229,78 @@ namespace Creditcall.ChipDna.Client } } + private static void HandleStartTransaction(HttpListenerContext context) + { + try + { + var serializer = new XmlSerializer(typeof(TransactionPayload)); + TransactionPayload payload = (TransactionPayload)serializer.Deserialize(context.Request.InputStream); + + Console.WriteLine($"Received transaction request: Amount={payload.amount}, Type={payload.transactionType}"); + + client.TransactionCompletionSource = new TaskCompletionSource>(); + + // start transaction (non-blocking) + client.PerformStartTransaction(payload.amount, payload.transactionType); + + // Wait for completion with timeout + var task = client.TransactionCompletionSource.Task; + if (!task.Wait(TimeSpan.FromSeconds(transactionTimeoutSeconds))) + { + // timeout + var errorMap = new Dictionary + { + { ParameterKeys.TransactionResult, "TIMEOUT" }, + { ParameterKeys.Errors, "Transaction timed out waiting for device response" } + }; + + var wrappedTimeout = new SerializableKeyValueList(errorMap); + context.Response.ContentType = "application/xml"; + new XmlSerializer(typeof(SerializableKeyValueList)).Serialize(context.Response.OutputStream, wrappedTimeout); + return; + } + + // Task completed — handle possible exception + Dictionary transactionResult; + try + { + transactionResult = task.Result; // safe now, Wait returned + } + catch (AggregateException agg) + { + var first = agg.Flatten().InnerExceptions[0]; + var errMap = new Dictionary + { + { ParameterKeys.TransactionResult, "ERROR" }, + { ParameterKeys.Errors, $"Transaction task faulted: {first.Message}" } + }; + var wrapped = new SerializableKeyValueList(errMap); + context.Response.ContentType = "application/xml"; + new XmlSerializer(typeof(SerializableKeyValueList)).Serialize(context.Response.OutputStream, wrapped); + return; + } + + 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 in start-transaction: " + ex.Message); + context.Response.StatusCode = 500; + } + finally + { + context.Response.OutputStream.Close(); + } + + } + + + + + private static string GetAbsolutePath(string fileName) { var path = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);