From 59a2432af982c276d209e30ace88faec4b61bef9 Mon Sep 17 00:00:00 2001 From: "nicolas.dorier" Date: Sat, 20 Jan 2018 14:09:57 +0900 Subject: [PATCH] Better invoice loop, fix javascript --- BTCPayServer.Tests/UnitTest1.cs | 6 ++- BTCPayServer/BTCPayServer.csproj | 2 +- BTCPayServer/HostedServices/InvoiceWatcher.cs | 39 ++++++++++++------- BTCPayServer/wwwroot/js/core.js | 10 ++--- 4 files changed, 34 insertions(+), 23 deletions(-) diff --git a/BTCPayServer.Tests/UnitTest1.cs b/BTCPayServer.Tests/UnitTest1.cs index 86c274be1..b92f4df27 100644 --- a/BTCPayServer.Tests/UnitTest1.cs +++ b/BTCPayServer.Tests/UnitTest1.cs @@ -519,6 +519,7 @@ namespace BTCPayServer.Tests }, Facade.Merchant); var cashCow = tester.ExplorerNode; + cashCow.Generate(2); // get some money in case var invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network); var firstPayment = Money.Coins(0.04m); cashCow.SendToAddress(invoiceAddress, firstPayment); @@ -553,6 +554,7 @@ namespace BTCPayServer.Tests invoiceAddress = BitcoinAddress.Create(invoice.BitcoinAddress, cashCow.Network); firstPayment = Money.Coins(0.04m); cashCow.SendToAddress(invoiceAddress, firstPayment); + Logs.Tester.LogInformation("First payment sent to " + invoiceAddress); Eventually(() => { invoice = user.BitPay.GetInvoice(invoice.Id); @@ -566,7 +568,7 @@ namespace BTCPayServer.Tests var secondPayment = Money.Coins(decimal.Parse(ltcCryptoInfo.Due)); cashCow.Generate(2); // LTC is not worth a lot, so just to make sure we have money... cashCow.SendToAddress(invoiceAddress, secondPayment); - + Logs.Tester.LogInformation("Second payment sent to " + invoiceAddress); Eventually(() => { invoice = user.BitPay.GetInvoice(invoice.Id); @@ -765,7 +767,7 @@ namespace BTCPayServer.Tests private void Eventually(Action act) { - CancellationTokenSource cts = new CancellationTokenSource(10000); + CancellationTokenSource cts = new CancellationTokenSource(20000); while (true) { try diff --git a/BTCPayServer/BTCPayServer.csproj b/BTCPayServer/BTCPayServer.csproj index 794789a78..968eb9bdf 100644 --- a/BTCPayServer/BTCPayServer.csproj +++ b/BTCPayServer/BTCPayServer.csproj @@ -2,7 +2,7 @@ Exe netcoreapp2.0 - 1.0.1.16 + 1.0.1.17 diff --git a/BTCPayServer/HostedServices/InvoiceWatcher.cs b/BTCPayServer/HostedServices/InvoiceWatcher.cs index b813726b2..777fe6e97 100644 --- a/BTCPayServer/HostedServices/InvoiceWatcher.cs +++ b/BTCPayServer/HostedServices/InvoiceWatcher.cs @@ -68,7 +68,11 @@ namespace BTCPayServer.HostedServices { var invoice = await _InvoiceRepository.GetInvoiceIdFromScriptPubKey(scriptPubKey, network.CryptoCode); if (invoice != null) + { + String address = scriptPubKey.GetDestinationAddress(network.NBitcoinNetwork)?.ToString() ?? scriptPubKey.ToString(); + Logs.PayServer.LogInformation($"{address} is mapping to invoice {invoice}"); _WatchRequests.Add(invoice); + } } async Task NotifyBlock() @@ -82,8 +86,11 @@ namespace BTCPayServer.HostedServices private async Task UpdateInvoice(string invoiceId, CancellationToken cancellation) { Dictionary changes = new Dictionary(); - while (!cancellation.IsCancellationRequested) + int maxLoop = 5; + int loopCount = -1; + while (!cancellation.IsCancellationRequested && loopCount < maxLoop) { + loopCount++; try { var invoice = await _InvoiceRepository.GetInvoice(null, invoiceId, true).ConfigureAwait(false); @@ -122,7 +129,7 @@ namespace BTCPayServer.HostedServices break; } - if (!changed || cancellation.IsCancellationRequested) + if (updateContext.Events.Count == 0 || cancellation.IsCancellationRequested) break; } catch (OperationCanceledException) when (cancellation.IsCancellationRequested) @@ -483,29 +490,31 @@ namespace BTCPayServer.HostedServices { Logs.PayServer.LogInformation("Start watching invoices"); await Task.Delay(1).ConfigureAwait(false); // Small hack so that the caller does not block on GetConsumingEnumerable - ConcurrentDictionary executing = new ConcurrentDictionary(); + ConcurrentDictionary> executing = new ConcurrentDictionary>(); try { + // This loop just make sure an invoice will not be updated at the same time by two tasks. + // If an update is happening while a request come, then the update is deferred when the executing task is over foreach (var item in _WatchRequests.GetConsumingEnumerable(cancellation)) { - bool added = false; - var task = executing.GetOrAdd(item, async i => + var localItem = item; + var toExecute = new Lazy(async () => { try { - added = true; - await UpdateInvoice(i, cancellation); + await UpdateInvoice(localItem, cancellation); } - catch (Exception ex) when (!cancellation.IsCancellationRequested) + finally { - Logs.PayServer.LogCritical(ex, $"Error in the InvoiceWatcher loop (Invoice {i})"); + executing.TryRemove(localItem, out Lazy unused); } - }); - - if (!added && task.Status == TaskStatus.RanToCompletion) + }, false); + var executingTask = executing.GetOrAdd(item, toExecute); + executingTask.Value.GetAwaiter(); // Make sure it run + if (executingTask != toExecute) { - executing.TryRemove(item, out Task t); - _WatchRequests.Add(item); + // What was planned can't run for now, rebook it when the executingTask finish + var unused = executingTask.Value.ContinueWith(t => _WatchRequests.Add(localItem)); } } } @@ -514,7 +523,7 @@ namespace BTCPayServer.HostedServices } finally { - await Task.WhenAll(executing.Values); + await Task.WhenAll(executing.Values.Select(v => v.Value).ToArray()); } Logs.PayServer.LogInformation("Stop watching invoices"); } diff --git a/BTCPayServer/wwwroot/js/core.js b/BTCPayServer/wwwroot/js/core.js index 5de0cf34e..92508c9f8 100644 --- a/BTCPayServer/wwwroot/js/core.js +++ b/BTCPayServer/wwwroot/js/core.js @@ -19,7 +19,7 @@ Vue.config.ignoredElements = [ 'low-fee-timeline', // Ignoring custom HTML5 elements, eg: bp-spinner /^bp-/ -] +]; var checkoutCtrl = new Vue({ el: '#checkoutCtrl', components: { @@ -28,7 +28,7 @@ var checkoutCtrl = new Vue({ data: { srvModel: srvModel } -}) +}); var display = $(".timer-row__time-left"); // Timer container @@ -88,7 +88,7 @@ function emailForm() { $("#emailAddressForm").addClass("ng-touched ng-dirty ng-submitted ng-invalid"); } - }) + }); } /* =============== Even listeners =============== */ @@ -136,7 +136,7 @@ $("#copy-tab").click(function () { $(".payment-tabs__slider").addClass("slide-right"); } - if (!($("#copy").is(".active"))) { + if (!$("#copy").is(".active")) { $("#copy").show(); $("#copy").addClass("active"); @@ -284,7 +284,7 @@ function progressStart(timerMax) { var now = new Date(); var timeDiff = end.getTime() - now.getTime(); - var perc = 100 - Math.round((timeDiff / timerMax) * 100); + var perc = 100 - Math.round(timeDiff / timerMax * 100); if (perc === 75 && (status === "paidPartial" || status === "new")) { $(".timer-row").addClass("expiring-soon");