daily_digest/Services/CoinGeckoCryptoService.cs
2025-04-12 00:27:03 +07:00

97 lines
4.4 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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;
}
}
}
}