Compare commits

..

2 Commits

Author SHA1 Message Date
7e1e487e83 Fix Solicitud de Token 2 2025-08-20 15:03:19 -03:00
3d685fba1e Fix Solicitud de Token 2025-08-20 15:03:02 -03:00
3 changed files with 48 additions and 10 deletions

View File

@@ -29,7 +29,7 @@ public class ElectoralApiService : IElectoralApiService
_rateLimiter = rateLimiter; _rateLimiter = rateLimiter;
} }
public async Task<string?> GetAuthTokenAsync() public async Task<TokenResponse?> GetAuthTokenAsync()
{ {
// "Pedir una ficha". Este método ahora devuelve un "lease" (permiso). // "Pedir una ficha". Este método ahora devuelve un "lease" (permiso).
// Si no hay fichas, esperará aquí automáticamente hasta que se rellene el cubo. // Si no hay fichas, esperará aquí automáticamente hasta que se rellene el cubo.
@@ -42,14 +42,18 @@ public class ElectoralApiService : IElectoralApiService
var username = _configuration["ElectoralApi:Username"]; var username = _configuration["ElectoralApi:Username"];
var password = _configuration["ElectoralApi:Password"]; var password = _configuration["ElectoralApi:Password"];
if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) return null; if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) return null;
var request = new HttpRequestMessage(HttpMethod.Get, "/api/createtoken/");
var request = new HttpRequestMessage(HttpMethod.Get, "/api/createtoken");
request.Headers.Add("username", username); request.Headers.Add("username", username);
request.Headers.Add("password", password); request.Headers.Add("password", password);
var response = await client.SendAsync(request); var response = await client.SendAsync(request);
if (!response.IsSuccessStatusCode) return null; if (!response.IsSuccessStatusCode) return null;
var tokenResponse = await response.Content.ReadFromJsonAsync<TokenResponse>();
return (tokenResponse is { Success: true, Data.AccessToken: not null }) ? tokenResponse.Data.AccessToken : null; // Ahora esto es válido, porque el método devuelve Task<TokenResponse?>
return await response.Content.ReadFromJsonAsync<TokenResponse>();
} }
// Si no se pudo obtener un permiso (ej. la cola está llena), devolvemos null. // Si no se pudo obtener un permiso (ej. la cola está llena), devolvemos null.
return null; return null;
} }

View File

@@ -7,8 +7,7 @@ namespace Elecciones.Infrastructure.Services;
public interface IElectoralApiService public interface IElectoralApiService
{ {
Task<string?> GetAuthTokenAsync(); Task<TokenResponse?> GetAuthTokenAsync();
// Métodos para catálogos // Métodos para catálogos
Task<CatalogoDto?> GetCatalogoAmbitosAsync(string authToken, int categoriaId); Task<CatalogoDto?> GetCatalogoAmbitosAsync(string authToken, int categoriaId);
Task<List<AgrupacionDto>?> GetAgrupacionesAsync(string authToken, string distritoId, int categoriaId); Task<List<AgrupacionDto>?> GetAgrupacionesAsync(string authToken, string distritoId, int categoriaId);

View File

@@ -20,6 +20,10 @@ public class Worker : BackgroundService
private readonly ILogger<Worker> _logger; private readonly ILogger<Worker> _logger;
private readonly IElectoralApiService _apiService; private readonly IElectoralApiService _apiService;
private readonly IServiceProvider _serviceProvider; private readonly IServiceProvider _serviceProvider;
// --- VARIABLES DE ESTADO PARA EL TOKEN ---
private string? _authToken;
// Usamos DateTimeOffset para manejar correctamente las zonas horarias.
private DateTimeOffset _tokenExpiration = DateTimeOffset.MinValue;
public Worker(ILogger<Worker> logger, IElectoralApiService apiService, IServiceProvider serviceProvider) public Worker(ILogger<Worker> logger, IElectoralApiService apiService, IServiceProvider serviceProvider)
{ {
@@ -28,6 +32,36 @@ public class Worker : BackgroundService
_serviceProvider = serviceProvider; _serviceProvider = serviceProvider;
} }
/// <summary>
/// Obtiene un token de autenticación válido, solicitando uno nuevo solo si el actual
/// no existe o ha expirado.
/// </summary>
private async Task<string?> GetValidAuthTokenAsync(CancellationToken stoppingToken)
{
// Comprobamos si el token es nulo o si la fecha de expiración ya pasó.
// Añadimos un buffer de seguridad de 1 minuto para renovarlo un poco antes.
if (string.IsNullOrEmpty(_authToken) || DateTimeOffset.UtcNow >= _tokenExpiration.AddMinutes(-1))
{
_logger.LogInformation("Token no válido o a punto de expirar. Solicitando uno nuevo...");
var tokenResponse = await _apiService.GetAuthTokenAsync(); // Asumimos que el ApiService devuelve el objeto completo
if (tokenResponse?.Data?.AccessToken != null)
{
_authToken = tokenResponse.Data.AccessToken;
// Calculamos la nueva fecha de expiración. La API nos da la duración en segundos.
_tokenExpiration = DateTimeOffset.UtcNow.AddSeconds(tokenResponse.Data.ExpiresIn);
_logger.LogInformation("Nuevo token obtenido. Válido hasta: {expiration}", _tokenExpiration);
}
else
{
_logger.LogError("CRÍTICO: No se pudo obtener un nuevo token de autenticación.");
_authToken = null; // Nos aseguramos de que el token viejo se invalide
}
}
return _authToken;
}
/// <summary> /// <summary>
/// Método principal del worker que se ejecuta en segundo plano. /// Método principal del worker que se ejecuta en segundo plano.
/// </summary> /// </summary>
@@ -48,10 +82,11 @@ public class Worker : BackgroundService
var cicloInicio = DateTime.UtcNow; var cicloInicio = DateTime.UtcNow;
cicloContador++; cicloContador++;
var authToken = await _apiService.GetAuthTokenAsync(); var authToken = await GetValidAuthTokenAsync(stoppingToken);
if (string.IsNullOrEmpty(authToken)) if (string.IsNullOrEmpty(authToken))
{ {
_logger.LogError("CRÍTICO: No se pudo obtener el token. Reintentando en 1 minuto..."); _logger.LogError("No se pudo obtener un token válido. Reintentando en 1 minuto...");
await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken); await Task.Delay(TimeSpan.FromMinutes(1), stoppingToken);
continue; continue;
} }
@@ -112,8 +147,8 @@ public class Worker : BackgroundService
{ {
_logger.LogInformation("Iniciando sincronización de catálogos maestros..."); _logger.LogInformation("Iniciando sincronización de catálogos maestros...");
// PASO 1: Obtener el token de autenticación. Sin él, no podemos hacer nada. var authToken = await GetValidAuthTokenAsync(stoppingToken);
var authToken = await _apiService.GetAuthTokenAsync();
if (string.IsNullOrEmpty(authToken) || stoppingToken.IsCancellationRequested) if (string.IsNullOrEmpty(authToken) || stoppingToken.IsCancellationRequested)
{ {
_logger.LogError("No se pudo obtener token para la sincronización de catálogos. La operación se cancela."); _logger.LogError("No se pudo obtener token para la sincronización de catálogos. La operación se cancela.");