More Options refactoring (#2179)

* More Options refactoring

Continues refactoring config classes to use the propert Options pattern where possible.
DataDirectories and DatabaseOptions are now configured the Options pattern and the BTCPayOptions is now moved alongside the other config setup

* Move COnfigure logic for Options to the Startup
This commit is contained in:
Andrew Camilleri 2021-01-06 15:51:13 +01:00 committed by GitHub
parent a18dae6d04
commit 58d01738ab
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 179 additions and 234 deletions

View file

@ -0,0 +1,12 @@
namespace BTCPayServer.Configuration
{
public class DataDirectories
{
public string DataDir { get; set; }
public string PluginDir { get; set; }
public string TempStorageDir { get; set; }
public string StorageDir { get; set; }
}
}

View file

@ -3,6 +3,7 @@ using BTCPayServer.Abstractions.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
using Microsoft.Extensions.Options;
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Migrations.Operations;
@ -10,10 +11,10 @@ namespace BTCPayServer.Abstractions.Contracts
{
public abstract class BaseDbContextFactory<T> where T: DbContext
{
private readonly DatabaseOptions _options;
private readonly IOptions<DatabaseOptions> _options;
private readonly string _schemaPrefix;
public BaseDbContextFactory(DatabaseOptions options, string schemaPrefix)
public BaseDbContextFactory(IOptions<DatabaseOptions> options, string schemaPrefix)
{
_options = options;
_schemaPrefix = schemaPrefix;
@ -65,10 +66,10 @@ namespace BTCPayServer.Abstractions.Contracts
public void ConfigureBuilder(DbContextOptionsBuilder builder)
{
switch (_options.DatabaseType)
switch (_options.Value.DatabaseType)
{
case DatabaseType.Sqlite:
builder.UseSqlite(_options.ConnectionString, o =>
builder.UseSqlite(_options.Value.ConnectionString, o =>
{
if (!string.IsNullOrEmpty(_schemaPrefix))
{
@ -78,7 +79,7 @@ namespace BTCPayServer.Abstractions.Contracts
break;
case DatabaseType.Postgres:
builder
.UseNpgsql(_options.ConnectionString, o =>
.UseNpgsql(_options.Value.ConnectionString, o =>
{
o.EnableRetryOnFailure(10);
if (!string.IsNullOrEmpty(_schemaPrefix))
@ -89,7 +90,7 @@ namespace BTCPayServer.Abstractions.Contracts
.ReplaceService<IMigrationsSqlGenerator, CustomNpgsqlMigrationsSqlGenerator>();
break;
case DatabaseType.MySQL:
builder.UseMySql(_options.ConnectionString, o =>
builder.UseMySql(_options.Value.ConnectionString, o =>
{
o.EnableRetryOnFailure(10);

View file

@ -1,43 +1,7 @@
using System;
using System.IO;
using System.Runtime.InteropServices.ComTypes;
using Microsoft.Extensions.Configuration;
namespace BTCPayServer.Abstractions.Models
{
public class DatabaseOptions
{
public DatabaseOptions(IConfiguration conf, string dataDir)
{
var postgresConnectionString = conf["postgres"];
var mySQLConnectionString = conf["mysql"];
var sqliteFileName = conf["sqlitefile"];
if (!string.IsNullOrEmpty(postgresConnectionString))
{
DatabaseType = DatabaseType.Postgres;
ConnectionString = postgresConnectionString;
}
else if (!string.IsNullOrEmpty(mySQLConnectionString))
{
DatabaseType = DatabaseType.MySQL;
ConnectionString = mySQLConnectionString;
}
else if (!string.IsNullOrEmpty(sqliteFileName))
{
var connStr = "Data Source=" + (Path.IsPathRooted(sqliteFileName)
? sqliteFileName
: Path.Combine(dataDir, sqliteFileName));
DatabaseType = DatabaseType.Sqlite;
ConnectionString = sqliteFileName;
}
else
{
throw new InvalidOperationException("No database option was configured.");
}
}
public DatabaseType DatabaseType { get; set; }
public string ConnectionString { get; set; }
}

View file

@ -1,12 +1,13 @@
using BTCPayServer.Abstractions.Contracts;
using BTCPayServer.Abstractions.Models;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Options;
namespace BTCPayServer.Data
{
public class ApplicationDbContextFactory : BaseDbContextFactory<ApplicationDbContext>
{
public ApplicationDbContextFactory(DatabaseOptions options) : base(options, "")
public ApplicationDbContextFactory(IOptions<DatabaseOptions> options) : base(options, "")
{
}

View file

@ -23,7 +23,7 @@ namespace BTCPayServer.Plugins.Test
public class TestPluginDbContextFactory : BaseDbContextFactory<TestPluginDbContext>
{
public TestPluginDbContextFactory(DatabaseOptions options) : base(options, "BTCPayServer.Plugins.Test")
public TestPluginDbContextFactory(IOptions<DatabaseOptions> options) : base(options, "BTCPayServer.Plugins.Test")
{
}

View file

@ -44,7 +44,7 @@ namespace BTCPayServer.Configuration
{
if (!Path.IsPathRooted(logfile))
{
logfile = Path.Combine(new DataDirectories(configuration).DataDir, logfile);
logfile = Path.Combine(new DataDirectories().Configure(configuration).DataDir, logfile);
}
}
return logfile;

View file

@ -1,26 +0,0 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Extensions.Configuration;
namespace BTCPayServer.Configuration
{
public class DataDirectories
{
public DataDirectories(IConfiguration conf)
{
var networkType = DefaultConfiguration.GetNetworkType(conf);
var defaultSettings = BTCPayDefaultSettings.GetDefaultSettings(networkType);
DataDir = conf["datadir"] ?? defaultSettings.DefaultDataDirectory;
PluginDir = conf["plugindir"] ?? defaultSettings.DefaultPluginDirectory;
StorageDir = Path.Combine(DataDir, Storage.Services.Providers.FileSystemStorage.FileSystemFileProviderService.LocalStorageDirectoryName);
TempStorageDir = Path.Combine(StorageDir, "tmp");
}
public string DataDir { get; }
public string PluginDir { get; }
public string TempStorageDir { get; }
public string StorageDir { get; set; }
}
}

View file

@ -1,8 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Configuration;
using NBitcoin;
namespace BTCPayServer.Configuration
{
@ -11,28 +8,5 @@ namespace BTCPayServer.Configuration
public Dictionary<string, Uri> OtherExternalServices { get; set; } = new Dictionary<string, Uri>();
public ExternalServices ExternalServices { get; set; } = new ExternalServices();
public void Configure(IConfiguration configuration, BTCPayNetworkProvider btcPayNetworkProvider)
{
foreach (var net in btcPayNetworkProvider.GetAll().OfType<BTCPayNetwork>())
{
ExternalServices.Load(net.CryptoCode, configuration);
}
ExternalServices.LoadNonCryptoServices(configuration);
var services = configuration.GetOrDefault<string>("externalservices", null);
if (services != null)
{
foreach (var service in services.Split(new[] {';', ','}, StringSplitOptions.RemoveEmptyEntries)
.Select(p => (p, SeparatorIndex: p.IndexOf(':', StringComparison.OrdinalIgnoreCase)))
.Where(p => p.SeparatorIndex != -1)
.Select(p => (Name: p.p.Substring(0, p.SeparatorIndex),
Link: p.p.Substring(p.SeparatorIndex + 1))))
{
if (Uri.TryCreate(service.Link, UriKind.RelativeOrAbsolute, out var uri))
OtherExternalServices.AddOrReplace(service.Name, uri);
}
}
}
}
}

View file

@ -1,10 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using BTCPayServer.Lightning;
using BTCPayServer.Logging;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace BTCPayServer.Configuration
{
@ -12,46 +7,5 @@ namespace BTCPayServer.Configuration
{
public Dictionary<string, LightningConnectionString> InternalLightningByCryptoCode { get; set; } =
new Dictionary<string, LightningConnectionString>();
public void Configure(IConfiguration conf, BTCPayNetworkProvider networkProvider)
{
foreach (var net in networkProvider.GetAll().OfType<BTCPayNetwork>())
{
var lightning = conf.GetOrDefault<string>($"{net.CryptoCode}.lightning", string.Empty);
if (lightning.Length != 0)
{
if (!LightningConnectionString.TryParse(lightning, true, out var connectionString,
out var error))
{
Logs.Configuration.LogWarning($"Invalid setting {net.CryptoCode}.lightning, " +
Environment.NewLine +
$"If you have a c-lightning server use: 'type=clightning;server=/root/.lightning/lightning-rpc', " +
Environment.NewLine +
$"If you have a lightning charge server: 'type=charge;server=https://charge.example.com;api-token=yourapitoken'" +
Environment.NewLine +
$"If you have a lnd server: 'type=lnd-rest;server=https://lnd:lnd@lnd.example.com;macaroon=abf239...;certthumbprint=2abdf302...'" +
Environment.NewLine +
$" lnd server: 'type=lnd-rest;server=https://lnd:lnd@lnd.example.com;macaroonfilepath=/root/.lnd/admin.macaroon;certthumbprint=2abdf302...'" +
Environment.NewLine +
$"If you have an eclair server: 'type=eclair;server=http://eclair.com:4570;password=eclairpassword;bitcoin-host=bitcoind:37393;bitcoin-auth=bitcoinrpcuser:bitcoinrpcpassword" +
Environment.NewLine +
$" eclair server: 'type=eclair;server=http://eclair.com:4570;password=eclairpassword;bitcoin-host=bitcoind:37393" +
Environment.NewLine +
$"Error: {error}" + Environment.NewLine +
"This service will not be exposed through BTCPay Server");
}
else
{
if (connectionString.IsLegacy)
{
Logs.Configuration.LogWarning(
$"Setting {net.CryptoCode}.lightning is a deprecated format, it will work now, but please replace it for future versions with '{connectionString.ToString()}'");
}
InternalLightningByCryptoCode.Add(net.CryptoCode, connectionString);
}
}
}
}
}
}

View file

@ -1,7 +1,4 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.Configuration;
namespace BTCPayServer.Configuration
{
@ -12,19 +9,5 @@ namespace BTCPayServer.Configuration
get;
set;
} = new List<NBXplorerConnectionSetting>();
public void Configure(IConfiguration conf, BTCPayNetworkProvider provider)
{
foreach (BTCPayNetwork btcPayNetwork in provider.GetAll().OfType<BTCPayNetwork>())
{
NBXplorerConnectionSetting setting = new NBXplorerConnectionSetting();
setting.CryptoCode = btcPayNetwork.CryptoCode;
setting.ExplorerUri = conf.GetOrDefault<Uri>($"{btcPayNetwork.CryptoCode}.explorer.url",
btcPayNetwork.NBXplorerNetwork.DefaultSettings.DefaultUrl);
setting.CookieFile = conf.GetOrDefault<string>($"{btcPayNetwork.CryptoCode}.explorer.cookiefile",
btcPayNetwork.NBXplorerNetwork.DefaultSettings.DefaultCookieFile);
NBXplorerConnectionSettings.Add(setting);
}
}
}
}

View file

@ -1,7 +1,5 @@
using System.Threading.Tasks;
using BTCPayServer.Configuration;
using BTCPayServer.Storage.Services;
using BTCPayServer.Storage.Services.Providers.FileSystemStorage;
using Microsoft.AspNetCore.Mvc;
namespace BTCPayServer.Storage
@ -10,12 +8,10 @@ namespace BTCPayServer.Storage
public class StorageController : Controller
{
private readonly FileService _FileService;
private readonly string _dir;
public StorageController(FileService fileService, DataDirectories datadirs)
public StorageController(FileService fileService)
{
_FileService = fileService;
_dir = datadirs.TempStorageDir;
}
[HttpGet("{fileId}")]

View file

@ -1,6 +1,7 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.WebSockets;
@ -375,15 +376,6 @@ namespace BTCPayServer
request.Host.ToUriComponent()) + relativeOrAbsolute.ToString().WithStartingSlash(), UriKind.Absolute);
}
public static IServiceCollection ConfigureBTCPayServer(this IServiceCollection services, IConfiguration conf)
{
services.Configure<BTCPayServerOptions>(o =>
{
o.LoadArgs(conf);
});
return services;
}
public static string GetSIN(this ClaimsPrincipal principal)
{
return principal.Claims.Where(c => c.Type == Security.Bitpay.BitpayClaims.SIN).Select(c => c.Value).FirstOrDefault();
@ -497,6 +489,17 @@ namespace BTCPayServer
return result;
}
public static DataDirectories Configure(this DataDirectories dataDirectories, IConfiguration configuration)
{
var networkType = DefaultConfiguration.GetNetworkType(configuration);
var defaultSettings = BTCPayDefaultSettings.GetDefaultSettings(networkType);
dataDirectories.DataDir = configuration["datadir"] ?? defaultSettings.DefaultDataDirectory;
dataDirectories.PluginDir = configuration["plugindir"] ?? defaultSettings.DefaultPluginDirectory;
dataDirectories.StorageDir = Path.Combine(dataDirectories.DataDir , Storage.Services.Providers.FileSystemStorage.FileSystemFileProviderService.LocalStorageDirectoryName);
dataDirectories.TempStorageDir = Path.Combine(dataDirectories.StorageDir, "tmp");
return dataDirectories;
}
private static object Private(this object obj, string privateField) => obj?.GetType().GetField(privateField, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(obj);
private static T Private<T>(this object obj, string privateField) => (T)obj?.GetType().GetField(privateField, BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(obj);
}

View file

@ -11,6 +11,7 @@ using BTCPayServer.Configuration;
using BTCPayServer.Controllers;
using BTCPayServer.Data;
using BTCPayServer.HostedServices;
using BTCPayServer.Lightning;
using BTCPayServer.Logging;
using BTCPayServer.PaymentRequest;
using BTCPayServer.Payments;
@ -105,7 +106,6 @@ namespace BTCPayServer.Hosting
services.AddStartupTask<BlockExplorerLinkStartupTask>();
services.TryAddSingleton<InvoiceRepository>(o =>
{
var datadirs = o.GetRequiredService<DataDirectories>();
var dbContext = o.GetRequiredService<ApplicationDbContextFactory>();
return new InvoiceRepository(dbContext, o.GetRequiredService<BTCPayNetworkProvider>(), o.GetService<EventAggregator>());
});
@ -115,50 +115,130 @@ namespace BTCPayServer.Hosting
services.TryAddSingleton<EventAggregator>();
services.TryAddSingleton<PaymentRequestService>();
services.TryAddSingleton<U2FService>();
services.TryAddSingleton<DataDirectories>();
services.TryAddSingleton<DatabaseOptions>(o =>
{
try
{
var dbOptions = new DatabaseOptions(o.GetRequiredService<IConfiguration>(),
o.GetRequiredService<DataDirectories>().DataDir);
if (dbOptions.DatabaseType == DatabaseType.Postgres)
{
Logs.Configuration.LogInformation($"Postgres DB used");
}
else if (dbOptions.DatabaseType == DatabaseType.MySQL)
{
Logs.Configuration.LogInformation($"MySQL DB used");
Logs.Configuration.LogWarning("MySQL is not widely tested and should be considered experimental, we advise you to use postgres instead.");
}
else if (dbOptions.DatabaseType == DatabaseType.Sqlite)
{
Logs.Configuration.LogInformation($"SQLite DB used");
Logs.Configuration.LogWarning("SQLite is not widely tested and should be considered experimental, we advise you to use postgres instead.");
}
return dbOptions;
}
catch (Exception ex)
{
throw new ConfigException($"No database option was configured. ({ex.Message})");
}
});
services.AddSingleton<ApplicationDbContextFactory>();
services.AddOptions<BTCPayServerOptions>().Configure(
(options) =>
{
options.LoadArgs(configuration);
});
services.AddOptions<DataDirectories>().Configure(
(options) =>
{
options.Configure(configuration);
});
services.AddOptions<DatabaseOptions>().Configure<IOptions<DataDirectories>>(
(options, datadirs) =>
{
var postgresConnectionString = configuration["postgres"];
var mySQLConnectionString = configuration["mysql"];
var sqliteFileName = configuration["sqlitefile"];
if (!string.IsNullOrEmpty(postgresConnectionString))
{
options.DatabaseType = DatabaseType.Postgres;
options.ConnectionString = postgresConnectionString;
}
else if (!string.IsNullOrEmpty(mySQLConnectionString))
{
options.DatabaseType = DatabaseType.MySQL;
options.ConnectionString = mySQLConnectionString;
}
else if (!string.IsNullOrEmpty(sqliteFileName))
{
var connStr = "Data Source=" + (Path.IsPathRooted(sqliteFileName)
? sqliteFileName
: Path.Combine(datadirs.Value.DataDir, sqliteFileName));
options.DatabaseType = DatabaseType.Sqlite;
options.ConnectionString = sqliteFileName;
}
else
{
throw new InvalidOperationException("No database option was configured.");
}
});
services.AddOptions<NBXplorerOptions>().Configure<BTCPayNetworkProvider>(
(options, btcPayNetworkProvider) =>
{
options.Configure(configuration, btcPayNetworkProvider);
foreach (BTCPayNetwork btcPayNetwork in btcPayNetworkProvider.GetAll().OfType<BTCPayNetwork>())
{
NBXplorerConnectionSetting setting =
new NBXplorerConnectionSetting
{
CryptoCode = btcPayNetwork.CryptoCode,
ExplorerUri = configuration.GetOrDefault<Uri>(
$"{btcPayNetwork.CryptoCode}.explorer.url",
btcPayNetwork.NBXplorerNetwork.DefaultSettings.DefaultUrl),
CookieFile = configuration.GetOrDefault<string>(
$"{btcPayNetwork.CryptoCode}.explorer.cookiefile",
btcPayNetwork.NBXplorerNetwork.DefaultSettings.DefaultCookieFile)
};
options.NBXplorerConnectionSettings.Add(setting);
}
});
services.AddOptions<LightningNetworkOptions>().Configure<BTCPayNetworkProvider>(
(options, btcPayNetworkProvider) =>
{
options.Configure(configuration, btcPayNetworkProvider);
foreach (var net in btcPayNetworkProvider.GetAll().OfType<BTCPayNetwork>())
{
var lightning = configuration.GetOrDefault<string>($"{net.CryptoCode}.lightning", string.Empty);
if (lightning.Length != 0)
{
if (!LightningConnectionString.TryParse(lightning, true, out var connectionString,
out var error))
{
Logs.Configuration.LogWarning($"Invalid setting {net.CryptoCode}.lightning, " +
Environment.NewLine +
$"If you have a c-lightning server use: 'type=clightning;server=/root/.lightning/lightning-rpc', " +
Environment.NewLine +
$"If you have a lightning charge server: 'type=charge;server=https://charge.example.com;api-token=yourapitoken'" +
Environment.NewLine +
$"If you have a lnd server: 'type=lnd-rest;server=https://lnd:lnd@lnd.example.com;macaroon=abf239...;certthumbprint=2abdf302...'" +
Environment.NewLine +
$" lnd server: 'type=lnd-rest;server=https://lnd:lnd@lnd.example.com;macaroonfilepath=/root/.lnd/admin.macaroon;certthumbprint=2abdf302...'" +
Environment.NewLine +
$"If you have an eclair server: 'type=eclair;server=http://eclair.com:4570;password=eclairpassword;bitcoin-host=bitcoind:37393;bitcoin-auth=bitcoinrpcuser:bitcoinrpcpassword" +
Environment.NewLine +
$" eclair server: 'type=eclair;server=http://eclair.com:4570;password=eclairpassword;bitcoin-host=bitcoind:37393" +
Environment.NewLine +
$"Error: {error}" + Environment.NewLine +
"This service will not be exposed through BTCPay Server");
}
else
{
if (connectionString.IsLegacy)
{
Logs.Configuration.LogWarning(
$"Setting {net.CryptoCode}.lightning is a deprecated format, it will work now, but please replace it for future versions with '{connectionString.ToString()}'");
}
options.InternalLightningByCryptoCode.Add(net.CryptoCode, connectionString);
}
}
}
});
services.AddOptions<ExternalServicesOptions>().Configure<BTCPayNetworkProvider>(
(options, btcPayNetworkProvider) =>
{
options.Configure(configuration, btcPayNetworkProvider);
foreach (var net in btcPayNetworkProvider.GetAll().OfType<BTCPayNetwork>())
{
options.ExternalServices.Load(net.CryptoCode, configuration);
}
options.ExternalServices.LoadNonCryptoServices(configuration);
var services = configuration.GetOrDefault<string>("externalservices", null);
if (services != null)
{
foreach (var service in services.Split(new[] {';', ','}, StringSplitOptions.RemoveEmptyEntries)
.Select(p => (p, SeparatorIndex: p.IndexOf(':', StringComparison.OrdinalIgnoreCase)))
.Where(p => p.SeparatorIndex != -1)
.Select(p => (Name: p.p.Substring(0, p.SeparatorIndex),
Link: p.p.Substring(p.SeparatorIndex + 1))))
{
if (Uri.TryCreate(service.Link, UriKind.RelativeOrAbsolute, out var uri))
options.OtherExternalServices.AddOrReplace(service.Name, uri);
}
}
});
services.TryAddSingleton(o => configuration.ConfigureNetworkProvider());

View file

@ -21,6 +21,7 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Microsoft.Net.Http.Headers;
using NBitcoin;
@ -45,11 +46,10 @@ namespace BTCPayServer.Hosting
public void ConfigureServices(IServiceCollection services)
{
Logs.Configure(LoggerFactory);
services.ConfigureBTCPayServer(Configuration);
services.AddMemoryCache();
services.AddDataProtection()
.SetApplicationName("BTCPay Server")
.PersistKeysToFileSystem(new DirectoryInfo(new DataDirectories(Configuration).DataDir));
.PersistKeysToFileSystem(new DirectoryInfo(new DataDirectories().Configure(Configuration).DataDir));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
@ -156,7 +156,7 @@ namespace BTCPayServer.Hosting
IWebHostEnvironment env,
IServiceProvider prov,
BTCPayServerOptions options,
DataDirectories dataDirectories,
IOptions<DataDirectories> dataDirectories,
ILoggerFactory loggerFactory)
{
Logs.Configuration.LogInformation($"Root Path: {options.RootPath}");
@ -172,7 +172,7 @@ namespace BTCPayServer.Hosting
});
}
}
private static void ConfigureCore(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider prov, ILoggerFactory loggerFactory, DataDirectories dataDirectories)
private static void ConfigureCore(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider prov, ILoggerFactory loggerFactory, IOptions<DataDirectories> dataDirectories)
{
Logs.Configure(loggerFactory);
app.UsePlugins();

View file

@ -28,7 +28,7 @@ namespace BTCPayServer.Plugins
IConfiguration config, ILoggerFactory loggerFactory)
{
_logger = loggerFactory.CreateLogger(typeof(PluginManager));
var pluginsFolder = new DataDirectories(config).PluginDir;
var pluginsFolder = new DataDirectories().Configure(config).PluginDir;
var plugins = new List<IBTCPayServerPlugin>();

View file

@ -11,19 +11,20 @@ using BTCPayServer.Configuration;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
namespace BTCPayServer.Plugins
{
public class PluginService: IPluginHookService
{
private readonly DataDirectories _datadirs;
private readonly IOptions<DataDirectories> _datadirs;
private readonly BTCPayServerOptions _options;
private readonly HttpClient _githubClient;
private readonly IEnumerable<IPluginHookAction> _actions;
private readonly IEnumerable<IPluginHookFilter> _filters;
public PluginService(IEnumerable<IBTCPayServerPlugin> btcPayServerPlugins,
IHttpClientFactory httpClientFactory, DataDirectories datadirs, BTCPayServerOptions options, IEnumerable<IPluginHookAction> actions, IEnumerable<IPluginHookFilter> filters)
IHttpClientFactory httpClientFactory, IOptions<DataDirectories> datadirs, BTCPayServerOptions options, IEnumerable<IPluginHookAction> actions, IEnumerable<IPluginHookFilter> filters)
{
LoadedPlugins = btcPayServerPlugins;
_githubClient = httpClientFactory.CreateClient();
@ -50,7 +51,7 @@ namespace BTCPayServer.Plugins
public async Task DownloadRemotePlugin(string plugin)
{
var dest = _datadirs.PluginDir;
var dest = _datadirs.Value.PluginDir;
var resp = await _githubClient
.GetStringAsync(new Uri($"https://api.github.com/repos/{_options.PluginRemote}/contents"));
var files = JsonConvert.DeserializeObject<GithubFile[]>(resp);
@ -67,19 +68,19 @@ namespace BTCPayServer.Plugins
public void InstallPlugin(string plugin)
{
var dest = _datadirs.PluginDir;
var dest = _datadirs.Value.PluginDir;
UninstallPlugin(plugin);
PluginManager.QueueCommands(dest, ("install", plugin));
}
public void UpdatePlugin(string plugin)
{
var dest = _datadirs.PluginDir;
var dest = _datadirs.Value.PluginDir;
PluginManager.QueueCommands(dest, ("update", plugin));
}
public async Task UploadPlugin(IFormFile plugin)
{
var dest = _datadirs.PluginDir;
var dest = _datadirs.Value.PluginDir;
var filedest = Path.Combine(dest, plugin.FileName);
Directory.CreateDirectory(Path.GetDirectoryName(filedest));
if (Path.GetExtension(filedest) == PluginManager.BTCPayPluginSuffix)
@ -91,7 +92,7 @@ namespace BTCPayServer.Plugins
public void UninstallPlugin(string plugin)
{
var dest = _datadirs.PluginDir;
var dest = _datadirs.Value.PluginDir;
PluginManager.QueueCommands(dest, ("delete", plugin));
}
@ -126,12 +127,12 @@ namespace BTCPayServer.Plugins
public (string command, string plugin)[] GetPendingCommands()
{
return PluginManager.GetPendingCommands(_datadirs.PluginDir);
return PluginManager.GetPendingCommands(_datadirs.Value.PluginDir);
}
public void CancelCommands(string plugin)
{
PluginManager.CancelCommands(_datadirs.PluginDir, plugin);
PluginManager.CancelCommands(_datadirs.Value.PluginDir, plugin);
}
public async Task ApplyAction(string hook, object args)

View file

@ -5,6 +5,7 @@ using BTCPayServer.Configuration;
using BTCPayServer.Data;
using BTCPayServer.Storage.Models;
using BTCPayServer.Storage.Services.Providers.FileSystemStorage.Configuration;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using TwentyTwenty.Storage;
using TwentyTwenty.Storage.Local;
@ -14,9 +15,9 @@ namespace BTCPayServer.Storage.Services.Providers.FileSystemStorage
public class
FileSystemFileProviderService : BaseTwentyTwentyStorageFileProviderServiceBase<FileSystemStorageConfiguration>
{
private readonly DataDirectories _datadirs;
private readonly IOptions<DataDirectories> _datadirs;
public FileSystemFileProviderService(DataDirectories datadirs)
public FileSystemFileProviderService(IOptions<DataDirectories> datadirs)
{
_datadirs = datadirs;
}
@ -30,14 +31,14 @@ namespace BTCPayServer.Storage.Services.Providers.FileSystemStorage
protected override Task<IStorageProvider> GetStorageProvider(FileSystemStorageConfiguration configuration)
{
return Task.FromResult<IStorageProvider>(
new LocalStorageProvider(new DirectoryInfo(_datadirs.StorageDir).FullName));
new LocalStorageProvider(new DirectoryInfo(_datadirs.Value.StorageDir).FullName));
}
public override async Task<string> GetFileUrl(Uri baseUri, StoredFile storedFile, StorageSettings configuration)
{
var baseResult = await base.GetFileUrl(baseUri, storedFile, configuration);
var url = new Uri(baseUri, LocalStorageDirectoryName);
return baseResult.Replace(new DirectoryInfo(_datadirs.StorageDir).FullName, url.AbsoluteUri,
return baseResult.Replace(new DirectoryInfo(_datadirs.Value.StorageDir).FullName, url.AbsoluteUri,
StringComparison.InvariantCultureIgnoreCase);
}
@ -53,13 +54,13 @@ namespace BTCPayServer.Storage.Services.Providers.FileSystemStorage
IsDownload = isDownload
};
var name = Guid.NewGuid().ToString();
var fullPath = Path.Combine(_datadirs.TempStorageDir, name);
var fullPath = Path.Combine(_datadirs.Value.TempStorageDir, name);
if (!File.Exists(fullPath))
{
File.Create(fullPath).Dispose();
}
await File.WriteAllTextAsync(Path.Combine(_datadirs.TempStorageDir, name), JsonConvert.SerializeObject(localFileDescriptor));
await File.WriteAllTextAsync(Path.Combine(_datadirs.Value.TempStorageDir, name), JsonConvert.SerializeObject(localFileDescriptor));
return new Uri(baseUri, $"{LocalStorageDirectoryName}tmp/{name}{(isDownload ? "?download" : string.Empty)}").AbsoluteUri;
}

View file

@ -12,6 +12,7 @@ using Microsoft.AspNetCore.StaticFiles;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.FileProviders;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using NBitcoin.Logging;
namespace BTCPayServer.Storage
@ -28,28 +29,28 @@ namespace BTCPayServer.Storage
// serviceCollection.AddSingleton<IStorageProviderService, GoogleCloudStorageFileProviderService>();
}
public static void UseProviderStorage(this IApplicationBuilder builder, DataDirectories datadirs)
public static void UseProviderStorage(this IApplicationBuilder builder, IOptions<DataDirectories> datadirs)
{
try
{
DirectoryInfo dirInfo;
if (!Directory.Exists(datadirs.StorageDir))
if (!Directory.Exists(datadirs.Value.StorageDir))
{
dirInfo = Directory.CreateDirectory(datadirs.StorageDir);
dirInfo = Directory.CreateDirectory(datadirs.Value.StorageDir);
}
else
{
dirInfo = new DirectoryInfo(datadirs.StorageDir);
dirInfo = new DirectoryInfo(datadirs.Value.StorageDir);
}
DirectoryInfo tmpdirInfo;
if (!Directory.Exists(datadirs.TempStorageDir))
if (!Directory.Exists(datadirs.Value.TempStorageDir))
{
tmpdirInfo = Directory.CreateDirectory(datadirs.TempStorageDir);
tmpdirInfo = Directory.CreateDirectory(datadirs.Value.TempStorageDir);
}
else
{
tmpdirInfo = new DirectoryInfo(datadirs.TempStorageDir);
tmpdirInfo = new DirectoryInfo(datadirs.Value.TempStorageDir);
}
builder.UseStaticFiles(new StaticFileOptions()