mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2025-12-18 06:24:24 +01:00
Lightning charge integration
This commit is contained in:
@@ -136,6 +136,9 @@
|
|||||||
<Content Update="Views\Home\BitpayTranslator.cshtml">
|
<Content Update="Views\Home\BitpayTranslator.cshtml">
|
||||||
<Pack>$(IncludeRazorContentInPack)</Pack>
|
<Pack>$(IncludeRazorContentInPack)</Pack>
|
||||||
</Content>
|
</Content>
|
||||||
|
<Content Update="Views\Server\LightningChargeServices.cshtml">
|
||||||
|
<Pack>$(IncludeRazorContentInPack)</Pack>
|
||||||
|
</Content>
|
||||||
<Content Update="Views\Server\SparkServices.cshtml">
|
<Content Update="Views\Server\SparkServices.cshtml">
|
||||||
<Pack>$(IncludeRazorContentInPack)</Pack>
|
<Pack>$(IncludeRazorContentInPack)</Pack>
|
||||||
</Content>
|
</Content>
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ namespace BTCPayServer.Configuration
|
|||||||
public static LogEventLevel GetDebugLogLevel(IConfiguration configuration)
|
public static LogEventLevel GetDebugLogLevel(IConfiguration configuration)
|
||||||
{
|
{
|
||||||
var raw = configuration.GetValue("debugloglevel", nameof(LogEventLevel.Debug));
|
var raw = configuration.GetValue("debugloglevel", nameof(LogEventLevel.Debug));
|
||||||
return (LogEventLevel)Enum.Parse(typeof(LogEventLevel), raw, true);
|
return (LogEventLevel)Enum.Parse(typeof(LogEventLevel), raw, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void LoadArgs(IConfiguration conf)
|
public void LoadArgs(IConfiguration conf)
|
||||||
@@ -139,7 +139,7 @@ namespace BTCPayServer.Configuration
|
|||||||
externalLnd<ExternalLndRest>($"{net.CryptoCode}.external.lnd.rest", "lnd-rest");
|
externalLnd<ExternalLndRest>($"{net.CryptoCode}.external.lnd.rest", "lnd-rest");
|
||||||
|
|
||||||
var spark = conf.GetOrDefault<string>($"{net.CryptoCode}.external.spark", string.Empty);
|
var spark = conf.GetOrDefault<string>($"{net.CryptoCode}.external.spark", string.Empty);
|
||||||
if(spark.Length != 0)
|
if (spark.Length != 0)
|
||||||
{
|
{
|
||||||
if (!SparkConnectionString.TryParse(spark, out var connectionString))
|
if (!SparkConnectionString.TryParse(spark, out var connectionString))
|
||||||
{
|
{
|
||||||
@@ -148,14 +148,30 @@ namespace BTCPayServer.Configuration
|
|||||||
}
|
}
|
||||||
ExternalServicesByCryptoCode.Add(net.CryptoCode, new ExternalSpark(connectionString));
|
ExternalServicesByCryptoCode.Add(net.CryptoCode, new ExternalSpark(connectionString));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var charge = conf.GetOrDefault<string>($"{net.CryptoCode}.external.charge", string.Empty);
|
||||||
|
if (charge.Length != 0)
|
||||||
|
{
|
||||||
|
if (!LightningConnectionString.TryParse(charge, false, out var chargeConnectionString, out var chargeError))
|
||||||
|
LightningConnectionString.TryParse("type=charge;" + charge, false, out chargeConnectionString, out chargeError);
|
||||||
|
|
||||||
|
if(chargeConnectionString == null || chargeConnectionString.ConnectionType != LightningConnectionType.Charge)
|
||||||
|
{
|
||||||
|
throw new ConfigException($"Invalid setting {net.CryptoCode}.external.charge, " + Environment.NewLine +
|
||||||
|
$"lightning charge server: 'type=charge;server=https://charge.example.com;api-token=2abdf302...'" + Environment.NewLine +
|
||||||
|
$"lightning charge server: 'type=charge;server=https://charge.example.com;cookiefilepath=/root/.charge/.cookie'" + Environment.NewLine +
|
||||||
|
chargeError ?? string.Empty);
|
||||||
|
}
|
||||||
|
ExternalServicesByCryptoCode.Add(net.CryptoCode, new ExternalCharge(chargeConnectionString));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Logs.Configuration.LogInformation("Supported chains: " + String.Join(',', supportedChains.ToArray()));
|
Logs.Configuration.LogInformation("Supported chains: " + String.Join(',', supportedChains.ToArray()));
|
||||||
|
|
||||||
var services = conf.GetOrDefault<string>("externalservices", null);
|
var services = conf.GetOrDefault<string>("externalservices", null);
|
||||||
if(services != null)
|
if (services != null)
|
||||||
{
|
{
|
||||||
foreach(var service in services.Split(new[] { ';', ',' })
|
foreach (var service in services.Split(new[] { ';', ',' })
|
||||||
.Select(p => p.Split(':'))
|
.Select(p => p.Split(':'))
|
||||||
.Where(p => p.Length == 2)
|
.Where(p => p.Length == 2)
|
||||||
.Select(p => (Name: p[0], Link: p[1])))
|
.Select(p => (Name: p[0], Link: p[1])))
|
||||||
|
|||||||
@@ -50,7 +50,8 @@ namespace BTCPayServer.Configuration
|
|||||||
app.Option($"--{crypto}explorercookiefile", $"Path to the cookie file (default: {network.NBXplorerNetwork.DefaultSettings.DefaultCookieFile})", CommandOptionType.SingleValue);
|
app.Option($"--{crypto}explorercookiefile", $"Path to the cookie file (default: {network.NBXplorerNetwork.DefaultSettings.DefaultCookieFile})", CommandOptionType.SingleValue);
|
||||||
app.Option($"--{crypto}lightning", $"Easy configuration of lightning for the server administrator: Must be a UNIX socket of c-lightning (lightning-rpc) or URL to a charge server (default: empty)", CommandOptionType.SingleValue);
|
app.Option($"--{crypto}lightning", $"Easy configuration of lightning for the server administrator: Must be a UNIX socket of c-lightning (lightning-rpc) or URL to a charge server (default: empty)", CommandOptionType.SingleValue);
|
||||||
app.Option($"--{crypto}externallndgrpc", $"The LND gRPC configuration BTCPay will expose to easily connect to the internal lnd wallet from Zap wallet (default: empty)", CommandOptionType.SingleValue);
|
app.Option($"--{crypto}externallndgrpc", $"The LND gRPC configuration BTCPay will expose to easily connect to the internal lnd wallet from Zap wallet (default: empty)", CommandOptionType.SingleValue);
|
||||||
app.Option($"--{crypto}externalspark", $"The connection string to spark server (default: empty)", CommandOptionType.SingleValue);
|
app.Option($"--{crypto}externalspark", $"Show spark information in Server settings / Server. The connection string to spark server (default: empty)", CommandOptionType.SingleValue);
|
||||||
|
app.Option($"--{crypto}externalcharge", $"Show lightning charge information in Server settings/Server. The connection string to charge server (default: empty)", CommandOptionType.SingleValue);
|
||||||
}
|
}
|
||||||
return app;
|
return app;
|
||||||
}
|
}
|
||||||
|
|||||||
19
BTCPayServer/Configuration/External/ExternalCharge.cs
vendored
Normal file
19
BTCPayServer/Configuration/External/ExternalCharge.cs
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using BTCPayServer.Lightning;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Configuration.External
|
||||||
|
{
|
||||||
|
public class ExternalCharge : ExternalService
|
||||||
|
{
|
||||||
|
public ExternalCharge(LightningConnectionString connectionString)
|
||||||
|
{
|
||||||
|
if (connectionString == null)
|
||||||
|
throw new ArgumentNullException(nameof(connectionString));
|
||||||
|
ConnectionString = connectionString;
|
||||||
|
}
|
||||||
|
public LightningConnectionString ConnectionString { get; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -449,6 +449,16 @@ namespace BTCPayServer.Controllers
|
|||||||
Index = i++,
|
Index = i++,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
foreach (var chargeService in _Options.ExternalServicesByCryptoCode.GetServices<ExternalCharge>(cryptoCode))
|
||||||
|
{
|
||||||
|
result.LNDServices.Add(new ServicesViewModel.LNDServiceViewModel()
|
||||||
|
{
|
||||||
|
Crypto = cryptoCode,
|
||||||
|
Type = "Lightning charge server",
|
||||||
|
Action = nameof(LightningChargeServices),
|
||||||
|
Index = i++,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
foreach(var externalService in _Options.ExternalServices)
|
foreach(var externalService in _Options.ExternalServices)
|
||||||
{
|
{
|
||||||
@@ -469,6 +479,45 @@ namespace BTCPayServer.Controllers
|
|||||||
return View(result);
|
return View(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Route("server/services/lightning-charge/{cryptoCode}/{index}")]
|
||||||
|
public async Task<IActionResult> LightningChargeServices(string cryptoCode, int index, bool showQR = false)
|
||||||
|
{
|
||||||
|
if (!_dashBoard.IsFullySynched(cryptoCode, out var unusud))
|
||||||
|
{
|
||||||
|
StatusMessage = $"Error: {cryptoCode} is not fully synched";
|
||||||
|
return RedirectToAction(nameof(Services));
|
||||||
|
}
|
||||||
|
var lightningCharge = _Options.ExternalServicesByCryptoCode.GetServices<ExternalCharge>(cryptoCode).Select(c => c.ConnectionString).FirstOrDefault();
|
||||||
|
if (lightningCharge == null)
|
||||||
|
{
|
||||||
|
return NotFound();
|
||||||
|
}
|
||||||
|
|
||||||
|
ChargeServiceViewModel vm = new ChargeServiceViewModel();
|
||||||
|
vm.Uri = lightningCharge.ToUri(false).AbsoluteUri;
|
||||||
|
vm.APIToken = lightningCharge.Password;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(vm.APIToken) && lightningCharge.CookieFilePath != null)
|
||||||
|
{
|
||||||
|
if (lightningCharge.CookieFilePath != "fake")
|
||||||
|
vm.APIToken = await System.IO.File.ReadAllTextAsync(lightningCharge.CookieFilePath);
|
||||||
|
else
|
||||||
|
vm.APIToken = "fake";
|
||||||
|
}
|
||||||
|
var builder = new UriBuilder(lightningCharge.ToUri(false));
|
||||||
|
builder.UserName = "api-token";
|
||||||
|
builder.Password = vm.APIToken;
|
||||||
|
vm.AuthenticatedUri = builder.ToString();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
StatusMessage = $"Error: {ex.Message}";
|
||||||
|
return RedirectToAction(nameof(Services));
|
||||||
|
}
|
||||||
|
return View(vm);
|
||||||
|
}
|
||||||
|
|
||||||
[Route("server/services/spark/{cryptoCode}/{index}")]
|
[Route("server/services/spark/{cryptoCode}/{index}")]
|
||||||
public async Task<IActionResult> SparkServices(string cryptoCode, int index, bool showQR = false)
|
public async Task<IActionResult> SparkServices(string cryptoCode, int index, bool showQR = false)
|
||||||
{
|
{
|
||||||
@@ -477,7 +526,7 @@ namespace BTCPayServer.Controllers
|
|||||||
StatusMessage = $"Error: {cryptoCode} is not fully synched";
|
StatusMessage = $"Error: {cryptoCode} is not fully synched";
|
||||||
return RedirectToAction(nameof(Services));
|
return RedirectToAction(nameof(Services));
|
||||||
}
|
}
|
||||||
var spark = _Options.ExternalServicesByCryptoCode.GetServices<ExternalSpark>(cryptoCode).Skip(index).Select(c => c.ConnectionString).FirstOrDefault();
|
var spark = _Options.ExternalServicesByCryptoCode.GetServices<ExternalSpark>(cryptoCode).Select(c => c.ConnectionString).FirstOrDefault();
|
||||||
if(spark == null)
|
if(spark == null)
|
||||||
{
|
{
|
||||||
return NotFound();
|
return NotFound();
|
||||||
|
|||||||
@@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace BTCPayServer.Models.ServerViewModels
|
||||||
|
{
|
||||||
|
public class ChargeServiceViewModel
|
||||||
|
{
|
||||||
|
public string Uri { get; set; }
|
||||||
|
public string APIToken { get; set; }
|
||||||
|
public string AuthenticatedUri { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
"BTCPAY_BTCEXTERNALLNDGRPC": "type=lnd-grpc;server=https://lnd:lnd@127.0.0.1:53280/;allowinsecure=true",
|
"BTCPAY_BTCEXTERNALLNDGRPC": "type=lnd-grpc;server=https://lnd:lnd@127.0.0.1:53280/;allowinsecure=true",
|
||||||
"BTCPAY_BTCEXTERNALLNDREST": "type=lnd-rest;server=https://lnd:lnd@127.0.0.1:53280/lnd-rest/btc/;allowinsecure=true",
|
"BTCPAY_BTCEXTERNALLNDREST": "type=lnd-rest;server=https://lnd:lnd@127.0.0.1:53280/lnd-rest/btc/;allowinsecure=true",
|
||||||
"BTCPAY_BTCEXTERNALSPARK": "server=https://127.0.0.1:53280/spark/btc/;cookiefile=fake",
|
"BTCPAY_BTCEXTERNALSPARK": "server=https://127.0.0.1:53280/spark/btc/;cookiefile=fake",
|
||||||
|
"BTCPAY_BTCEXTERNALCHARGE": "server=https://127.0.0.1:53280/spark/btc/;cookiefilepath=fake",
|
||||||
"BTCPAY_BTCEXPLORERURL": "http://127.0.0.1:32838/",
|
"BTCPAY_BTCEXPLORERURL": "http://127.0.0.1:32838/",
|
||||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||||
"BTCPAY_CHAINS": "btc,ltc",
|
"BTCPAY_CHAINS": "btc,ltc",
|
||||||
|
|||||||
60
BTCPayServer/Views/Server/LightningChargeServices.cshtml
Normal file
60
BTCPayServer/Views/Server/LightningChargeServices.cshtml
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
@model ChargeServiceViewModel
|
||||||
|
@{
|
||||||
|
ViewData.SetActivePageAndTitle(ServerNavPages.Services);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
<h4>Lightning charge service</h4>
|
||||||
|
<partial name="_StatusMessage" for="@TempData["StatusMessage"]" />
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-6">
|
||||||
|
<div asp-validation-summary="All" class="text-danger"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<div class="form-group">
|
||||||
|
<p>
|
||||||
|
<span>Lightning charge is a simple API for invoicing on lightning network, you can use it with several plugins:</span>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://github.com/ElementsProject/woocommerce-gateway-lightning" target="_blank">WooCommerce Lightning Gateway</a>: A comprehensive e-commerce application that integrates with stock-management and order-tracking systems</li>
|
||||||
|
<li><a href="https://github.com/ElementsProject/nanopos" target="_blank">Nanopos</a>: A simple point-of-sale system for fixed-price goods</li>
|
||||||
|
<li><a href="https://github.com/ElementsProject/filebazaar" target="_blank">FileBazaar</a>: A system for selling files such as documents, images, and videos</li>
|
||||||
|
<li><a href="https://github.com/ElementsProject/wordpress-lightning-publisher" target="_blank">Lightning Publisher for WordPress</a>: A patronage model for unlocking WordPress blog entries</li>
|
||||||
|
<li><a href="https://github.com/ElementsProject/paypercall" target="_blank">Paypercall</a>: A programmer’s toolkit for Lightning that enables micropayments for individual API calls</li>
|
||||||
|
<li><a href="https://github.com/ElementsProject/ifpaytt" target="_blank">Ifpaytt</a>: An extension of paypercall that allows web developers using IFTTT to request payments for service usage</li>
|
||||||
|
<li><a href="https://github.com/ElementsProject/lightning-jukebox" target="_blank">Lightning Jukebox</a>: A fun demo that reimagines a classic technology for the Lightning Network</li>
|
||||||
|
<li><a href="https://github.com/ElementsProject/nanotip" target="_blank">Nanotip</a>: The simple tip jar, rebuilt to issue Lightning Network invoices</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-md-8">
|
||||||
|
<h4>Credentials</h4>
|
||||||
|
@if (Model.Uri != null)
|
||||||
|
{
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="Uri"></label>
|
||||||
|
<input asp-for="Uri" readonly class="form-control" />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (Model.APIToken != null)
|
||||||
|
{
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="APIToken"></label>
|
||||||
|
<input asp-for="APIToken" readonly class="form-control" />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
@if (Model.AuthenticatedUri != null)
|
||||||
|
{
|
||||||
|
<div class="form-group">
|
||||||
|
<label asp-for="AuthenticatedUri"></label>
|
||||||
|
<input asp-for="AuthenticatedUri" readonly class="form-control" />
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
Reference in New Issue
Block a user