mirror of
https://github.com/aljazceru/btcpayserver-docker.git
synced 2025-12-18 13:24:20 +01:00
Add LND support
This commit is contained in:
@@ -23,7 +23,7 @@ services:
|
||||
- bitcoind
|
||||
btcpayserver:
|
||||
environment:
|
||||
BTCPAY_BTCLIGHTNING: "/etc/clightning_bitcoin/lightning-rpc"
|
||||
BTCPAY_BTCLIGHTNING: "type=clightning;server=unix://etc/clightning_bitcoin/lightning-rpc"
|
||||
volumes:
|
||||
- "clightning_bitcoin_datadir:/etc/clightning_bitcoin"
|
||||
links:
|
||||
|
||||
49
docker-compose-generator/docker-fragments/bitcoin-lnd.yml
Normal file
49
docker-compose-generator/docker-fragments/bitcoin-lnd.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
lnd_bitcoin:
|
||||
image: btcpayserver/lnd:0.4.2.0
|
||||
container_name: btcpayserver_lnd_bitcoin
|
||||
environment:
|
||||
LND_CHAIN: "btc"
|
||||
LND_ENVIRONMENT: "${NBITCOIN_NETWORK:-regtest}"
|
||||
LND_EXTRA_ARGS: |
|
||||
restlisten=0.0.0.0:8080
|
||||
bitcoin.node=bitcoind
|
||||
bitcoind.rpchost=bitcoind:43782
|
||||
bitcoind.zmqpath=tcp://bitcoind:28332
|
||||
externalip=${BTCPAY_HOST}:9735
|
||||
alias=${LIGHTNING_ALIAS}
|
||||
noencryptwallet=1
|
||||
notls=1
|
||||
ports:
|
||||
- "9735:9735"
|
||||
expose:
|
||||
- "8080"
|
||||
- "9735"
|
||||
volumes:
|
||||
- "lnd_bitcoin_datadir:/data"
|
||||
- "bitcoin_datadir:/deps/.bitcoin"
|
||||
links:
|
||||
- bitcoind
|
||||
|
||||
btcpayserver:
|
||||
environment:
|
||||
BTCPAY_BTCLIGHTNING: "type=lnd-rest;server=http://lnd_bitcoin:8080/;macaroonfilepath=/etc/lnd_bitcoin/admin.macaroon;allowinsecure=true"
|
||||
volumes:
|
||||
- "lnd_bitcoin_datadir:/etc/lnd_bitcoin"
|
||||
links:
|
||||
- lnd_bitcoin
|
||||
|
||||
bitcoind:
|
||||
environment:
|
||||
BITCOIN_EXTRA_ARGS: |
|
||||
zmqpubrawtx=tcp://0.0.0.0:28332
|
||||
zmqpubrawblock=tcp://0.0.0.0:28332
|
||||
zmqpubrawtxlock=tcp://0.0.0.0:28332
|
||||
zmqpubhashblock=tcp://0.0.0.0:28332
|
||||
expose:
|
||||
- "28332"
|
||||
|
||||
volumes:
|
||||
lnd_bitcoin_datadir:
|
||||
@@ -4,7 +4,7 @@ services:
|
||||
|
||||
btcpayserver:
|
||||
restart: unless-stopped
|
||||
image: nicolasdorier/btcpayserver:1.0.2.39
|
||||
image: nicolasdorier/btcpayserver:1.0.2.40
|
||||
expose:
|
||||
- "49392"
|
||||
environment:
|
||||
|
||||
@@ -23,7 +23,7 @@ services:
|
||||
- litecoind
|
||||
btcpayserver:
|
||||
environment:
|
||||
BTCPAY_LTCLIGHTNING: "/etc/clightning_litecoin/lightning-rpc"
|
||||
BTCPAY_LTCLIGHTNING: "type=clightning;server=unix://etc/clightning_litecoin/lightning-rpc"
|
||||
volumes:
|
||||
- "clightning_litecoin_datadir:/etc/clightning_litecoin"
|
||||
links:
|
||||
|
||||
49
docker-compose-generator/docker-fragments/litecoin-lnd.yml
Normal file
49
docker-compose-generator/docker-fragments/litecoin-lnd.yml
Normal file
@@ -0,0 +1,49 @@
|
||||
version: "3"
|
||||
|
||||
services:
|
||||
lnd_litecoin:
|
||||
image: btcpayserver/lnd:0.4.2.0
|
||||
container_name: btcpayserver_lnd_litecoin
|
||||
environment:
|
||||
LND_CHAIN: "ltc"
|
||||
LND_ENVIRONMENT: "${NBITCOIN_NETWORK:-regtest}"
|
||||
LND_EXTRA_ARGS: |
|
||||
restlisten=0.0.0.0:8080
|
||||
litecoin.node=litecoind
|
||||
litecoind.rpchost=litecoind:43782
|
||||
litecoind.zmqpath=tcp://litecoind:28332
|
||||
externalip=${BTCPAY_HOST}:9736
|
||||
alias=${LIGHTNING_ALIAS}
|
||||
noencryptwallet=1
|
||||
notls=1
|
||||
ports:
|
||||
- "9736:9735"
|
||||
expose:
|
||||
- "8080"
|
||||
- "9736"
|
||||
volumes:
|
||||
- "lnd_litecoin_datadir:/data"
|
||||
- "litecoin_datadir:/deps/.litecoin"
|
||||
links:
|
||||
- litecoind
|
||||
|
||||
btcpayserver:
|
||||
environment:
|
||||
BTCPAY_LTCLIGHTNING: "type=lnd-rest;server=http://lnd_litecoin:8080/;macaroonfilepath=/etc/lnd_litecoin/admin.macaroon;allowinsecure=true"
|
||||
volumes:
|
||||
- "lnd_litecoin_datadir:/etc/lnd_litecoin"
|
||||
links:
|
||||
- lnd_litecoin
|
||||
|
||||
litecoind:
|
||||
environment:
|
||||
BITCOIN_EXTRA_ARGS: |
|
||||
zmqpubrawtx=tcp://0.0.0.0:28332
|
||||
zmqpubrawblock=tcp://0.0.0.0:28332
|
||||
zmqpubrawtxlock=tcp://0.0.0.0:28332
|
||||
zmqpubhashblock=tcp://0.0.0.0:28332
|
||||
expose:
|
||||
- "28332"
|
||||
|
||||
volumes:
|
||||
lnd_litecoin_datadir:
|
||||
@@ -21,8 +21,13 @@ namespace DockerGenerator
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
public string LNDFragment
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public static CryptoDefinition[] GetDefinitions()
|
||||
public static CryptoDefinition[] GetDefinitions()
|
||||
{
|
||||
return new[]
|
||||
{
|
||||
@@ -31,30 +36,29 @@ namespace DockerGenerator
|
||||
Crypto = "ltc",
|
||||
CryptoFragment = "litecoin",
|
||||
CLightningFragment = "litecoin-clightning",
|
||||
},
|
||||
LNDFragment = "litecoin-lnd"
|
||||
},
|
||||
new CryptoDefinition()
|
||||
{
|
||||
Crypto = "btc",
|
||||
CryptoFragment = "bitcoin",
|
||||
CLightningFragment = "bitcoin-clightning",
|
||||
LNDFragment = "bitcoin-lnd"
|
||||
},
|
||||
new CryptoDefinition()
|
||||
{
|
||||
Crypto = "btg",
|
||||
CryptoFragment = "bgold",
|
||||
CLightningFragment = null,
|
||||
CryptoFragment = "bgold"
|
||||
},
|
||||
new CryptoDefinition()
|
||||
{
|
||||
Crypto = "ftc",
|
||||
CryptoFragment = "feathercoin",
|
||||
CLightningFragment = null,
|
||||
CryptoFragment = "feathercoin"
|
||||
},
|
||||
new CryptoDefinition()
|
||||
{
|
||||
Crypto = "grs",
|
||||
CryptoFragment = "groestlcoin",
|
||||
CLightningFragment = null,
|
||||
CryptoFragment = "groestlcoin"
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -8,128 +8,145 @@ using System.IO;
|
||||
|
||||
namespace DockerGenerator
|
||||
{
|
||||
public class DockerComposeDefinition
|
||||
{
|
||||
public List<string> Fragments
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
private string _Name;
|
||||
public class DockerComposeDefinition
|
||||
{
|
||||
public List<string> Fragments
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
private string _Name;
|
||||
|
||||
public DockerComposeDefinition(string name, List<string> fragments)
|
||||
{
|
||||
Fragments = fragments;
|
||||
_Name = name;
|
||||
}
|
||||
public DockerComposeDefinition(string name, List<string> fragments)
|
||||
{
|
||||
Fragments = fragments;
|
||||
_Name = name;
|
||||
}
|
||||
|
||||
public string FragmentLocation
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string BuildOutputDirectory
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string FragmentLocation
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
public string BuildOutputDirectory
|
||||
{
|
||||
get; set;
|
||||
}
|
||||
|
||||
public string GetFilePath()
|
||||
{
|
||||
return Path.Combine(BuildOutputDirectory, $"docker-compose.{_Name}.yml");
|
||||
}
|
||||
public void Build()
|
||||
{
|
||||
Console.WriteLine($"Generating {GetFilePath()}");
|
||||
var deserializer = new DeserializerBuilder().Build();
|
||||
var serializer = new SerializerBuilder().Build();
|
||||
public string GetFilePath()
|
||||
{
|
||||
return Path.Combine(BuildOutputDirectory, $"docker-compose.{_Name}.yml");
|
||||
}
|
||||
public void Build()
|
||||
{
|
||||
Console.WriteLine($"Generating {GetFilePath()}");
|
||||
var deserializer = new DeserializerBuilder().Build();
|
||||
var serializer = new SerializerBuilder().Build();
|
||||
|
||||
Console.WriteLine($"With fragments:");
|
||||
foreach(var fragment in Fragments)
|
||||
{
|
||||
Console.WriteLine($"\t{fragment}");
|
||||
}
|
||||
var services = new List<KeyValuePair<YamlNode, YamlNode>>();
|
||||
var volumes = new List<KeyValuePair<YamlNode, YamlNode>>();
|
||||
Console.WriteLine($"With fragments:");
|
||||
foreach(var fragment in Fragments)
|
||||
{
|
||||
Console.WriteLine($"\t{fragment}");
|
||||
}
|
||||
var services = new List<KeyValuePair<YamlNode, YamlNode>>();
|
||||
var volumes = new List<KeyValuePair<YamlNode, YamlNode>>();
|
||||
|
||||
foreach(var doc in Fragments.Select(f => ParseDocument(f)))
|
||||
{
|
||||
if(doc.Children.ContainsKey("services") && doc.Children["services"] is YamlMappingNode fragmentServicesRoot)
|
||||
{
|
||||
services.AddRange(fragmentServicesRoot.Children);
|
||||
}
|
||||
foreach(var doc in Fragments.Select(f => ParseDocument(f)))
|
||||
{
|
||||
if(doc.Children.ContainsKey("services") && doc.Children["services"] is YamlMappingNode fragmentServicesRoot)
|
||||
{
|
||||
services.AddRange(fragmentServicesRoot.Children);
|
||||
}
|
||||
|
||||
if(doc.Children.ContainsKey("volumes") && doc.Children["volumes"] is YamlMappingNode fragmentVolumesRoot)
|
||||
{
|
||||
volumes.AddRange(fragmentVolumesRoot.Children);
|
||||
}
|
||||
}
|
||||
if(doc.Children.ContainsKey("volumes") && doc.Children["volumes"] is YamlMappingNode fragmentVolumesRoot)
|
||||
{
|
||||
volumes.AddRange(fragmentVolumesRoot.Children);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
YamlMappingNode output = new YamlMappingNode();
|
||||
output.Add("version", new YamlScalarNode("3") { Style = YamlDotNet.Core.ScalarStyle.DoubleQuoted });
|
||||
output.Add("services", new YamlMappingNode(Merge(services)));
|
||||
output.Add("volumes", new YamlMappingNode(volumes));
|
||||
var result = serializer.Serialize(output);
|
||||
var outputFile = GetFilePath();
|
||||
File.WriteAllText(outputFile, result.Replace("''", ""));
|
||||
Console.WriteLine($"Generated {outputFile}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
private KeyValuePair<YamlNode, YamlNode>[] Merge(List<KeyValuePair<YamlNode, YamlNode>> services)
|
||||
{
|
||||
return services
|
||||
.GroupBy(s => s.Key.ToString(), s=> s.Value)
|
||||
.Select(group =>
|
||||
(GroupName: group.Key,
|
||||
MainNode: group.OfType<YamlMappingNode>().Single(n=> n.Children.ContainsKey("image")),
|
||||
MergedNodes: group.OfType<YamlMappingNode>().Where(n => !n.Children.ContainsKey("image"))))
|
||||
.Select(_ =>
|
||||
{
|
||||
foreach(var node in _.MergedNodes)
|
||||
{
|
||||
foreach(var child in node)
|
||||
{
|
||||
var childValue = child.Value;
|
||||
if(!_.MainNode.Children.TryGetValue(child.Key, out var mainChildValue))
|
||||
{
|
||||
mainChildValue = child.Value;
|
||||
_.MainNode.Add(child.Key, child.Value);
|
||||
}
|
||||
else if(childValue is YamlMappingNode childMapping && mainChildValue is YamlMappingNode mainChildMapping)
|
||||
{
|
||||
foreach(var leaf in childMapping)
|
||||
{
|
||||
if(mainChildMapping.Children.TryGetValue(leaf.Key, out var mainLeaf))
|
||||
{
|
||||
if(leaf.Value is YamlScalarNode leafScalar && mainLeaf is YamlScalarNode leafMainScalar)
|
||||
{
|
||||
leafMainScalar.Value = leafMainScalar.Value + "," + leaf.Value;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mainChildMapping.Add(leaf.Key, leaf.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(childValue is YamlSequenceNode childSequence && mainChildValue is YamlSequenceNode mainSequence)
|
||||
{
|
||||
foreach(var c in childSequence.Children)
|
||||
{
|
||||
mainSequence.Add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new KeyValuePair<YamlNode, YamlNode>(_.GroupName, _.MainNode);
|
||||
}).ToArray();
|
||||
}
|
||||
YamlMappingNode output = new YamlMappingNode();
|
||||
output.Add("version", new YamlScalarNode("3") { Style = YamlDotNet.Core.ScalarStyle.DoubleQuoted });
|
||||
output.Add("services", new YamlMappingNode(Merge(services)));
|
||||
output.Add("volumes", new YamlMappingNode(volumes));
|
||||
var result = serializer.Serialize(output);
|
||||
var outputFile = GetFilePath();
|
||||
File.WriteAllText(outputFile, result.Replace("''", ""));
|
||||
Console.WriteLine($"Generated {outputFile}");
|
||||
Console.WriteLine();
|
||||
}
|
||||
|
||||
private YamlMappingNode ParseDocument(string fragment)
|
||||
{
|
||||
var input = new StringReader(File.ReadAllText(Path.Combine(FragmentLocation, $"{fragment}.yml")));
|
||||
YamlStream stream = new YamlStream();
|
||||
stream.Load(input);
|
||||
return (YamlMappingNode)stream.Documents[0].RootNode;
|
||||
}
|
||||
}
|
||||
private KeyValuePair<YamlNode, YamlNode>[] Merge(List<KeyValuePair<YamlNode, YamlNode>> services)
|
||||
{
|
||||
return services
|
||||
.GroupBy(s => s.Key.ToString(), s => s.Value)
|
||||
.Select(group =>
|
||||
(GroupName: group.Key,
|
||||
MainNode: group.OfType<YamlMappingNode>().Single(n => n.Children.ContainsKey("image")),
|
||||
MergedNodes: group.OfType<YamlMappingNode>().Where(n => !n.Children.ContainsKey("image"))))
|
||||
.Select(_ =>
|
||||
{
|
||||
foreach(var node in _.MergedNodes)
|
||||
{
|
||||
foreach(var child in node)
|
||||
{
|
||||
var childValue = child.Value;
|
||||
if(!_.MainNode.Children.TryGetValue(child.Key, out var mainChildValue))
|
||||
{
|
||||
mainChildValue = child.Value;
|
||||
_.MainNode.Add(child.Key, child.Value);
|
||||
}
|
||||
else if(childValue is YamlMappingNode childMapping && mainChildValue is YamlMappingNode mainChildMapping)
|
||||
{
|
||||
foreach(var leaf in childMapping)
|
||||
{
|
||||
if(mainChildMapping.Children.TryGetValue(leaf.Key, out var mainLeaf))
|
||||
{
|
||||
if(leaf.Value is YamlScalarNode leafScalar && mainLeaf is YamlScalarNode leafMainScalar)
|
||||
{
|
||||
var eof = EOF(leafMainScalar.Value) ?? EOF(leaf.Value.ToString());
|
||||
if(eof != null)
|
||||
{
|
||||
leafMainScalar.Value = leafMainScalar.Value + eof + leaf.Value;
|
||||
}
|
||||
else
|
||||
{
|
||||
leafMainScalar.Value = leafMainScalar.Value + "," + leaf.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
mainChildMapping.Add(leaf.Key, leaf.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(childValue is YamlSequenceNode childSequence && mainChildValue is YamlSequenceNode mainSequence)
|
||||
{
|
||||
foreach(var c in childSequence.Children)
|
||||
{
|
||||
mainSequence.Add(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new KeyValuePair<YamlNode, YamlNode>(_.GroupName, _.MainNode);
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
private string EOF(string value)
|
||||
{
|
||||
if(value.Contains("\r\n", StringComparison.OrdinalIgnoreCase))
|
||||
return "\r\n";
|
||||
if(value.Contains("\n", StringComparison.OrdinalIgnoreCase))
|
||||
return "\n";
|
||||
return null;
|
||||
}
|
||||
|
||||
private YamlMappingNode ParseDocument(string fragment)
|
||||
{
|
||||
var input = new StringReader(File.ReadAllText(Path.Combine(FragmentLocation, $"{fragment}.yml")));
|
||||
YamlStream stream = new YamlStream();
|
||||
stream.Load(input);
|
||||
return (YamlMappingNode)stream.Documents[0].RootNode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,7 +86,11 @@ namespace DockerGenerator
|
||||
{
|
||||
fragments.Add(crypto.CLightningFragment);
|
||||
}
|
||||
}
|
||||
if(composition.SelectedLN == "lnd" && crypto.LNDFragment != null)
|
||||
{
|
||||
fragments.Add(crypto.LNDFragment);
|
||||
}
|
||||
}
|
||||
|
||||
var def = new DockerComposeDefinition(name, fragments);
|
||||
def.FragmentLocation = fragmentLocation;
|
||||
|
||||
Reference in New Issue
Block a user