diff --git a/BTCPayServer/BTCPayServer.csproj b/BTCPayServer/BTCPayServer.csproj index e1dcfb2c5..fb9c22f3d 100644 --- a/BTCPayServer/BTCPayServer.csproj +++ b/BTCPayServer/BTCPayServer.csproj @@ -12,6 +12,7 @@ + @@ -20,6 +21,7 @@ + @@ -36,10 +38,6 @@ - - - - diff --git a/BTCPayServer/Configuration/BTCPayServerOptions.cs b/BTCPayServer/Configuration/BTCPayServerOptions.cs index ab7c0b717..2e0eb5e65 100644 --- a/BTCPayServer/Configuration/BTCPayServerOptions.cs +++ b/BTCPayServer/Configuration/BTCPayServerOptions.cs @@ -56,11 +56,17 @@ namespace BTCPayServer.Configuration Explorer = conf.GetOrDefault("explorer.url", networkInfo.DefaultExplorerUrl); CookieFile = conf.GetOrDefault("explorer.cookiefile", networkInfo.DefaultExplorerCookieFile); RequireHttps = conf.GetOrDefault("requirehttps", false); + PostgresConnectionString = conf.GetOrDefault("postgres", null); } public bool RequireHttps { get; set; } + public string PostgresConnectionString + { + get; + set; + } } } diff --git a/BTCPayServer/Configuration/BTCPayServerRuntime.cs b/BTCPayServer/Configuration/BTCPayServerRuntime.cs index 293e36a36..f0da1c293 100644 --- a/BTCPayServer/Configuration/BTCPayServerRuntime.cs +++ b/BTCPayServer/Configuration/BTCPayServerRuntime.cs @@ -56,7 +56,11 @@ namespace BTCPayServer.Configuration db = new DBreezeEngine(CreateDBPath(opts, "InvoiceDB")); _Resources.Add(db); - var dbContext = new ApplicationDbContextFactory(Path.Combine(opts.DataDir, "sqllite.db")); + ApplicationDbContextFactory dbContext = null; + if(opts.PostgresConnectionString == null) + dbContext = new ApplicationDbContextFactory(DatabaseType.Sqlite, "Data Source=" + Path.Combine(opts.DataDir, "sqllite.db")); + else + dbContext = new ApplicationDbContextFactory(DatabaseType.Postgres, opts.PostgresConnectionString); DBFactory = dbContext; InvoiceRepository = new InvoiceRepository(dbContext, db, Network); diff --git a/BTCPayServer/Configuration/DefaultConfiguration.cs b/BTCPayServer/Configuration/DefaultConfiguration.cs index 76d5e6f40..53f362e8f 100644 --- a/BTCPayServer/Configuration/DefaultConfiguration.cs +++ b/BTCPayServer/Configuration/DefaultConfiguration.cs @@ -27,6 +27,7 @@ namespace BTCPayServer.Configuration app.Option("--testnet | -testnet", $"Use testnet", CommandOptionType.BoolValue); app.Option("--regtest | -regtest", $"Use regtest", CommandOptionType.BoolValue); app.Option("--requirehttps", $"Will redirect to https version of the website (default: false)", CommandOptionType.BoolValue); + app.Option("--postgres", $"Connection string to postgres database (default: sqlite is used)", CommandOptionType.SingleValue); app.Option("--explorerurl", $"Url of the NBxplorer (default: : Default setting of NBXplorer for the network)", CommandOptionType.SingleValue); app.Option("--explorercookiefile", $"Path to the cookie file (default: Default setting of NBXplorer for the network)", CommandOptionType.SingleValue); @@ -78,6 +79,9 @@ namespace BTCPayServer.Configuration builder.AppendLine("#port=" + network.DefaultPort); builder.AppendLine("#bind=127.0.0.1"); builder.AppendLine(); + builder.AppendLine("### Database ###"); + builder.AppendLine("#postgres=User ID=root;Password=myPassword;Host=localhost;Port=5432;Database=myDataBase;"); + builder.AppendLine(); builder.AppendLine("### NBXplorer settings ###"); builder.AppendLine("#explorer.url=" + network.DefaultExplorerUrl.AbsoluteUri); builder.AppendLine("#explorer.cookiefile=" + network.DefaultExplorerCookieFile); diff --git a/BTCPayServer/Data/ApplicationDbContext.cs b/BTCPayServer/Data/ApplicationDbContext.cs index f97122d93..3ad386d14 100644 --- a/BTCPayServer/Data/ApplicationDbContext.cs +++ b/BTCPayServer/Data/ApplicationDbContext.cs @@ -6,6 +6,7 @@ using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; using BTCPayServer.Models; using Microsoft.EntityFrameworkCore.Infrastructure.Internal; +using Microsoft.EntityFrameworkCore.Infrastructure; namespace BTCPayServer.Data { @@ -52,8 +53,8 @@ namespace BTCPayServer.Data protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { - var options = optionsBuilder.Options.FindExtension(); - if(options?.ConnectionString == null) + var isConfigured = optionsBuilder.Options.Extensions.OfType().Any(); + if(!isConfigured) optionsBuilder.UseSqlite("Data Source=temp.db"); } @@ -70,7 +71,8 @@ namespace BTCPayServer.Data .HasIndex(o => o.InvoiceDataId); builder.Entity() - .HasKey(t => new { + .HasKey(t => new + { t.ApplicationUserId, t.StoreDataId }); diff --git a/BTCPayServer/Data/ApplicationDbContextFactory.cs b/BTCPayServer/Data/ApplicationDbContextFactory.cs index 3e8f70f85..d6368313f 100644 --- a/BTCPayServer/Data/ApplicationDbContextFactory.cs +++ b/BTCPayServer/Data/ApplicationDbContextFactory.cs @@ -3,22 +3,48 @@ using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; +using Hangfire; +using Hangfire.MemoryStorage; +using Hangfire.PostgreSql; namespace BTCPayServer.Data { + public enum DatabaseType + { + Sqlite, + Postgres + } public class ApplicationDbContextFactory { - string _Path; - public ApplicationDbContextFactory(string path) + string _ConnectionString; + DatabaseType _Type; + public ApplicationDbContextFactory(DatabaseType type, string connectionString) { - _Path = path ?? throw new ArgumentNullException(nameof(path)); + _ConnectionString = connectionString ?? throw new ArgumentNullException(nameof(connectionString)); + _Type = type; } public ApplicationDbContext CreateContext() { var builder = new DbContextOptionsBuilder(); - builder.UseSqlite("Data Source=" + _Path); + ConfigureBuilder(builder); return new ApplicationDbContext(builder.Options); } + + public void ConfigureBuilder(DbContextOptionsBuilder builder) + { + if(_Type == DatabaseType.Sqlite) + builder.UseSqlite(_ConnectionString); + else if(_Type == DatabaseType.Postgres) + builder.UseNpgsql(_ConnectionString); + } + + public void ConfigureHangfireBuilder(IGlobalConfiguration builder) + { + if(_Type == DatabaseType.Sqlite) + builder.UseMemoryStorage(); //Sql provider does not support multiple workers + else if(_Type == DatabaseType.Postgres) + builder.UsePostgreSqlStorage(_ConnectionString); + } } } diff --git a/BTCPayServer/Hosting/BTCPayServerServices.cs b/BTCPayServer/Hosting/BTCPayServerServices.cs index 3ed2be04a..2881d58d1 100644 --- a/BTCPayServer/Hosting/BTCPayServerServices.cs +++ b/BTCPayServer/Hosting/BTCPayServerServices.cs @@ -92,8 +92,8 @@ namespace BTCPayServer.Hosting { services.AddDbContext((provider, o) => { - var path = Path.Combine(provider.GetRequiredService().DataDir, "sqllite.db"); - o.UseSqlite("Data Source=" + path); + var factory = provider.GetRequiredService(); + factory.ConfigureBuilder(o); }); services.TryAddSingleton(); services.TryAddSingleton(); diff --git a/BTCPayServer/Hosting/Startup.cs b/BTCPayServer/Hosting/Startup.cs index ca4af5872..e8305eb93 100644 --- a/BTCPayServer/Hosting/Startup.cs +++ b/BTCPayServer/Hosting/Startup.cs @@ -19,7 +19,6 @@ using Microsoft.AspNetCore.Identity; using BTCPayServer.Data; using Microsoft.Extensions.Logging; using Hangfire; -using Hangfire.MemoryStorage; using BTCPayServer.Logging; using Microsoft.AspNetCore.Authorization; using System.Threading.Tasks; @@ -82,10 +81,9 @@ namespace BTCPayServer.Hosting Action configuration = o => { var scope = AspNetCoreJobActivator.Current.BeginScope(null); - var options = (ApplicationDbContext)scope.Resolve(typeof(ApplicationDbContext)); - var path = Path.Combine(((BTCPayServerOptions)scope.Resolve(typeof(BTCPayServerOptions))).DataDir, "hangfire.db"); - o.UseMemoryStorage(); //SQLite provider can work with only one background job :/ - }; + var options = (ApplicationDbContextFactory)scope.Resolve(typeof(ApplicationDbContextFactory)); + options.ConfigureHangfireBuilder(o); + }; ServiceCollectionDescriptorExtensions.TryAddSingleton>(services, (IServiceProvider serviceProvider) => new Action((config) => { diff --git a/BTCPayServer/Migrations/20170913143004_Init.cs b/BTCPayServer/Migrations/20170913143004_Init.cs index b82911674..7d58bd4b1 100644 --- a/BTCPayServer/Migrations/20170913143004_Init.cs +++ b/BTCPayServer/Migrations/20170913143004_Init.cs @@ -30,16 +30,16 @@ namespace BTCPayServer.Migrations AccessFailedCount = table.Column(type: "INTEGER", nullable: false), ConcurrencyStamp = table.Column(type: "TEXT", nullable: true), Email = table.Column(type: "TEXT", maxLength: 256, nullable: true), - EmailConfirmed = table.Column(type: "INTEGER", nullable: false), - LockoutEnabled = table.Column(type: "INTEGER", nullable: false), - LockoutEnd = table.Column(type: "TEXT", nullable: true), + EmailConfirmed = table.Column(nullable: false), + LockoutEnabled = table.Column(nullable: false), + LockoutEnd = table.Column(nullable: true), NormalizedEmail = table.Column(type: "TEXT", maxLength: 256, nullable: true), NormalizedUserName = table.Column(type: "TEXT", maxLength: 256, nullable: true), PasswordHash = table.Column(type: "TEXT", nullable: true), PhoneNumber = table.Column(type: "TEXT", nullable: true), - PhoneNumberConfirmed = table.Column(type: "INTEGER", nullable: false), + PhoneNumberConfirmed = table.Column(nullable: false), SecurityStamp = table.Column(type: "TEXT", nullable: true), - TwoFactorEnabled = table.Column(type: "INTEGER", nullable: false), + TwoFactorEnabled = table.Column(nullable: false), UserName = table.Column(type: "TEXT", maxLength: 256, nullable: true) }, constraints: table => @@ -54,7 +54,7 @@ namespace BTCPayServer.Migrations Id = table.Column(type: "TEXT", nullable: false), DerivationStrategy = table.Column(type: "TEXT", nullable: true), SpeedPolicy = table.Column(type: "INTEGER", nullable: false), - StoreCertificate = table.Column(type: "BLOB", nullable: true), + StoreCertificate = table.Column(nullable: true), StoreName = table.Column(type: "TEXT", nullable: true), StoreWebsite = table.Column(type: "TEXT", nullable: true) }, @@ -174,8 +174,8 @@ namespace BTCPayServer.Migrations columns: table => new { Id = table.Column(type: "TEXT", nullable: false), - Blob = table.Column(type: "BLOB", nullable: true), - Created = table.Column(type: "TEXT", nullable: false), + Blob = table.Column(nullable: true), + Created = table.Column(nullable: false), CustomerEmail = table.Column(type: "TEXT", nullable: true), ExceptionStatus = table.Column(type: "TEXT", nullable: true), ItemCode = table.Column(type: "TEXT", nullable: true), @@ -224,7 +224,7 @@ namespace BTCPayServer.Migrations columns: table => new { Id = table.Column(type: "TEXT", nullable: false), - Blob = table.Column(type: "BLOB", nullable: true), + Blob = table.Column(nullable: true), InvoiceDataId = table.Column(type: "TEXT", nullable: true) }, constraints: table => @@ -243,7 +243,7 @@ namespace BTCPayServer.Migrations columns: table => new { Id = table.Column(type: "TEXT", nullable: false), - Blob = table.Column(type: "BLOB", nullable: true), + Blob = table.Column(nullable: true), InvoiceDataId = table.Column(type: "TEXT", nullable: true) }, constraints: table => diff --git a/BTCPayServer/Migrations/20170926084408_RequiresEmailConfirmation.cs b/BTCPayServer/Migrations/20170926084408_RequiresEmailConfirmation.cs index 23592089b..48f2cfe23 100644 --- a/BTCPayServer/Migrations/20170926084408_RequiresEmailConfirmation.cs +++ b/BTCPayServer/Migrations/20170926084408_RequiresEmailConfirmation.cs @@ -11,7 +11,6 @@ namespace BTCPayServer.Migrations migrationBuilder.AddColumn( name: "RequiresEmailConfirmation", table: "AspNetUsers", - type: "INTEGER", nullable: false, defaultValue: false); }