daily_digest/Services/CoinGeckoCryptoService.cs

97 lines
4.4 KiB
C#
Raw Permalink Normal View History

using DailyDigestWorker.Configuration; // Для DataSourceUrls
using DailyDigestWorker.Models;
using Microsoft.Extensions.Options; // Для IOptions
using Newtonsoft.Json; // Для JsonConvert (или System.Text.Json)
using Newtonsoft.Json.Linq; // Для JObject, если парсить вручную
namespace DailyDigestWorker.Services
{
public class CoinGeckoCryptoService : ICryptoService // Реализуем интерфейс
{
private readonly IHttpClientFactory _httpClientFactory;
private readonly ILogger<CoinGeckoCryptoService> _logger;
private readonly DataSourceUrls _dataSourceUrls;
// Внедряем зависимости
public CoinGeckoCryptoService(
IHttpClientFactory httpClientFactory,
IOptions<DataSourceUrls> dataSourceUrlsOptions,
ILogger<CoinGeckoCryptoService> logger)
{
_httpClientFactory = httpClientFactory;
_logger = logger;
_dataSourceUrls = dataSourceUrlsOptions.Value; // Получаем URL из настроек
}
public async Task<CryptoData?> GetCryptoRatesAsync(CancellationToken cancellationToken)
{
_logger.LogInformation("Запрос курсов криптовалют с API CoinGecko...");
var client = _httpClientFactory.CreateClient();
try
{
HttpResponseMessage response = await client.GetAsync(_dataSourceUrls.CoinGecko, cancellationToken);
if (!response.IsSuccessStatusCode)
{
_logger.LogError("Ошибка при запросе к API CoinGecko. Статус код: {StatusCode}", response.StatusCode);
return null;
}
// Читаем ответ как строку
string jsonResponse = await response.Content.ReadAsStringAsync(cancellationToken);
// Десериализуем JSON
// CoinGecko API возвращает структуру типа: {"bitcoin": {"usd": 60000, "rub": 5000000}, "ethereum": {...}}
// Мы можем десериализовать это прямо в наш тип словаря.
var rates = JsonConvert.DeserializeObject<Dictionary<string, Dictionary<string, decimal>>>(jsonResponse);
if (rates == null || rates.Count == 0)
{
_logger.LogWarning("Не удалось десериализовать ответ от CoinGecko или он пуст.");
return null;
}
_logger.LogInformation("Курсы криптовалют успешно получены из CoinGecko.");
// Создаем и возвращаем результат
var resultData = new CryptoData();
foreach (var cryptoPair in rates)
{
resultData.CryptoRates.Add(cryptoPair.Key, cryptoPair.Value);
}
// Логгируем полученные значения для проверки (опционально)
foreach (var crypto in resultData.CryptoRates)
{
foreach (var currencyRate in crypto.Value)
{
_logger.LogDebug(" - {CryptoId} [{Currency}]: {Rate}", crypto.Key, currencyRate.Key.ToUpper(), currencyRate.Value);
}
}
return resultData;
}
catch (HttpRequestException ex)
{
_logger.LogError(ex, "Ошибка HTTP при запросе к API CoinGecko.");
return null;
}
catch (JsonException ex) // Ловим ошибки десериализации JSON
{
_logger.LogError(ex, "Ошибка парсинга JSON ответа CoinGecko.");
return null;
}
catch (OperationCanceledException)
{
_logger.LogInformation("Запрос курсов криптовалют был отменен.");
return null;
}
catch (Exception ex)
{
_logger.LogError(ex, "Неожиданная ошибка при получении курсов криптовалют CoinGecko.");
return null;
}
}
}
}