mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2025-02-21 22:11:48 +01:00
Add Node Info Page
This commit is contained in:
parent
5fd77d9fcc
commit
12c418d84d
9 changed files with 260 additions and 5 deletions
|
@ -0,0 +1,87 @@
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BTCPayServer.Data;
|
||||||
|
using BTCPayServer.Lightning;
|
||||||
|
using BTCPayServer.Models.StoreViewModels;
|
||||||
|
using BTCPayServer.Payments;
|
||||||
|
using BTCPayServer.Payments.Lightning;
|
||||||
|
using BTCPayServer.Services.Stores;
|
||||||
|
using Microsoft.AspNetCore.Mvc;
|
||||||
|
using Microsoft.AspNetCore.Authorization;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Controllers
|
||||||
|
{
|
||||||
|
|
||||||
|
[Route("embed/{storeId}/{cryptoCode}/ln")]
|
||||||
|
[AllowAnonymous]
|
||||||
|
public class PublicLightningNodeInfoController : Controller
|
||||||
|
{
|
||||||
|
private readonly BTCPayNetworkProvider _BtcPayNetworkProvider;
|
||||||
|
private readonly LightningLikePaymentHandler _LightningLikePaymentHandler;
|
||||||
|
private readonly StoreRepository _StoreRepository;
|
||||||
|
|
||||||
|
public PublicLightningNodeInfoController(BTCPayNetworkProvider btcPayNetworkProvider,
|
||||||
|
LightningLikePaymentHandler lightningLikePaymentHandler, StoreRepository storeRepository)
|
||||||
|
{
|
||||||
|
_BtcPayNetworkProvider = btcPayNetworkProvider;
|
||||||
|
_LightningLikePaymentHandler = lightningLikePaymentHandler;
|
||||||
|
_StoreRepository = storeRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
[HttpGet]
|
||||||
|
public async Task<IActionResult> ShowLightningNodeInfo(string storeId, string cryptoCode)
|
||||||
|
{
|
||||||
|
var store = await _StoreRepository.FindStore(storeId);
|
||||||
|
if (store == null)
|
||||||
|
return NotFound();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var paymentMethodDetails = GetExistingLightningSupportedPaymentMethod(cryptoCode, store);
|
||||||
|
var network = _BtcPayNetworkProvider.GetNetwork(cryptoCode);
|
||||||
|
var nodeInfo =
|
||||||
|
await _LightningLikePaymentHandler.GetNodeInfo(paymentMethodDetails,
|
||||||
|
network);
|
||||||
|
|
||||||
|
return View(new ShowLightningNodeInfoViewModel()
|
||||||
|
{
|
||||||
|
Available = true,
|
||||||
|
NodeInfo = nodeInfo.ToString(),
|
||||||
|
CryptoCode = cryptoCode,
|
||||||
|
CryptoImage = GetImage(paymentMethodDetails.PaymentId, network)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return View(new ShowLightningNodeInfoViewModel() {Available = false, CryptoCode = cryptoCode});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private LightningSupportedPaymentMethod GetExistingLightningSupportedPaymentMethod(string cryptoCode, StoreData store)
|
||||||
|
{
|
||||||
|
var id = new PaymentMethodId(cryptoCode, PaymentTypes.LightningLike);
|
||||||
|
var existing = store.GetSupportedPaymentMethods(_BtcPayNetworkProvider)
|
||||||
|
.OfType<LightningSupportedPaymentMethod>()
|
||||||
|
.FirstOrDefault(d => d.PaymentId == id);
|
||||||
|
return existing;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private string GetImage(PaymentMethodId paymentMethodId, BTCPayNetwork network)
|
||||||
|
{
|
||||||
|
var res = paymentMethodId.PaymentType == PaymentTypes.BTCLike
|
||||||
|
? Url.Content(network.CryptoImagePath)
|
||||||
|
: Url.Content(network.LightningImagePath);
|
||||||
|
return "/" + res;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class ShowLightningNodeInfoViewModel
|
||||||
|
{
|
||||||
|
public string NodeInfo { get; set; }
|
||||||
|
public bool Available { get; set; }
|
||||||
|
public string CryptoCode { get; set; }
|
||||||
|
public string CryptoImage { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,7 +27,8 @@ namespace BTCPayServer.Controllers
|
||||||
LightningNodeViewModel vm = new LightningNodeViewModel
|
LightningNodeViewModel vm = new LightningNodeViewModel
|
||||||
{
|
{
|
||||||
CryptoCode = cryptoCode,
|
CryptoCode = cryptoCode,
|
||||||
InternalLightningNode = GetInternalLighningNode(cryptoCode)?.ToString()
|
InternalLightningNode = GetInternalLighningNode(cryptoCode)?.ToString(),
|
||||||
|
StoreId = storeId
|
||||||
};
|
};
|
||||||
SetExistingValues(store, vm);
|
SetExistingValues(store, vm);
|
||||||
return View(vm);
|
return View(vm);
|
||||||
|
@ -154,7 +155,7 @@ namespace BTCPayServer.Controllers
|
||||||
var handler = (LightningLikePaymentHandler)_ServiceProvider.GetRequiredService<IPaymentMethodHandler<Payments.Lightning.LightningSupportedPaymentMethod>>();
|
var handler = (LightningLikePaymentHandler)_ServiceProvider.GetRequiredService<IPaymentMethodHandler<Payments.Lightning.LightningSupportedPaymentMethod>>();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var info = await handler.Test(paymentMethod, network);
|
var info = await handler.GetNodeInfo(paymentMethod, network);
|
||||||
if (!vm.SkipPortTest)
|
if (!vm.SkipPortTest)
|
||||||
{
|
{
|
||||||
using (CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(20)))
|
using (CancellationTokenSource cts = new CancellationTokenSource(TimeSpan.FromSeconds(20)))
|
||||||
|
|
|
@ -10,7 +10,9 @@ using BTCPayServer.Data;
|
||||||
using BTCPayServer.Models;
|
using BTCPayServer.Models;
|
||||||
using BTCPayServer.Models.AppViewModels;
|
using BTCPayServer.Models.AppViewModels;
|
||||||
using BTCPayServer.Models.StoreViewModels;
|
using BTCPayServer.Models.StoreViewModels;
|
||||||
|
using BTCPayServer.Payments;
|
||||||
using BTCPayServer.Payments.Changelly;
|
using BTCPayServer.Payments.Changelly;
|
||||||
|
using BTCPayServer.Payments.Lightning;
|
||||||
using BTCPayServer.Rating;
|
using BTCPayServer.Rating;
|
||||||
using BTCPayServer.Security;
|
using BTCPayServer.Security;
|
||||||
using BTCPayServer.Services;
|
using BTCPayServer.Services;
|
||||||
|
|
|
@ -39,6 +39,7 @@ using BTCPayServer.HostedServices;
|
||||||
using Meziantou.AspNetCore.BundleTagHelpers;
|
using Meziantou.AspNetCore.BundleTagHelpers;
|
||||||
using System.Security.Claims;
|
using System.Security.Claims;
|
||||||
using BTCPayServer.Payments.Changelly;
|
using BTCPayServer.Payments.Changelly;
|
||||||
|
using BTCPayServer.Payments.Lightning;
|
||||||
using BTCPayServer.Security;
|
using BTCPayServer.Security;
|
||||||
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
using Microsoft.AspNetCore.Mvc.ModelBinding;
|
||||||
using NBXplorer.DerivationStrategy;
|
using NBXplorer.DerivationStrategy;
|
||||||
|
@ -132,6 +133,7 @@ namespace BTCPayServer.Hosting
|
||||||
services.AddSingleton<IHostedService, HostedServices.CheckConfigurationHostedService>();
|
services.AddSingleton<IHostedService, HostedServices.CheckConfigurationHostedService>();
|
||||||
|
|
||||||
services.AddSingleton<Payments.IPaymentMethodHandler<Payments.Lightning.LightningSupportedPaymentMethod>, Payments.Lightning.LightningLikePaymentHandler>();
|
services.AddSingleton<Payments.IPaymentMethodHandler<Payments.Lightning.LightningSupportedPaymentMethod>, Payments.Lightning.LightningLikePaymentHandler>();
|
||||||
|
services.AddSingleton<LightningLikePaymentHandler>();
|
||||||
services.AddSingleton<IHostedService, Payments.Lightning.LightningListener>();
|
services.AddSingleton<IHostedService, Payments.Lightning.LightningListener>();
|
||||||
|
|
||||||
services.AddSingleton<ChangellyClientProvider>();
|
services.AddSingleton<ChangellyClientProvider>();
|
||||||
|
|
|
@ -25,5 +25,7 @@ namespace BTCPayServer.Models.StoreViewModels
|
||||||
public string InternalLightningNode { get; internal set; }
|
public string InternalLightningNode { get; internal set; }
|
||||||
public bool SkipPortTest { get; set; }
|
public bool SkipPortTest { get; set; }
|
||||||
public bool Enabled { get; set; } = true;
|
public bool Enabled { get; set; } = true;
|
||||||
|
|
||||||
|
public string StoreId { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,7 +25,7 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
public override async Task<IPaymentMethodDetails> CreatePaymentMethodDetails(LightningSupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod, StoreData store, BTCPayNetwork network, object preparePaymentObject)
|
public override async Task<IPaymentMethodDetails> CreatePaymentMethodDetails(LightningSupportedPaymentMethod supportedPaymentMethod, PaymentMethod paymentMethod, StoreData store, BTCPayNetwork network, object preparePaymentObject)
|
||||||
{
|
{
|
||||||
var storeBlob = store.GetStoreBlob();
|
var storeBlob = store.GetStoreBlob();
|
||||||
var test = Test(supportedPaymentMethod, network);
|
var test = GetNodeInfo(supportedPaymentMethod, network);
|
||||||
var invoice = paymentMethod.ParentEntity;
|
var invoice = paymentMethod.ParentEntity;
|
||||||
var due = Extensions.RoundUp(invoice.ProductInformation.Price / paymentMethod.Rate, 8);
|
var due = Extensions.RoundUp(invoice.ProductInformation.Price / paymentMethod.Rate, 8);
|
||||||
var client = supportedPaymentMethod.CreateClient(network);
|
var client = supportedPaymentMethod.CreateClient(network);
|
||||||
|
@ -63,7 +63,7 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<NodeInfo> Test(LightningSupportedPaymentMethod supportedPaymentMethod, BTCPayNetwork network)
|
public async Task<NodeInfo> GetNodeInfo(LightningSupportedPaymentMethod supportedPaymentMethod, BTCPayNetwork network)
|
||||||
{
|
{
|
||||||
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");
|
||||||
|
@ -78,7 +78,7 @@ namespace BTCPayServer.Payments.Lightning
|
||||||
}
|
}
|
||||||
catch (OperationCanceledException) when (cts.IsCancellationRequested)
|
catch (OperationCanceledException) when (cts.IsCancellationRequested)
|
||||||
{
|
{
|
||||||
throw new PaymentMethodUnavailableException($"The lightning node did not replied in a timely maner");
|
throw new PaymentMethodUnavailableException($"The lightning node did not replied in a timely manner");
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,142 @@
|
||||||
|
@addTagHelper *, Meziantou.AspNetCore.BundleTagHelpers
|
||||||
|
@inject BTCPayServer.HostedServices.CssThemeManager themeManager
|
||||||
|
|
||||||
|
@model BTCPayServer.Controllers.ShowLightningNodeInfoViewModel
|
||||||
|
@{
|
||||||
|
Layout = null;
|
||||||
|
}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>@Model.CryptoCode LN Node Info</title>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<link rel="apple-touch-icon" href="~/img/icons/icon-512x512.png">
|
||||||
|
<link rel="apple-touch-startup-image" href="~/img/splash.png">
|
||||||
|
|
||||||
|
<link rel="manifest" href="~/manifest.json">
|
||||||
|
|
||||||
|
<link href="@this.Context.Request.GetAbsoluteUri(themeManager.BootstrapUri)" rel="stylesheet"/>
|
||||||
|
<link href="~/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet"/>
|
||||||
|
|
||||||
|
<bundle name="wwwroot/bundles/lightning-node-info-bundle.min.js"/>
|
||||||
|
<script type="text/javascript">
|
||||||
|
var srvModel = @Html.Raw(Json.Serialize(Model));
|
||||||
|
|
||||||
|
|
||||||
|
window.onload = function() {
|
||||||
|
Vue.use(Toasted);
|
||||||
|
var app = new Vue({
|
||||||
|
el: '#app',
|
||||||
|
components: {
|
||||||
|
qrcode: VueQr
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
srvModel: srvModel
|
||||||
|
},
|
||||||
|
mounted: function() {
|
||||||
|
setTimeout(function() {
|
||||||
|
var copyInput = new Clipboard('.copy',
|
||||||
|
{
|
||||||
|
target: function(trigger) {
|
||||||
|
Vue.toasted.show('Copied',
|
||||||
|
{
|
||||||
|
iconPack: "fontawesome",
|
||||||
|
icon: "copy",
|
||||||
|
duration: 5000
|
||||||
|
});
|
||||||
|
return trigger;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
500);
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<style>
|
||||||
|
.qr-icon {
|
||||||
|
height: 64px;
|
||||||
|
width: 64px;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.qr-container {
|
||||||
|
position: relative;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.copy {
|
||||||
|
cursor: copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body >
|
||||||
|
<noscript>
|
||||||
|
<div class="container">
|
||||||
|
<div class="col-md-8 col-sm-12 col-lg-6 mx-auto my-auto ">
|
||||||
|
<div class="card border-0">
|
||||||
|
<div class="row"></div>
|
||||||
|
<h1 class="card-title text-center">
|
||||||
|
@Model.CryptoCode Lightning Node - @(Model.Available? "Online" : "Unavailable")
|
||||||
|
<small class="@(Model.Available? "text-success" : "text-danger")">
|
||||||
|
<span class="fa fa-circle "></span>
|
||||||
|
</small>
|
||||||
|
</h1>
|
||||||
|
@if (Model.Available)
|
||||||
|
{
|
||||||
|
<div class="card-body m-sm-0 p-sm-0" >
|
||||||
|
<div class="input-group">
|
||||||
|
<input type="text" class="form-control " readonly="readonly" asp-for="NodeInfo" id="peer-info"/>
|
||||||
|
<div class="input-group-append">
|
||||||
|
<span class="input-group-text fa fa-copy"> </span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</noscript>
|
||||||
|
<div id="app" class="container">
|
||||||
|
<div class="row " style="height: 100vh">
|
||||||
|
<div class="col-md-8 col-sm-12 col-lg-6 mx-auto my-auto ">
|
||||||
|
<div class="card border-0">
|
||||||
|
<div class="row"></div>
|
||||||
|
<h1 class="card-title text-center">
|
||||||
|
{{srvModel.cryptoCode}} Lightning Node
|
||||||
|
- {{srvModel.available? "Online" : "Unavailable"}}
|
||||||
|
<small v-bind:class="{ 'text-success': srvModel.available, 'text-danger': !srvModel.available }">
|
||||||
|
<span class="fa fa-circle "></span>
|
||||||
|
</small>
|
||||||
|
</h1>
|
||||||
|
<div class="card-body m-sm-0 p-sm-0" v-if="srvModel.available">
|
||||||
|
<div class="qr-container mb-2">
|
||||||
|
<img v-bind:src="srvModel.cryptoImage" class="qr-icon"/>
|
||||||
|
<qrcode v-bind:val="srvModel.nodeInfo" v-bind:size="256" bg-color="#f5f5f7" fg-color="#000">
|
||||||
|
</qrcode>
|
||||||
|
</div>
|
||||||
|
<div class="input-group copy" data-clipboard-target="#peer-info">
|
||||||
|
<input type="text" class=" form-control " readonly="readonly" :value="srvModel.nodeInfo" id="peer-info"/>
|
||||||
|
<div class="input-group-append">
|
||||||
|
<span class="input-group-text fa fa-copy"> </span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -85,6 +85,15 @@
|
||||||
</div>
|
</div>
|
||||||
<button name="command" type="submit" value="save" class="btn btn-primary">Submit</button>
|
<button name="command" type="submit" value="save" class="btn btn-primary">Submit</button>
|
||||||
<button name="command" type="submit" value="test" class="btn btn-secondary">Test connection</button>
|
<button name="command" type="submit" value="test" class="btn btn-secondary">Test connection</button>
|
||||||
|
<a
|
||||||
|
class="btn btn-secondary"
|
||||||
|
asp-controller="PublicLightningNodeInfo"
|
||||||
|
asp-action="ShowLightningNodeInfo"
|
||||||
|
asp-route-cryptoCode="@Model.CryptoCode"
|
||||||
|
asp-route-storeId="@Model.StoreId"
|
||||||
|
target="_blank">
|
||||||
|
Open Public Node Info Page
|
||||||
|
</a>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -53,6 +53,16 @@
|
||||||
"wwwroot/checkout/**/*.js"
|
"wwwroot/checkout/**/*.js"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"outputFileName": "wwwroot/bundles/lightning-node-info-bundle.min.js",
|
||||||
|
"inputFiles": [
|
||||||
|
"wwwroot/vendor/clipboard.js/clipboard.js",
|
||||||
|
"wwwroot/vendor/jquery/jquery.js",
|
||||||
|
"wwwroot/vendor/vuejs/vue.min.js",
|
||||||
|
"wwwroot/vendor/vuejs/vue-qrcode.js",
|
||||||
|
"wwwroot/vendor/vue-toasted/vue-toasted.min.js"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"outputFileName": "wwwroot/bundles/cart-bundle.min.js",
|
"outputFileName": "wwwroot/bundles/cart-bundle.min.js",
|
||||||
"inputFiles": [
|
"inputFiles": [
|
||||||
|
|
Loading…
Add table
Reference in a new issue