mirror of
https://github.com/btcpayserver/btcpayserver.git
synced 2024-11-19 18:11:36 +01:00
170 lines
6.1 KiB
C#
170 lines
6.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using BTCPayServer.Configuration;
|
|
using BTCPayServer.HostedServices;
|
|
using BTCPayServer.Logging;
|
|
using Microsoft.Extensions.Logging;
|
|
using Microsoft.Extensions.Options;
|
|
|
|
namespace BTCPayServer.Services
|
|
{
|
|
public class TorServices : BaseAsyncService
|
|
{
|
|
private readonly BTCPayNetworkProvider _btcPayNetworkProvider;
|
|
private readonly IOptions<BTCPayServerOptions> _options;
|
|
|
|
|
|
public TorServices(BTCPayNetworkProvider btcPayNetworkProvider, IOptions<BTCPayServerOptions> options, Logs logs) : base(logs)
|
|
{
|
|
_btcPayNetworkProvider = btcPayNetworkProvider;
|
|
_options = options;
|
|
}
|
|
|
|
public TorService[] Services { get; internal set; } = Array.Empty<TorService>();
|
|
|
|
private bool firstRun = true;
|
|
internal async Task Refresh()
|
|
{
|
|
if (firstRun)
|
|
{
|
|
firstRun = false;
|
|
}
|
|
else
|
|
{
|
|
await Task.Delay(TimeSpan.FromSeconds(120), Cancellation);
|
|
}
|
|
List<TorService> result = new List<TorService>();
|
|
try
|
|
{
|
|
if (!File.Exists(_options.Value.TorrcFile))
|
|
{
|
|
Logs.PayServer.LogWarning("Torrc file is not found");
|
|
Services = Array.Empty<TorService>();
|
|
return;
|
|
}
|
|
|
|
var torrcContent = await File.ReadAllTextAsync(_options.Value.TorrcFile);
|
|
if (!Torrc.TryParse(torrcContent, out var torrc))
|
|
{
|
|
Logs.PayServer.LogWarning("Torrc file could not be parsed");
|
|
Services = Array.Empty<TorService>();
|
|
return;
|
|
}
|
|
|
|
var torrcDir = Path.GetDirectoryName(_options.Value.TorrcFile);
|
|
var services = torrc.ServiceDirectories.SelectMany(d =>
|
|
d.ServicePorts.Select(p => (Directory: GetDirectory(d, torrcDir), VirtualPort: p.VirtualPort)))
|
|
.Select(d => (ServiceName: d.Directory.Name,
|
|
ReadingLines: System.IO.File.ReadAllLinesAsync(Path.Combine(d.Directory.FullName, "hostname")),
|
|
VirtualPort: d.VirtualPort))
|
|
.ToArray();
|
|
foreach (var service in services)
|
|
{
|
|
try
|
|
{
|
|
var onionHost = (await service.ReadingLines)[0].Trim();
|
|
var torService = ParseService(service.ServiceName, onionHost, service.VirtualPort);
|
|
result.Add(torService);
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logs.PayServer.LogWarning(ex,
|
|
$"Error while reading hidden service {service.ServiceName} configuration");
|
|
}
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Logs.PayServer.LogWarning(ex, $"Error while reading torrc file");
|
|
}
|
|
|
|
Services = result.ToArray();
|
|
}
|
|
|
|
private TorService ParseService(string serviceName, string onionHost, int virtualPort)
|
|
{
|
|
var torService = new TorService() { Name = serviceName, OnionHost = onionHost, VirtualPort = virtualPort };
|
|
|
|
if (Enum.TryParse<TorServiceType>(serviceName, true, out var serviceType))
|
|
torService.ServiceType = serviceType;
|
|
else if (TryParseCryptoSpecificService(serviceName, out var network, out serviceType))
|
|
{
|
|
torService.ServiceType = serviceType;
|
|
torService.Network = network;
|
|
}
|
|
else
|
|
{
|
|
torService.ServiceType = TorServiceType.Other;
|
|
}
|
|
|
|
return torService;
|
|
}
|
|
|
|
private static DirectoryInfo GetDirectory(HiddenServiceDir hs, string relativeTo)
|
|
{
|
|
if (Path.IsPathRooted(hs.DirectoryPath))
|
|
return new DirectoryInfo(hs.DirectoryPath);
|
|
return new DirectoryInfo(Path.Combine(relativeTo, hs.DirectoryPath));
|
|
}
|
|
|
|
private bool TryParseCryptoSpecificService(string name, out BTCPayNetworkBase network,
|
|
out TorServiceType serviceType)
|
|
{
|
|
network = null;
|
|
serviceType = TorServiceType.Other;
|
|
var splitted = name.Trim().Split('-');
|
|
return splitted.Length == 2 && Enum.TryParse(splitted[1], true, out serviceType) &&
|
|
_btcPayNetworkProvider.TryGetNetwork(splitted[0], out network);
|
|
}
|
|
|
|
public override async Task StartAsync(CancellationToken cancellationToken)
|
|
{
|
|
if (string.IsNullOrEmpty(_options.Value.TorrcFile) && _options.Value.TorServices != null)
|
|
{
|
|
LoadFromConfig();
|
|
}
|
|
else if (!string.IsNullOrEmpty(_options.Value.TorrcFile))
|
|
{
|
|
await Refresh();
|
|
await base.StartAsync(cancellationToken);
|
|
}
|
|
}
|
|
|
|
internal override Task[] InitializeTasks()
|
|
{
|
|
return new[] { CreateLoopTask(Refresh) };
|
|
}
|
|
|
|
private void LoadFromConfig()
|
|
{
|
|
Services = _options.Value.TorServices.Select(p => p.Split(":", StringSplitOptions.RemoveEmptyEntries))
|
|
.Where(p => p.Length == 3)
|
|
.Select(strings =>
|
|
int.TryParse(strings[2], out var port) ? ParseService(strings[0], strings[1], port) : null)
|
|
.Where(p => p != null)
|
|
.ToArray();
|
|
}
|
|
}
|
|
|
|
public class TorService
|
|
{
|
|
public TorServiceType ServiceType { get; set; } = TorServiceType.Other;
|
|
public BTCPayNetworkBase Network { get; set; }
|
|
public string Name { get; set; }
|
|
public string OnionHost { get; set; }
|
|
public int VirtualPort { get; set; }
|
|
}
|
|
|
|
public enum TorServiceType
|
|
{
|
|
BTCPayServer,
|
|
P2P,
|
|
RPC,
|
|
Other
|
|
}
|
|
}
|