Compare commits
2 Commits
9d5c2086c5
...
7e1e487e83
| Author | SHA1 | Date | |
|---|---|---|---|
| 7e1e487e83 | |||
| 3d685fba1e |
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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.");
|
||||||
|
|||||||
Reference in New Issue
Block a user