mirror of
https://github.com/aljazceru/btcpayserver.git
synced 2026-01-31 11:54:24 +01:00
Fix migration of Invoice's payment (#6241)
This commit is contained in:
@@ -210,7 +210,7 @@ namespace BTCPayServer.Data
|
||||
}
|
||||
|
||||
blob.ConvertNumberToString("price");
|
||||
Currency = blob["currency"].Value<string>();
|
||||
Currency = blob["currency"].Value<string>().ToUpperInvariant();
|
||||
var isTopup = blob["type"]?.Value<string>() is "TopUp";
|
||||
var amount = decimal.Parse(blob["price"].Value<string>(), CultureInfo.InvariantCulture);
|
||||
Amount = isTopup && amount == 0 ? null : decimal.Parse(blob["price"].Value<string>(), CultureInfo.InvariantCulture);
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Reflection.Metadata;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using BTCPayServer.Migrations;
|
||||
using Microsoft.EntityFrameworkCore.ChangeTracking.Internal;
|
||||
using NBitcoin;
|
||||
using NBitcoin.Altcoins;
|
||||
using NBitcoin.DataEncoders;
|
||||
@@ -44,6 +46,7 @@ namespace BTCPayServer.Data
|
||||
}
|
||||
|
||||
var cryptoCode = blob["cryptoCode"].Value<string>();
|
||||
MigratedPaymentMethodId = PaymentMethodId;
|
||||
PaymentMethodId = cryptoCode + "_" + blob["cryptoPaymentDataType"].Value<string>();
|
||||
PaymentMethodId = MigrationExtensions.MigratePaymentMethodId(PaymentMethodId);
|
||||
var divisibility = MigrationExtensions.GetDivisibility(PaymentMethodId);
|
||||
@@ -163,6 +166,9 @@ namespace BTCPayServer.Data
|
||||
}
|
||||
[NotMapped]
|
||||
public bool Migrated { get; set; }
|
||||
[NotMapped]
|
||||
[EditorBrowsable(EditorBrowsableState.Never)]
|
||||
public string MigratedPaymentMethodId { get; set; }
|
||||
|
||||
static readonly DateTimeOffset unixRef = new DateTimeOffset(1970, 1, 1, 0, 0, 0, TimeSpan.Zero);
|
||||
public static long DateTimeToMilliUnixTime(in DateTime time)
|
||||
|
||||
@@ -704,7 +704,7 @@ retry:
|
||||
{
|
||||
var localPayment = invoice.Replace("3sgUCCtUBg6S8LJkrbdfAWbsJMqByFLfvSqjG6xKBWEd", storeId);
|
||||
// Old data could have Type to null.
|
||||
localPayment += "BTC-CHAIN";
|
||||
localPayment += "UNKNOWN";
|
||||
await writer.WriteLineAsync(localPayment);
|
||||
}
|
||||
await writer.FlushAsync();
|
||||
|
||||
@@ -29,7 +29,7 @@ public abstract class BlobMigratorHostedService<TEntity> : IHostedService
|
||||
public bool Complete { get; set; }
|
||||
}
|
||||
Task? _Migrating;
|
||||
TaskCompletionSource _Cts = new TaskCompletionSource();
|
||||
CancellationTokenSource? _Cts;
|
||||
public BlobMigratorHostedService(
|
||||
ILogger logs,
|
||||
ISettingsRepository settingsRepository,
|
||||
@@ -46,7 +46,8 @@ public abstract class BlobMigratorHostedService<TEntity> : IHostedService
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_Migrating = Migrate(cancellationToken);
|
||||
_Cts = new CancellationTokenSource();
|
||||
_Migrating = Migrate(_Cts.Token);
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
public int BatchSize { get; set; } = 1000;
|
||||
@@ -61,47 +62,57 @@ public abstract class BlobMigratorHostedService<TEntity> : IHostedService
|
||||
else
|
||||
Logs.LogInformation("Migrating from the beginning");
|
||||
|
||||
|
||||
int batchSize = BatchSize;
|
||||
retry:
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
retry:
|
||||
List<TEntity> entities;
|
||||
DateTimeOffset progress;
|
||||
await using (var ctx = ApplicationDbContextFactory.CreateContext(o => o.CommandTimeout((int)TimeSpan.FromDays(1.0).TotalSeconds)))
|
||||
try
|
||||
{
|
||||
var query = GetQuery(ctx, settings?.Progress).Take(batchSize);
|
||||
entities = await query.ToListAsync(cancellationToken);
|
||||
if (entities.Count == 0)
|
||||
List<TEntity> entities;
|
||||
DateTimeOffset progress;
|
||||
await using (var ctx = ApplicationDbContextFactory.CreateContext(o => o.CommandTimeout((int)TimeSpan.FromDays(1.0).TotalSeconds)))
|
||||
{
|
||||
var count = await GetQuery(ctx, null).CountAsync(cancellationToken);
|
||||
if (count != 0)
|
||||
var query = GetQuery(ctx, settings?.Progress).Take(batchSize);
|
||||
entities = await query.ToListAsync(cancellationToken);
|
||||
if (entities.Count == 0)
|
||||
{
|
||||
settings = new Settings() { Progress = null };
|
||||
Logs.LogWarning("Corruption detected, reindexing the table...");
|
||||
await Reindex(ctx, cancellationToken);
|
||||
var count = await GetQuery(ctx, null).CountAsync(cancellationToken);
|
||||
if (count != 0)
|
||||
{
|
||||
settings = new Settings() { Progress = null };
|
||||
Logs.LogWarning("Corruption detected, reindexing the table...");
|
||||
await Reindex(ctx, cancellationToken);
|
||||
goto retry;
|
||||
}
|
||||
await SettingsRepository.UpdateSetting<Settings>(new Settings() { Complete = true }, SettingsKey);
|
||||
Logs.LogInformation("Migration completed");
|
||||
await PostMigrationCleanup(ctx, cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
progress = ProcessEntities(ctx, entities);
|
||||
await ctx.SaveChangesAsync();
|
||||
batchSize = BatchSize;
|
||||
}
|
||||
catch (Exception ex) when (ex is DbUpdateConcurrencyException or TimeoutException or OperationCanceledException)
|
||||
{
|
||||
batchSize /= 2;
|
||||
batchSize = Math.Max(1, batchSize);
|
||||
goto retry;
|
||||
}
|
||||
await SettingsRepository.UpdateSetting<Settings>(new Settings() { Complete = true }, SettingsKey);
|
||||
Logs.LogInformation("Migration completed");
|
||||
await PostMigrationCleanup(ctx, cancellationToken);
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
progress = ProcessEntities(ctx, entities);
|
||||
await ctx.SaveChangesAsync();
|
||||
batchSize = BatchSize;
|
||||
}
|
||||
catch (Exception ex) when (ex is DbUpdateConcurrencyException or TimeoutException or OperationCanceledException)
|
||||
{
|
||||
batchSize /= 2;
|
||||
batchSize = Math.Max(1, batchSize);
|
||||
goto retry;
|
||||
}
|
||||
settings = new Settings() { Progress = progress };
|
||||
await SettingsRepository.UpdateSetting<Settings>(settings, SettingsKey);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logs.LogError(ex, "Error while migrating");
|
||||
goto retry;
|
||||
}
|
||||
settings = new Settings() { Progress = progress };
|
||||
await SettingsRepository.UpdateSetting<Settings>(settings, SettingsKey);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -121,11 +132,7 @@ retry:
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
_Cts.TrySetCanceled();
|
||||
return (_Migrating ?? Task.CompletedTask).ContinueWith(t =>
|
||||
{
|
||||
if (t.IsFaulted)
|
||||
Logs.LogError(t.Exception, "Error while migrating");
|
||||
});
|
||||
_Cts?.Cancel();
|
||||
return _Migrating ?? Task.CompletedTask;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,6 +71,12 @@ public class InvoiceBlobMigratorHostedService : BlobMigratorHostedService<Invoic
|
||||
paymentEntity.Details = JToken.FromObject(handler.ParsePaymentDetails(paymentEntity.Details), handler.Serializer);
|
||||
}
|
||||
pay.SetBlob(paymentEntity);
|
||||
|
||||
if (pay.PaymentMethodId != pay.MigratedPaymentMethodId)
|
||||
{
|
||||
ctx.Entry(pay).State = EntityState.Added;
|
||||
ctx.Payments.Remove(new PaymentData() { Id = pay.Id, PaymentMethodId = pay.MigratedPaymentMethodId });
|
||||
}
|
||||
}
|
||||
}
|
||||
return invoices[^1].Created;
|
||||
|
||||
Reference in New Issue
Block a user