2020-06-28 21:44:35 -05:00
|
|
|
using System;
|
2018-04-14 22:35:52 +09:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
2018-05-12 00:54:17 +09:00
|
|
|
using System.Net.Http;
|
2023-01-30 09:46:12 +09:00
|
|
|
using System.Security.Cryptography;
|
2019-03-05 17:09:17 +09:00
|
|
|
using System.Threading;
|
2018-04-14 22:35:52 +09:00
|
|
|
using System.Threading.Tasks;
|
2018-05-03 03:32:42 +09:00
|
|
|
using BTCPayServer.Rating;
|
2022-12-14 13:14:19 +09:00
|
|
|
using BTCPayServer.Rating.Providers;
|
2018-05-04 15:35:39 +09:00
|
|
|
using ExchangeSharp;
|
2023-01-30 09:46:12 +09:00
|
|
|
using NBitcoin;
|
2020-01-13 22:20:45 +09:00
|
|
|
using Newtonsoft.Json.Linq;
|
2018-04-14 22:35:52 +09:00
|
|
|
|
|
|
|
namespace BTCPayServer.Services.Rates
|
|
|
|
{
|
2018-08-22 16:53:40 +09:00
|
|
|
public class RateProviderFactory
|
2018-04-14 22:35:52 +09:00
|
|
|
{
|
2018-08-23 00:24:33 +09:00
|
|
|
class WrapperRateProvider : IRateProvider
|
|
|
|
{
|
2023-01-30 09:46:12 +09:00
|
|
|
public RateSourceInfo RateSourceInfo => _inner.RateSourceInfo;
|
2018-08-23 00:24:33 +09:00
|
|
|
private readonly IRateProvider _inner;
|
|
|
|
public Exception Exception { get; private set; }
|
|
|
|
public TimeSpan Latency { get; set; }
|
|
|
|
public WrapperRateProvider(IRateProvider inner)
|
|
|
|
{
|
|
|
|
_inner = inner;
|
|
|
|
}
|
2020-01-17 18:11:05 +09:00
|
|
|
public async Task<PairRate[]> GetRatesAsync(CancellationToken cancellationToken)
|
2018-08-23 00:24:33 +09:00
|
|
|
{
|
|
|
|
DateTimeOffset now = DateTimeOffset.UtcNow;
|
|
|
|
try
|
|
|
|
{
|
2019-03-05 17:09:17 +09:00
|
|
|
return await _inner.GetRatesAsync(cancellationToken);
|
2018-08-23 00:24:33 +09:00
|
|
|
}
|
|
|
|
catch (Exception ex)
|
|
|
|
{
|
|
|
|
Exception = ex;
|
2020-01-17 18:11:05 +09:00
|
|
|
return Array.Empty<PairRate>();
|
2018-08-23 00:24:33 +09:00
|
|
|
}
|
|
|
|
finally
|
|
|
|
{
|
|
|
|
Latency = DateTimeOffset.UtcNow - now;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-08-22 16:53:40 +09:00
|
|
|
public class QueryRateResult
|
2018-05-03 03:32:42 +09:00
|
|
|
{
|
2018-08-23 00:24:33 +09:00
|
|
|
public TimeSpan Latency { get; set; }
|
2020-01-17 18:11:05 +09:00
|
|
|
public PairRate[] PairRates { get; set; }
|
2018-08-23 00:24:33 +09:00
|
|
|
public ExchangeException Exception { get; internal set; }
|
2020-01-17 18:11:05 +09:00
|
|
|
public string Exchange { get; internal set; }
|
2018-05-03 03:32:42 +09:00
|
|
|
}
|
2023-01-30 09:46:12 +09:00
|
|
|
public RateProviderFactory(IHttpClientFactory httpClientFactory, IEnumerable<IRateProvider> rateProviders)
|
2018-08-22 16:53:40 +09:00
|
|
|
{
|
|
|
|
_httpClientFactory = httpClientFactory;
|
2023-01-30 09:46:12 +09:00
|
|
|
foreach (var prov in rateProviders)
|
2018-08-22 16:53:40 +09:00
|
|
|
{
|
2023-01-30 09:46:12 +09:00
|
|
|
Providers.Add(prov.RateSourceInfo.Id, prov);
|
2018-08-22 16:53:40 +09:00
|
|
|
}
|
2023-01-30 09:46:12 +09:00
|
|
|
InitExchanges();
|
2018-05-03 03:32:42 +09:00
|
|
|
}
|
2023-01-30 09:46:12 +09:00
|
|
|
private readonly IHttpClientFactory _httpClientFactory;
|
|
|
|
public Dictionary<string, IRateProvider> Providers { get; } = new Dictionary<string, IRateProvider>();
|
2020-01-13 22:20:45 +09:00
|
|
|
void InitExchanges()
|
2018-05-03 03:32:42 +09:00
|
|
|
{
|
2018-08-23 00:24:33 +09:00
|
|
|
foreach (var provider in Providers.ToArray())
|
|
|
|
{
|
2020-01-18 19:42:46 +09:00
|
|
|
var prov = new BackgroundFetcherRateProvider(Providers[provider.Key]);
|
2020-01-17 14:16:12 +09:00
|
|
|
prov.RefreshRate = TimeSpan.FromMinutes(1.0);
|
|
|
|
prov.ValidatyTime = TimeSpan.FromMinutes(5.0);
|
2018-08-23 00:24:33 +09:00
|
|
|
Providers[provider.Key] = prov;
|
2023-01-30 09:46:12 +09:00
|
|
|
var rsi = provider.Value.RateSourceInfo;
|
|
|
|
AvailableRateProviders.Add(new(rsi.Id, rsi.DisplayName, rsi.Url));
|
2018-08-23 00:24:33 +09:00
|
|
|
}
|
|
|
|
|
2023-01-30 09:46:12 +09:00
|
|
|
foreach (var supportedExchange in CoinGeckoRateProvider.SupportedExchanges.Values)
|
2020-01-13 22:20:45 +09:00
|
|
|
{
|
2020-01-17 18:15:08 +09:00
|
|
|
if (!Providers.ContainsKey(supportedExchange.Id) && supportedExchange.Id != CoinGeckoRateProvider.CoinGeckoName)
|
2020-01-13 22:20:45 +09:00
|
|
|
{
|
2020-01-17 14:23:04 +09:00
|
|
|
var coingecko = new CoinGeckoRateProvider(_httpClientFactory)
|
2020-01-13 22:20:45 +09:00
|
|
|
{
|
2023-01-30 09:46:12 +09:00
|
|
|
UnderlyingExchange = supportedExchange.Id
|
2020-01-13 22:20:45 +09:00
|
|
|
};
|
2020-01-18 19:42:46 +09:00
|
|
|
var bgFetcher = new BackgroundFetcherRateProvider(coingecko);
|
2020-01-17 14:23:04 +09:00
|
|
|
bgFetcher.RefreshRate = TimeSpan.FromMinutes(1.0);
|
|
|
|
bgFetcher.ValidatyTime = TimeSpan.FromMinutes(5.0);
|
|
|
|
Providers.Add(supportedExchange.Id, bgFetcher);
|
2023-01-30 09:46:12 +09:00
|
|
|
var rsi = coingecko.RateSourceInfo;
|
|
|
|
AvailableRateProviders.Add(new(rsi.Id, rsi.DisplayName, rsi.Url, RateSource.Coingecko));
|
2020-01-13 22:20:45 +09:00
|
|
|
}
|
|
|
|
}
|
2023-04-10 11:07:03 +09:00
|
|
|
AvailableRateProviders.Sort((a, b) => StringComparer.Ordinal.Compare(a.DisplayName, b.DisplayName));
|
2018-05-03 03:32:42 +09:00
|
|
|
}
|
|
|
|
|
2023-01-30 09:46:12 +09:00
|
|
|
public List<AvailableRateProvider> AvailableRateProviders { get; } = new List<AvailableRateProvider>();
|
2018-05-03 03:32:42 +09:00
|
|
|
|
2019-03-05 17:09:17 +09:00
|
|
|
public async Task<QueryRateResult> QueryRates(string exchangeName, CancellationToken cancellationToken)
|
2018-04-14 22:35:52 +09:00
|
|
|
{
|
2018-08-23 00:24:33 +09:00
|
|
|
Providers.TryGetValue(exchangeName, out var directProvider);
|
|
|
|
directProvider = directProvider ?? NullRateProvider.Instance;
|
|
|
|
|
|
|
|
var wrapper = new WrapperRateProvider(directProvider);
|
2019-03-05 17:09:17 +09:00
|
|
|
var value = await wrapper.GetRatesAsync(cancellationToken);
|
2018-05-03 03:32:42 +09:00
|
|
|
return new QueryRateResult()
|
|
|
|
{
|
2020-01-17 18:11:05 +09:00
|
|
|
Exchange = exchangeName,
|
2018-08-23 00:24:33 +09:00
|
|
|
Latency = wrapper.Latency,
|
2020-01-17 18:11:05 +09:00
|
|
|
PairRates = value,
|
2018-08-23 00:24:33 +09:00
|
|
|
Exception = wrapper.Exception != null ? new ExchangeException() { Exception = wrapper.Exception, ExchangeName = exchangeName } : null
|
2018-05-03 03:32:42 +09:00
|
|
|
};
|
2018-04-14 22:35:52 +09:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|