Compare commits
	
		
			2 Commits
		
	
	
		
			9d5c2086c5
			...
			7e1e487e83
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
| 7e1e487e83 | |||
| 3d685fba1e | 
| @@ -29,7 +29,7 @@ public class ElectoralApiService : IElectoralApiService | ||||
|         _rateLimiter = rateLimiter; | ||||
|     } | ||||
|  | ||||
|     public async Task<string?> GetAuthTokenAsync() | ||||
|     public async Task<TokenResponse?> GetAuthTokenAsync() | ||||
|     { | ||||
|         // "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. | ||||
| @@ -42,14 +42,18 @@ public class ElectoralApiService : IElectoralApiService | ||||
|             var username = _configuration["ElectoralApi:Username"]; | ||||
|             var password = _configuration["ElectoralApi:Password"]; | ||||
|             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("password", password); | ||||
|  | ||||
|             var response = await client.SendAsync(request); | ||||
|             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. | ||||
|         return null; | ||||
|     } | ||||
|   | ||||
| @@ -7,8 +7,7 @@ namespace Elecciones.Infrastructure.Services; | ||||
|  | ||||
| public interface IElectoralApiService | ||||
| { | ||||
|     Task<string?> GetAuthTokenAsync(); | ||||
|  | ||||
|     Task<TokenResponse?> GetAuthTokenAsync(); | ||||
|     // Métodos para catálogos | ||||
|     Task<CatalogoDto?> GetCatalogoAmbitosAsync(string authToken, 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 IElectoralApiService _apiService; | ||||
|     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) | ||||
|     { | ||||
| @@ -28,6 +32,36 @@ public class Worker : BackgroundService | ||||
|         _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> | ||||
|     /// Método principal del worker que se ejecuta en segundo plano. | ||||
|     /// </summary> | ||||
| @@ -48,10 +82,11 @@ public class Worker : BackgroundService | ||||
|             var cicloInicio = DateTime.UtcNow; | ||||
|             cicloContador++; | ||||
|  | ||||
|             var authToken = await _apiService.GetAuthTokenAsync(); | ||||
|             var authToken = await GetValidAuthTokenAsync(stoppingToken); | ||||
|  | ||||
|             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); | ||||
|                 continue; | ||||
|             } | ||||
| @@ -112,8 +147,8 @@ public class Worker : BackgroundService | ||||
|         { | ||||
|             _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 _apiService.GetAuthTokenAsync(); | ||||
|             var authToken = await GetValidAuthTokenAsync(stoppingToken); | ||||
|  | ||||
|             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."); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user