2020-06-28 21:44:35 -05:00
|
|
|
using System;
|
2018-08-21 15:59:57 +09:00
|
|
|
using System.Collections.Concurrent;
|
2018-05-04 15:35:39 +09:00
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
2020-01-18 21:48:04 +09:00
|
|
|
using System.Net.Http;
|
2019-03-05 17:09:17 +09:00
|
|
|
using System.Threading;
|
2018-05-04 15:35:39 +09:00
|
|
|
using System.Threading.Tasks;
|
|
|
|
using BTCPayServer.Rating;
|
|
|
|
using ExchangeSharp;
|
|
|
|
|
|
|
|
namespace BTCPayServer.Services.Rates
|
|
|
|
{
|
2022-06-06 11:56:50 +02:00
|
|
|
public class ExchangeSharpRateProvider<T> : IRateProvider where T : ExchangeAPI
|
2018-05-04 15:35:39 +09:00
|
|
|
{
|
2020-06-28 22:07:48 -05:00
|
|
|
readonly HttpClient _httpClient;
|
2022-06-06 11:56:50 +02:00
|
|
|
public ExchangeSharpRateProvider(HttpClient httpClient)
|
2018-05-04 15:35:39 +09:00
|
|
|
{
|
2021-12-28 17:39:54 +09:00
|
|
|
ArgumentNullException.ThrowIfNull(httpClient);
|
2020-01-18 21:48:04 +09:00
|
|
|
_httpClient = httpClient;
|
2018-05-04 15:35:39 +09:00
|
|
|
}
|
|
|
|
|
2020-01-17 18:11:05 +09:00
|
|
|
public async Task<PairRate[]> GetRatesAsync(CancellationToken cancellationToken)
|
2018-05-04 15:35:39 +09:00
|
|
|
{
|
|
|
|
await new SynchronizationContextRemover();
|
2019-11-11 07:14:29 +01:00
|
|
|
|
2023-01-06 14:18:07 +01:00
|
|
|
var exchangeAPI = (T)await ExchangeAPI.GetExchangeAPIAsync<T>();
|
2020-01-18 21:48:04 +09:00
|
|
|
exchangeAPI.RequestMaker = new HttpClientRequestMaker(exchangeAPI, _httpClient, cancellationToken);
|
|
|
|
var rates = await exchangeAPI.GetTickersAsync();
|
|
|
|
|
|
|
|
var exchangeRateTasks = rates
|
|
|
|
.Where(t => t.Value.Ask != 0m && t.Value.Bid != 0m)
|
|
|
|
.Select(t => CreateExchangeRate(exchangeAPI, t));
|
|
|
|
|
|
|
|
var exchangeRates = await Task.WhenAll(exchangeRateTasks);
|
2019-11-11 07:14:29 +01:00
|
|
|
|
2020-01-17 18:11:05 +09:00
|
|
|
return exchangeRates
|
2019-11-11 07:14:29 +01:00
|
|
|
.Where(t => t != null)
|
2020-01-17 18:11:05 +09:00
|
|
|
.ToArray();
|
2018-05-04 15:35:39 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
// ExchangeSymbolToGlobalSymbol throws exception which would kill perf
|
2020-06-28 22:07:48 -05:00
|
|
|
readonly ConcurrentDictionary<string, string> notFoundSymbols = new ConcurrentDictionary<string, string>();
|
2023-01-30 09:46:12 +09:00
|
|
|
|
|
|
|
public RateSourceInfo RateSourceInfo { get; set; }
|
|
|
|
|
2020-01-18 21:48:04 +09:00
|
|
|
private async Task<PairRate> CreateExchangeRate(T exchangeAPI, KeyValuePair<string, ExchangeTicker> ticker)
|
2018-05-04 15:35:39 +09:00
|
|
|
{
|
2019-11-11 07:14:29 +01:00
|
|
|
if (notFoundSymbols.TryGetValue(ticker.Key, out _))
|
2018-05-04 15:35:39 +09:00
|
|
|
return null;
|
|
|
|
try
|
|
|
|
{
|
2022-06-06 11:56:50 +02:00
|
|
|
CurrencyPair pair;
|
|
|
|
if (ticker.Value.Volume.BaseCurrency is not null && ticker.Value.Volume.QuoteCurrency is not null)
|
|
|
|
{
|
|
|
|
pair = new CurrencyPair(ticker.Value.Volume.BaseCurrency, ticker.Value.Volume.QuoteCurrency);
|
|
|
|
}
|
|
|
|
else
|
2018-05-04 15:35:39 +09:00
|
|
|
{
|
2022-06-06 11:56:50 +02:00
|
|
|
var tickerName = await exchangeAPI.ExchangeMarketSymbolToGlobalMarketSymbolAsync(ticker.Key);
|
|
|
|
if (!CurrencyPair.TryParse(tickerName, out pair))
|
|
|
|
{
|
|
|
|
notFoundSymbols.TryAdd(ticker.Key, ticker.Key);
|
|
|
|
return null;
|
|
|
|
}
|
2018-05-04 15:35:39 +09:00
|
|
|
}
|
2020-01-17 18:11:05 +09:00
|
|
|
return new PairRate(pair, new BidAsk(ticker.Value.Bid, ticker.Value.Ask));
|
2018-05-04 15:35:39 +09:00
|
|
|
}
|
|
|
|
catch (ArgumentException)
|
|
|
|
{
|
2018-08-21 15:59:57 +09:00
|
|
|
notFoundSymbols.TryAdd(ticker.Key, ticker.Key);
|
2018-05-04 15:35:39 +09:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|