mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-22 14:22:40 +01:00
Improve public LN node info (#2876)
* Add store name to LN info unavailable pae * Display multiple node info items if available Allows to view clearnet and Tor connection info side by side. * Re-add preferOnion for certain cases * HTML compatible node ids * Display more node connection failure details * Fix syntax error * Update BTCPayServer/Payments/Lightning/LightningLikePaymentHandler.cs Co-authored-by: Nicolas Dorier <nicolas.dorier@gmail.com> * View updates * Revert previous variable change * Keep logic out of the view Co-authored-by: Nicolas Dorier <nicolas.dorier@gmail.com>
This commit is contained in:
parent
5d8bc73063
commit
7f49824783
4 changed files with 73 additions and 25 deletions
|
@ -3,6 +3,7 @@ using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using BTCPayServer.Data;
|
using BTCPayServer.Data;
|
||||||
using BTCPayServer.Filters;
|
using BTCPayServer.Filters;
|
||||||
|
using BTCPayServer.Lightning;
|
||||||
using BTCPayServer.Payments;
|
using BTCPayServer.Payments;
|
||||||
using BTCPayServer.Payments.Lightning;
|
using BTCPayServer.Payments.Lightning;
|
||||||
using BTCPayServer.Services.Stores;
|
using BTCPayServer.Services.Stores;
|
||||||
|
@ -40,14 +41,12 @@ namespace BTCPayServer.Controllers
|
||||||
{
|
{
|
||||||
var paymentMethodDetails = GetExistingLightningSupportedPaymentMethod(cryptoCode, store);
|
var paymentMethodDetails = GetExistingLightningSupportedPaymentMethod(cryptoCode, store);
|
||||||
var network = _BtcPayNetworkProvider.GetNetwork<BTCPayNetwork>(cryptoCode);
|
var network = _BtcPayNetworkProvider.GetNetwork<BTCPayNetwork>(cryptoCode);
|
||||||
var nodeInfo =
|
var nodeInfo = await _LightningLikePaymentHandler.GetNodeInfo(paymentMethodDetails, network);
|
||||||
await _LightningLikePaymentHandler.GetNodeInfo(Request.IsOnion(), paymentMethodDetails,
|
|
||||||
network);
|
|
||||||
|
|
||||||
return View(new ShowLightningNodeInfoViewModel
|
return View(new ShowLightningNodeInfoViewModel
|
||||||
{
|
{
|
||||||
Available = true,
|
Available = true,
|
||||||
NodeInfo = nodeInfo.ToString(),
|
NodeInfo = nodeInfo.Select(n => new ShowLightningNodeInfoViewModel.NodeData(n)).ToArray(),
|
||||||
CryptoCode = cryptoCode,
|
CryptoCode = cryptoCode,
|
||||||
CryptoImage = GetImage(paymentMethodDetails.PaymentId, network),
|
CryptoImage = GetImage(paymentMethodDetails.PaymentId, network),
|
||||||
StoreName = store.StoreName
|
StoreName = store.StoreName
|
||||||
|
@ -55,7 +54,12 @@ namespace BTCPayServer.Controllers
|
||||||
}
|
}
|
||||||
catch (Exception)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
return View(new ShowLightningNodeInfoViewModel { Available = false, CryptoCode = cryptoCode });
|
return View(new ShowLightningNodeInfoViewModel
|
||||||
|
{
|
||||||
|
Available = false,
|
||||||
|
CryptoCode = cryptoCode,
|
||||||
|
StoreName = store.StoreName
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,9 +82,26 @@ namespace BTCPayServer.Controllers
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public class ShowLightningNodeInfoViewModel
|
public class ShowLightningNodeInfoViewModel
|
||||||
{
|
{
|
||||||
public string NodeInfo { get; set; }
|
public class NodeData
|
||||||
|
{
|
||||||
|
string _connection;
|
||||||
|
public NodeData(NodeInfo nodeInfo)
|
||||||
|
{
|
||||||
|
_connection = nodeInfo.ToString();
|
||||||
|
Id = $"{nodeInfo.Host}-{nodeInfo.Port}".Replace(".", "-", StringComparison.OrdinalIgnoreCase);
|
||||||
|
IsTor = nodeInfo.IsTor;
|
||||||
|
}
|
||||||
|
public string Id { get; }
|
||||||
|
public bool IsTor { get; }
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return _connection;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public NodeData[] NodeInfo { get; set; }
|
||||||
public bool Available { get; set; }
|
public bool Available { get; set; }
|
||||||
public string CryptoCode { get; set; }
|
public string CryptoCode { get; set; }
|
||||||
public string CryptoImage { get; set; }
|
public string CryptoImage { get; set; }
|
||||||
|
|
|
@ -109,13 +109,13 @@ namespace BTCPayServer.Controllers
|
||||||
var handler = _ServiceProvider.GetRequiredService<LightningLikePaymentHandler>();
|
var handler = _ServiceProvider.GetRequiredService<LightningLikePaymentHandler>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var info = await handler.GetNodeInfo(Request.IsOnion(), paymentMethod, network);
|
var info = await handler.GetNodeInfo(paymentMethod, network, Request.IsOnion());
|
||||||
if (!vm.SkipPortTest)
|
if (!vm.SkipPortTest)
|
||||||
{
|
{
|
||||||
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
|
using var cts = new CancellationTokenSource(TimeSpan.FromSeconds(20));
|
||||||
await handler.TestConnection(info, cts.Token);
|
await handler.TestConnection(info.First(), cts.Token);
|
||||||
}
|
}
|
||||||
TempData[WellKnownTempData.SuccessMessage] = $"Connection to the Lightning node successful. Your node address: {info}";
|
TempData[WellKnownTempData.SuccessMessage] = $"Connection to the Lightning node successful. Your node address: {info.First()}";
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -68,7 +68,7 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
}
|
}
|
||||||
//direct casting to (BTCPayNetwork) is fixed in other pull requests with better generic interfacing for handlers
|
//direct casting to (BTCPayNetwork) is fixed in other pull requests with better generic interfacing for handlers
|
||||||
var storeBlob = store.GetStoreBlob();
|
var storeBlob = store.GetStoreBlob();
|
||||||
var test = GetNodeInfo(paymentMethod.PreferOnion, supportedPaymentMethod, network);
|
var test = GetNodeInfo(supportedPaymentMethod, network, paymentMethod.PreferOnion);
|
||||||
|
|
||||||
var invoice = paymentMethod.ParentEntity;
|
var invoice = paymentMethod.ParentEntity;
|
||||||
decimal due = Extensions.RoundUp(invoice.Price / paymentMethod.Rate, network.Divisibility);
|
decimal due = Extensions.RoundUp(invoice.Price / paymentMethod.Rate, network.Divisibility);
|
||||||
|
@ -108,17 +108,18 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
throw new PaymentMethodUnavailableException($"Impossible to create lightning invoice ({ex.Message})", ex);
|
throw new PaymentMethodUnavailableException($"Impossible to create lightning invoice ({ex.Message})", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var nodeInfo = await test;
|
var nodeInfo = await test;
|
||||||
return new LightningLikePaymentMethodDetails
|
return new LightningLikePaymentMethodDetails
|
||||||
{
|
{
|
||||||
Activated = true,
|
Activated = true,
|
||||||
BOLT11 = lightningInvoice.BOLT11,
|
BOLT11 = lightningInvoice.BOLT11,
|
||||||
InvoiceId = lightningInvoice.Id,
|
InvoiceId = lightningInvoice.Id,
|
||||||
NodeInfo = nodeInfo.ToString()
|
NodeInfo = nodeInfo.First().ToString()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<NodeInfo> GetNodeInfo(bool preferOnion, LightningSupportedPaymentMethod supportedPaymentMethod, BTCPayNetwork network)
|
public async Task<NodeInfo[]> GetNodeInfo(LightningSupportedPaymentMethod supportedPaymentMethod, BTCPayNetwork network, bool? preferOnion = null)
|
||||||
{
|
{
|
||||||
if (!_Dashboard.IsFullySynched(network.CryptoCode, out var summary))
|
if (!_Dashboard.IsFullySynched(network.CryptoCode, out var summary))
|
||||||
throw new PaymentMethodUnavailableException("Full node not available");
|
throw new PaymentMethodUnavailableException("Full node not available");
|
||||||
|
@ -137,10 +138,15 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
throw new PaymentMethodUnavailableException($"Error while connecting to the API ({ex.Message})");
|
throw new PaymentMethodUnavailableException($"Error while connecting to the API: {ex.Message}" +
|
||||||
|
(!string.IsNullOrEmpty(ex.InnerException?.Message) ? $" ({ex.InnerException.Message})" : ""));
|
||||||
}
|
}
|
||||||
var nodeInfo = info.NodeInfoList.FirstOrDefault(i => i.IsTor == preferOnion) ?? info.NodeInfoList.FirstOrDefault();
|
|
||||||
if (nodeInfo == null)
|
var nodeInfo = preferOnion != null && info.NodeInfoList.Any(i => i.IsTor == preferOnion)
|
||||||
|
? info.NodeInfoList.Where(i => i.IsTor == preferOnion.Value).ToArray()
|
||||||
|
: info.NodeInfoList.Select(i => i).ToArray();
|
||||||
|
|
||||||
|
if (!nodeInfo.Any())
|
||||||
{
|
{
|
||||||
throw new PaymentMethodUnavailableException("No lightning node public address has been configured");
|
throw new PaymentMethodUnavailableException("No lightning node public address has been configured");
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
@addTagHelper *, BundlerMinifier.TagHelpers
|
@addTagHelper *, BundlerMinifier.TagHelpers
|
||||||
@inject ISettingsRepository _settingsRepository
|
@inject ISettingsRepository _settingsRepository
|
||||||
|
|
||||||
@using BTCPayServer.Abstractions.Contracts
|
@using BTCPayServer.Abstractions.Contracts
|
||||||
|
@using BTCPayServer.Lightning
|
||||||
@model BTCPayServer.Controllers.ShowLightningNodeInfoViewModel
|
@model BTCPayServer.Controllers.ShowLightningNodeInfoViewModel
|
||||||
@{
|
@{
|
||||||
Layout = null;
|
Layout = null;
|
||||||
|
@ -28,7 +29,7 @@
|
||||||
<div class="card border-0">
|
<div class="card border-0">
|
||||||
<div class="card-body p-4">
|
<div class="card-body p-4">
|
||||||
<h1 class="card-title text-center">@Model.StoreName</h1>
|
<h1 class="card-title text-center">@Model.StoreName</h1>
|
||||||
<h2 class="card-subtitle text-center text-secondary mb-2">
|
<h2 class="card-subtitle text-center text-secondary my-3">
|
||||||
<span>@Model.CryptoCode</span>
|
<span>@Model.CryptoCode</span>
|
||||||
Lightning Node
|
Lightning Node
|
||||||
</h2>
|
</h2>
|
||||||
|
@ -42,13 +43,33 @@
|
||||||
</h3>
|
</h3>
|
||||||
@if (Model.Available)
|
@if (Model.Available)
|
||||||
{
|
{
|
||||||
|
@if (Model.NodeInfo.Length > 1)
|
||||||
|
{
|
||||||
|
<ul class="nav nav-pills justify-content-center mt-4" id="nodeInfo-tab" role="tablist">
|
||||||
|
@for (int i = 0; i < Model.NodeInfo.Length; i++)
|
||||||
|
{
|
||||||
|
var nodeInfo = Model.NodeInfo[i];
|
||||||
|
<li class="nav-item" role="presentation">
|
||||||
|
<button class="nav-link w-100px @(i == 0 ? "active" : "")" id="nodeInfo-tab-@nodeInfo.Id" data-bs-toggle="pill" data-bs-target="#nodeInfo-@nodeInfo.Id" type="button" role="tab" aria-controls="nodeInfo-@nodeInfo.Id" aria-selected="true">@(Model.NodeInfo[i].IsTor ? "Tor" : "Clearnet")</button>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
<div class="tab-content" id="nodeInfo-tabContent">
|
||||||
|
@for (int i = 0; i < Model.NodeInfo.Length; i++)
|
||||||
|
{
|
||||||
|
var nodeInfo = Model.NodeInfo[i];
|
||||||
|
<div class="tab-pane fade @(i == 0 ? "show active" : "")" id="nodeInfo-@nodeInfo.Id" role="tabpanel" aria-labelledby="nodeInfo-tab-@nodeInfo.Id">
|
||||||
<div class="qr-container my-3">
|
<div class="qr-container my-3">
|
||||||
<img alt="@Model.CryptoCode" class="qr-icon" src="@Model.CryptoImage" />
|
<img alt="@Model.CryptoCode" class="qr-icon" src="@Model.CryptoImage"/>
|
||||||
<vc:qr-code data="@Model.NodeInfo"> </vc:qr-code>
|
<vc:qr-code data="@nodeInfo.ToString()"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-group d-flex" data-clipboard="@Model.NodeInfo">
|
<div class="input-group" data-clipboard="@nodeInfo.ToString()">
|
||||||
<input type="text" class="form-control" style="cursor: copy" readonly="readonly" value="@Model.NodeInfo" id="peer-info"/>
|
<input type="text" class="form-control" style="cursor:copy" readonly="readonly" value="@nodeInfo.ToString()" id="nodeInfo-addr-@nodeInfo.Id"/>
|
||||||
<button type="button" class="btn btn-outline-secondary" data-clipboard-confirm>Copy node info</button>
|
<button type="button" class="btn btn-outline-secondary" data-clipboard-confirm>Copy</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
@ -56,6 +77,6 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<script src="~/js/copy-to-clipboard.js" asp-append-version="true"></script>
|
<partial name="LayoutFoot" />
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
Loading…
Add table
Reference in a new issue