voidkitty/VoidCat/Services/Payment/StrikePaymentProvider.cs

145 lines
5.2 KiB
C#
Raw Normal View History

2022-02-21 12:54:57 +00:00
using System.Globalization;
using VoidCat.Database;
2022-02-21 12:54:57 +00:00
using VoidCat.Model;
using VoidCat.Services.Abstractions;
2022-02-22 14:20:31 +00:00
using VoidCat.Services.Strike;
2022-02-21 12:54:57 +00:00
2022-09-07 14:52:40 +00:00
namespace VoidCat.Services.Payment;
2022-02-21 12:54:57 +00:00
2022-06-13 13:35:26 +00:00
/// <inheritdoc />
2022-09-07 14:52:40 +00:00
public class StrikePaymentProvider : IPaymentProvider
2022-02-21 12:54:57 +00:00
{
2022-09-07 14:52:40 +00:00
private readonly ILogger<StrikePaymentProvider> _logger;
2022-02-21 12:54:57 +00:00
private readonly StrikeApi _strike;
2022-09-07 14:52:40 +00:00
private readonly IPaymentOrderStore _orderStore;
2022-02-21 12:54:57 +00:00
2022-09-07 14:52:40 +00:00
public StrikePaymentProvider(ILogger<StrikePaymentProvider> logger, StrikeApi strike, IPaymentOrderStore orderStore)
2022-02-21 12:54:57 +00:00
{
_logger = logger;
_strike = strike;
2022-06-13 13:35:26 +00:00
_orderStore = orderStore;
2022-02-21 12:54:57 +00:00
}
2022-06-13 13:35:26 +00:00
/// <inheritdoc />
public async ValueTask<PaywallOrder?> CreateOrder(Paywall config)
2022-02-21 12:54:57 +00:00
{
2023-05-30 10:24:13 +00:00
if (config.Service != PaywallService.Strike || config.Upstream == default)
{
throw new InvalidOperationException("Paywall config is not Strike");
}
_logger.LogInformation("Generating invoice for {Currency} {Amount}", config.Currency, config.Amount);
2022-02-21 12:54:57 +00:00
var currency = MapCurrency(config.Currency);
2022-02-21 12:54:57 +00:00
if (currency == Currencies.USD)
{
// map USD to USDT if USD is not available and USDT is
2023-05-30 10:24:13 +00:00
var profile = await _strike.GetProfile(config.Upstream);
2022-02-21 12:54:57 +00:00
if (profile != default)
{
var usd = profile.Currencies.FirstOrDefault(a => a.Currency == Currencies.USD);
var usdt = profile.Currencies.FirstOrDefault(a => a.Currency == Currencies.USDT);
if (!(usd?.IsAvailable ?? false) && (usdt?.IsAvailable ?? false))
{
currency = Currencies.USDT;
}
}
}
var invoice = await _strike.GenerateInvoice(new()
{
2023-05-30 10:24:13 +00:00
Handle = config.Upstream,
2022-02-21 12:54:57 +00:00
Amount = new()
{
Amount = config.Amount.ToString(CultureInfo.InvariantCulture),
2022-02-21 12:54:57 +00:00
Currency = currency
},
Description = config.File.Id.ToBase58()
2022-02-21 12:54:57 +00:00
});
if (invoice != default)
{
var quote = await _strike.GetInvoiceQuote(invoice.InvoiceId);
if (quote != default)
{
var order = new PaywallOrder
2022-06-13 13:35:26 +00:00
{
Id = invoice.InvoiceId,
FileId = config.File.Id,
Service = PaywallService.Strike,
Amount = config.Amount,
Status = PaywallOrderStatus.Unpaid,
OrderLightning = new()
{
OrderId = invoice.InvoiceId,
Invoice = quote.LnInvoice!,
Expire = DateTime.SpecifyKind(quote.Expiration.DateTime, DateTimeKind.Utc)
}
2022-06-13 13:35:26 +00:00
};
await _orderStore.Add(order.Id, order);
2022-02-21 12:54:57 +00:00
return order;
}
_logger.LogWarning("Failed to get quote for invoice: {Id}", invoice.InvoiceId);
}
2022-06-13 13:35:26 +00:00
_logger.LogWarning("Failed to get invoice for config: File={File}, Service={Service}", config.File,
config.Service.ToString());
2022-02-21 12:54:57 +00:00
return default;
}
2022-06-13 13:35:26 +00:00
/// <inheritdoc />
public async ValueTask<PaywallOrder?> GetOrderStatus(Guid id)
2022-02-21 12:54:57 +00:00
{
2022-06-13 13:35:26 +00:00
var order = await _orderStore.Get(id);
if (order is {Status: PaywallOrderStatus.Paid or PaywallOrderStatus.Expired}) return order;
2022-06-13 13:35:26 +00:00
var providerOrder = await _strike.GetInvoice(id);
if (providerOrder != default)
2022-02-21 12:54:57 +00:00
{
2022-06-13 13:35:26 +00:00
var status = MapStatus(providerOrder.State);
await _orderStore.UpdateStatus(id, status);
return new()
2022-02-21 12:54:57 +00:00
{
2022-06-13 13:35:26 +00:00
Id = id,
Amount = decimal.Parse(providerOrder.Amount!.Amount!),
Currency = MapCurrency(providerOrder.Amount!.Currency!.Value),
Service = PaywallService.Strike,
2022-06-13 13:35:26 +00:00
Status = status
};
2022-02-21 12:54:57 +00:00
}
2022-06-13 13:35:26 +00:00
return default;
2022-02-21 12:54:57 +00:00
}
private PaywallOrderStatus MapStatus(InvoiceState providerOrderState)
2022-06-13 13:35:26 +00:00
=> providerOrderState switch
{
InvoiceState.UNPAID => PaywallOrderStatus.Unpaid,
InvoiceState.PENDING => PaywallOrderStatus.Unpaid,
InvoiceState.PAID => PaywallOrderStatus.Paid,
InvoiceState.CANCELLED => PaywallOrderStatus.Expired,
2022-06-13 13:35:26 +00:00
_ => throw new ArgumentOutOfRangeException(nameof(providerOrderState), providerOrderState, null)
};
private static Currencies MapCurrency(PaywallCurrency c)
2022-02-21 12:54:57 +00:00
=> c switch
{
PaywallCurrency.BTC => Currencies.BTC,
PaywallCurrency.USD => Currencies.USD,
PaywallCurrency.EUR => Currencies.EUR,
PaywallCurrency.GBP => Currencies.GBP,
2022-02-21 12:54:57 +00:00
_ => throw new ArgumentOutOfRangeException(nameof(c), c, null)
};
private static PaywallCurrency MapCurrency(Currencies c)
2022-02-21 12:54:57 +00:00
=> c switch
{
Currencies.BTC => PaywallCurrency.BTC,
Currencies.USD => PaywallCurrency.USD,
Currencies.USDT => PaywallCurrency.USD,
Currencies.EUR => PaywallCurrency.EUR,
Currencies.GBP => PaywallCurrency.GBP,
2022-02-21 12:54:57 +00:00
_ => throw new ArgumentOutOfRangeException(nameof(c), c, null)
};
}