mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-03-10 09:19:24 +01:00
Make LightningListener nullable, fix some NRE
This commit is contained in:
parent
0c78e9e4ac
commit
6193835ea1
1 changed files with 55 additions and 42 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
#nullable enable
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
@ -38,7 +39,7 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
private readonly StoreRepository _storeRepository;
|
private readonly StoreRepository _storeRepository;
|
||||||
private readonly PaymentService _paymentService;
|
private readonly PaymentService _paymentService;
|
||||||
readonly Channel<string> _CheckInvoices = Channel.CreateUnbounded<string>();
|
readonly Channel<string> _CheckInvoices = Channel.CreateUnbounded<string>();
|
||||||
Task _CheckingInvoice;
|
Task? _CheckingInvoice;
|
||||||
readonly Dictionary<(string, string), LightningInstanceListener> _InstanceListeners = new Dictionary<(string, string), LightningInstanceListener>();
|
readonly Dictionary<(string, string), LightningInstanceListener> _InstanceListeners = new Dictionary<(string, string), LightningInstanceListener>();
|
||||||
|
|
||||||
public LightningListener(EventAggregator aggregator,
|
public LightningListener(EventAggregator aggregator,
|
||||||
|
@ -87,12 +88,15 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
var invoice = await GetInvoice(invoiceId);
|
var invoice = await GetInvoice(invoiceId);
|
||||||
foreach (var listenedInvoice in GetListenedInvoices(invoice))
|
foreach (var listenedInvoice in GetListenedInvoices(invoice))
|
||||||
{
|
{
|
||||||
var instanceListenerKey = (listenedInvoice.Network.CryptoCode, GetLightningUrl(listenedInvoice.SupportedPaymentMethod).ToString());
|
var connStr = GetLightningUrl(listenedInvoice.SupportedPaymentMethod);
|
||||||
|
if (connStr is null)
|
||||||
|
continue;
|
||||||
|
var instanceListenerKey = (listenedInvoice.Network.CryptoCode, connStr.ToString());
|
||||||
lock (_InstanceListeners)
|
lock (_InstanceListeners)
|
||||||
{
|
{
|
||||||
if (!_InstanceListeners.TryGetValue(instanceListenerKey, out var instanceListener))
|
if (!_InstanceListeners.TryGetValue(instanceListenerKey, out var instanceListener))
|
||||||
{
|
{
|
||||||
instanceListener ??= new LightningInstanceListener(_InvoiceRepository, _Aggregator, lightningClientFactory, listenedInvoice.Network, GetLightningUrl(listenedInvoice.SupportedPaymentMethod), _paymentService, Logs);
|
instanceListener ??= new LightningInstanceListener(_InvoiceRepository, _Aggregator, lightningClientFactory, listenedInvoice.Network, connStr, _paymentService, Logs);
|
||||||
_InstanceListeners.TryAdd(instanceListenerKey, instanceListener);
|
_InstanceListeners.TryAdd(instanceListenerKey, instanceListener);
|
||||||
}
|
}
|
||||||
instanceListener.AddListenedInvoice(listenedInvoice);
|
instanceListener.AddListenedInvoice(listenedInvoice);
|
||||||
|
@ -143,7 +147,7 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
.Where(c => new[] { PaymentTypes.LightningLike, LNURLPayPaymentType.Instance }.Contains(c.GetId().PaymentType)))
|
.Where(c => new[] { PaymentTypes.LightningLike, LNURLPayPaymentType.Instance }.Contains(c.GetId().PaymentType)))
|
||||||
{
|
{
|
||||||
LightningLikePaymentMethodDetails lightningMethod;
|
LightningLikePaymentMethodDetails lightningMethod;
|
||||||
LightningSupportedPaymentMethod lightningSupportedMethod;
|
LightningSupportedPaymentMethod? lightningSupportedMethod;
|
||||||
switch (paymentMethod.GetPaymentMethodDetails())
|
switch (paymentMethod.GetPaymentMethodDetails())
|
||||||
{
|
{
|
||||||
case LNURLPayPaymentMethodDetails lnurlPayPaymentMethodDetails:
|
case LNURLPayPaymentMethodDetails lnurlPayPaymentMethodDetails:
|
||||||
|
@ -167,16 +171,17 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
continue;
|
continue;
|
||||||
var network = _NetworkProvider.GetNetwork<BTCPayNetwork>(paymentMethod.GetId().CryptoCode);
|
var network = _NetworkProvider.GetNetwork<BTCPayNetwork>(paymentMethod.GetId().CryptoCode);
|
||||||
|
|
||||||
listenedInvoices.Add(new ListenedInvoice()
|
var lnUri = GetLightningUrl(lightningSupportedMethod);
|
||||||
{
|
if (lnUri == null)
|
||||||
Expiration = invoice.ExpirationTime,
|
continue;
|
||||||
Uri = GetLightningUrl(lightningSupportedMethod).BaseUri.AbsoluteUri,
|
listenedInvoices.Add(new ListenedInvoice(
|
||||||
PaymentMethodDetails = lightningMethod,
|
lnUri.BaseUri,
|
||||||
SupportedPaymentMethod = lightningSupportedMethod,
|
invoice.ExpirationTime,
|
||||||
PaymentMethod = paymentMethod,
|
lightningMethod,
|
||||||
Network = network,
|
lightningSupportedMethod,
|
||||||
InvoiceId = invoice.Id
|
paymentMethod,
|
||||||
});
|
network,
|
||||||
|
invoice.Id));
|
||||||
}
|
}
|
||||||
return listenedInvoices;
|
return listenedInvoices;
|
||||||
}
|
}
|
||||||
|
@ -262,6 +267,8 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
.Where(method => new[] { PaymentTypes.LightningLike, LNURLPayPaymentType.Instance }.Contains(method.GetId().PaymentType))
|
.Where(method => new[] { PaymentTypes.LightningLike, LNURLPayPaymentType.Instance }.Contains(method.GetId().PaymentType))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
var store = await _storeRepository.FindStore(invoice.StoreId);
|
var store = await _storeRepository.FindStore(invoice.StoreId);
|
||||||
|
if (store is null)
|
||||||
|
return;
|
||||||
if (paymentMethods.Any())
|
if (paymentMethods.Any())
|
||||||
{
|
{
|
||||||
var logs = new InvoiceLogs();
|
var logs = new InvoiceLogs();
|
||||||
|
@ -334,9 +341,11 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
.CreatePaymentMethodDetails(logs, supportedMethod, paymentMethod, store,
|
.CreatePaymentMethodDetails(logs, supportedMethod, paymentMethod, store,
|
||||||
paymentMethod.Network, prepObj, pmis));
|
paymentMethod.Network, prepObj, pmis));
|
||||||
|
|
||||||
var instanceListenerKey = (paymentMethod.Network.CryptoCode,
|
var connStr = GetLightningUrl(supportedMethod);
|
||||||
GetLightningUrl(supportedMethod).ToString());
|
if (connStr is null)
|
||||||
LightningInstanceListener instanceListener;
|
continue;
|
||||||
|
var instanceListenerKey = (paymentMethod.Network.CryptoCode, connStr.ToString());
|
||||||
|
LightningInstanceListener? instanceListener;
|
||||||
lock (_InstanceListeners)
|
lock (_InstanceListeners)
|
||||||
{
|
{
|
||||||
_InstanceListeners.TryGetValue(instanceListenerKey, out instanceListener);
|
_InstanceListeners.TryGetValue(instanceListenerKey, out instanceListener);
|
||||||
|
@ -346,16 +355,17 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
await _InvoiceRepository.NewPaymentDetails(invoice.Id, newPaymentMethodDetails,
|
await _InvoiceRepository.NewPaymentDetails(invoice.Id, newPaymentMethodDetails,
|
||||||
paymentMethod.Network);
|
paymentMethod.Network);
|
||||||
|
|
||||||
instanceListener.AddListenedInvoice(new ListenedInvoice()
|
var url = GetLightningUrl(supportedMethod);
|
||||||
{
|
if (url is null)
|
||||||
Expiration = invoice.ExpirationTime,
|
continue;
|
||||||
Uri = GetLightningUrl(supportedMethod).BaseUri.AbsoluteUri,
|
instanceListener.AddListenedInvoice(new ListenedInvoice(
|
||||||
PaymentMethodDetails = newPaymentMethodDetails,
|
url.BaseUri,
|
||||||
SupportedPaymentMethod = supportedMethod,
|
invoice.ExpirationTime,
|
||||||
PaymentMethod = paymentMethod,
|
newPaymentMethodDetails,
|
||||||
Network = (BTCPayNetwork)paymentMethod.Network,
|
supportedMethod,
|
||||||
InvoiceId = invoice.Id
|
paymentMethod,
|
||||||
});
|
(BTCPayNetwork)paymentMethod.Network,
|
||||||
|
invoice.Id));
|
||||||
|
|
||||||
_Aggregator.Publish(new Events.InvoiceNewPaymentDetailsEvent(invoice.Id,
|
_Aggregator.Publish(new Events.InvoiceNewPaymentDetailsEvent(invoice.Id,
|
||||||
newPaymentMethodDetails, paymentMethod.GetId()));
|
newPaymentMethodDetails, paymentMethod.GetId()));
|
||||||
|
@ -374,14 +384,14 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private LightningConnectionString GetLightningUrl(LightningSupportedPaymentMethod supportedMethod)
|
private LightningConnectionString? GetLightningUrl(LightningSupportedPaymentMethod supportedMethod)
|
||||||
{
|
{
|
||||||
var url = supportedMethod.GetExternalLightningUrl();
|
var url = supportedMethod.GetExternalLightningUrl();
|
||||||
if (url != null)
|
if (url != null)
|
||||||
return url;
|
return url;
|
||||||
if (Options.Value.InternalLightningByCryptoCode.TryGetValue(supportedMethod.CryptoCode, out var conn))
|
if (Options.Value.InternalLightningByCryptoCode.TryGetValue(supportedMethod.CryptoCode, out var conn))
|
||||||
return conn;
|
return conn;
|
||||||
throw new InvalidOperationException($"{supportedMethod.CryptoCode}: The internal lightning node is not set up");
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
TimeSpan _PollInterval = TimeSpan.FromMinutes(1.0);
|
TimeSpan _PollInterval = TimeSpan.FromMinutes(1.0);
|
||||||
|
@ -400,7 +410,7 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
private Timer _ListenPoller;
|
private Timer? _ListenPoller;
|
||||||
|
|
||||||
public IOptions<LightningNetworkOptions> Options { get; }
|
public IOptions<LightningNetworkOptions> Options { get; }
|
||||||
|
|
||||||
|
@ -412,6 +422,7 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
_Cts.Cancel();
|
_Cts.Cancel();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
if (_CheckingInvoice != null)
|
||||||
await _CheckingInvoice;
|
await _CheckingInvoice;
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
|
@ -420,7 +431,7 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
}
|
}
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
await Task.WhenAll(_ListeningInstances.Select(c => c.Value.Listening).ToArray());
|
await Task.WhenAll(_ListeningInstances.Select(c => c.Value.Listening).Where(c => c != null).ToArray()!);
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException)
|
catch (OperationCanceledException)
|
||||||
{
|
{
|
||||||
|
@ -479,7 +490,7 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
|
|
||||||
public bool Empty => _ListenedInvoices.IsEmpty;
|
public bool Empty => _ListenedInvoices.IsEmpty;
|
||||||
public bool IsListening => Listening?.Status is TaskStatus.Running || Listening?.Status is TaskStatus.WaitingForActivation;
|
public bool IsListening => Listening?.Status is TaskStatus.Running || Listening?.Status is TaskStatus.WaitingForActivation;
|
||||||
public Task Listening { get; set; }
|
public Task? Listening { get; set; }
|
||||||
public void EnsureListening(CancellationToken cancellation)
|
public void EnsureListening(CancellationToken cancellation)
|
||||||
{
|
{
|
||||||
if (!IsListening)
|
if (!IsListening)
|
||||||
|
@ -490,7 +501,7 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
Listening = Listen(StopListeningCancellationTokenSource.Token);
|
Listening = Listen(StopListeningCancellationTokenSource.Token);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public CancellationTokenSource StopListeningCancellationTokenSource;
|
public CancellationTokenSource? StopListeningCancellationTokenSource;
|
||||||
async Task Listen(CancellationToken cancellation)
|
async Task Listen(CancellationToken cancellation)
|
||||||
{
|
{
|
||||||
Logs.PayServer.LogInformation($"{_network.CryptoCode} (Lightning): Start listening {ConnectionString.BaseUri}");
|
Logs.PayServer.LogInformation($"{_network.CryptoCode} (Lightning): Start listening {ConnectionString.BaseUri}");
|
||||||
|
@ -566,6 +577,8 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
|
|
||||||
public async Task<bool> AddPayment(LightningInvoice notification, string invoiceId, PaymentType paymentType)
|
public async Task<bool> AddPayment(LightningInvoice notification, string invoiceId, PaymentType paymentType)
|
||||||
{
|
{
|
||||||
|
if (notification?.PaidAt is null)
|
||||||
|
return false;
|
||||||
var payment = await _paymentService.AddPayment(invoiceId, notification.PaidAt.Value, new LightningLikePaymentData
|
var payment = await _paymentService.AddPayment(invoiceId, notification.PaidAt.Value, new LightningLikePaymentData
|
||||||
{
|
{
|
||||||
BOLT11 = notification.BOLT11,
|
BOLT11 = notification.BOLT11,
|
||||||
|
@ -595,15 +608,15 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ListenedInvoice
|
public record ListenedInvoice(
|
||||||
|
Uri Uri,
|
||||||
|
DateTimeOffset Expiration,
|
||||||
|
LightningLikePaymentMethodDetails PaymentMethodDetails,
|
||||||
|
LightningSupportedPaymentMethod SupportedPaymentMethod,
|
||||||
|
PaymentMethod PaymentMethod,
|
||||||
|
BTCPayNetwork Network,
|
||||||
|
string InvoiceId)
|
||||||
{
|
{
|
||||||
public bool IsExpired() { return DateTimeOffset.UtcNow > Expiration; }
|
public bool IsExpired() { return DateTimeOffset.UtcNow > Expiration; }
|
||||||
public DateTimeOffset Expiration { get; set; }
|
|
||||||
public LightningLikePaymentMethodDetails PaymentMethodDetails { get; set; }
|
|
||||||
public LightningSupportedPaymentMethod SupportedPaymentMethod { get; set; }
|
|
||||||
public PaymentMethod PaymentMethod { get; set; }
|
|
||||||
public string Uri { get; internal set; }
|
|
||||||
public BTCPayNetwork Network { get; internal set; }
|
|
||||||
public string InvoiceId { get; internal set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue