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