diff --git a/Elecciones-Web/src/Elecciones.Infrastructure/Services/CurlElectoralApiService.cs b/Elecciones-Web/src/Elecciones.Infrastructure/Services/CurlElectoralApiService.cs index 5024306..3320e1e 100644 --- a/Elecciones-Web/src/Elecciones.Infrastructure/Services/CurlElectoralApiService.cs +++ b/Elecciones-Web/src/Elecciones.Infrastructure/Services/CurlElectoralApiService.cs @@ -10,99 +10,80 @@ using static Elecciones.Core.DTOs.BancaDto; namespace Elecciones.Infrastructure.Services; -// Implementación de emergencia que usa el comando 'curl' del sistema operativo public class CurlElectoralApiService : IElectoralApiService { - private readonly ILogger _logger; - private readonly IConfiguration _configuration; - private readonly string _baseUrl; + private readonly ILogger _logger; - public CurlElectoralApiService(ILogger logger, IConfiguration configuration) - { - _logger = logger; - _configuration = configuration; - _baseUrl = _configuration["ElectoralApi:BaseUrl"] ?? ""; - } - - private async Task<(int, string)> ExecuteCurlCommand(string arguments) - { - var process = new Process + public CurlElectoralApiService(ILogger logger, IConfiguration configuration) { - StartInfo = new ProcessStartInfo - { - FileName = "curl", - Arguments = arguments, - RedirectStandardOutput = true, - RedirectStandardError = true, - UseShellExecute = false, - CreateNoWindow = true, - } - }; - - process.Start(); - string output = await process.StandardOutput.ReadToEndAsync(); - string error = await process.StandardError.ReadToEndAsync(); - await process.WaitForExitAsync(); - - if (process.ExitCode != 0) - { - _logger.LogError("Error al ejecutar curl. Exit Code: {ExitCode}. Error: {Error}", process.ExitCode, error); - return (-1, error); + _logger = logger; } - // Extraemos el código de estado HTTP del final del stderr si usamos -w - // (Simplificación: asumimos 200 si el ExitCode es 0) - return (200, output); - } - - public async Task GetAuthTokenAsync() - { - // Leemos las claves simples del .env - var username = _configuration["API_USER"]; - var password = _configuration["API_PASSWORD"]; - - // Hardcodeamos la URL para estar 100% seguros - var url = "https://api.eleccionesbonaerenses.gba.gob.ar/api/createtoken"; - - // Usamos comillas simples para los headers para proteger caracteres especiales en el shell - var arguments = $"-s -H 'username: {username}' -H 'password: {password}' '{url}'"; - - var (status, output) = await ExecuteCurlCommand(arguments); - - // Si el ExitCode no es 0, la respuesta de curl es un error, no el cuerpo de la página. - if (status != 200) + private async Task<(int, string)> ExecuteCurlCommand(string arguments) { - _logger.LogError("Curl falló al ejecutar el comando. Salida de error: {Output}", output); - return null; + var processInfo = new ProcessStartInfo("curl", arguments) + { + RedirectStandardOutput = true, + RedirectStandardError = true, + UseShellExecute = false, + CreateNoWindow = true, + }; + + using var process = Process.Start(processInfo); + if (process == null) return (-1, "No se pudo iniciar el proceso curl."); + + string output = await process.StandardOutput.ReadToEndAsync(); + string error = await process.StandardError.ReadToEndAsync(); + await process.WaitForExitAsync(); + + if (process.ExitCode != 0) + { + _logger.LogError("Error al ejecutar curl. Exit Code: {ExitCode}. Stderr: {Error}", process.ExitCode, error); + return (process.ExitCode, error.Length > 0 ? error : output); + } + return (200, output); } - try + public async Task GetAuthTokenAsync() { - // Añadimos opciones para ser más flexibles con el JSON que venga - var jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; - var tokenResponse = JsonSerializer.Deserialize(output, jsonOptions); + // --- CREDENCIALES Y URL HARDCODEADAS --- + var username = "30500094156@elecciones2025.onmicrosoft.com"; + var password = "PTP847elec"; + var url = "https://api.eleccionesbonaerenses.gba.gob.ar/api/createtoken"; - // Log de éxito - _logger.LogInformation("Token obtenido exitosamente!"); - return tokenResponse?.Data?.AccessToken; - } - catch (JsonException ex) - { - _logger.LogError(ex, "Falló la deserialización del JSON. El servidor respondió con HTML (probablemente un error). Respuesta recibida: {Output}", output); - return null; - } - } + // --- FORMATO DE ARGUMENTOS CORREGIDO (SIN ESPACIOS) --- + var arguments = $"-s -H \"username:{username}\" -H \"password:{password}\" \"{url}\""; + + _logger.LogInformation("Ejecutando comando curl con argumentos: {Arguments}", arguments); - // Implementa los demás métodos de la interfaz usando el mismo patrón - // ... - // Por ahora, solo necesitamos GetAuthTokenAsync para validar la conexión. - public Task?> GetCategoriasAsync(string authToken) => Task.FromResult?>(null); - public Task?> GetCatalogoCompletoAsync(string authToken) => Task.FromResult?>(null); - public Task?> GetAgrupacionesAsync(string authToken, string distritoId, int categoriaId) => Task.FromResult?>(null); - public Task GetResultadosAsync(string authToken, string distritoId, string seccionId, string municipioId) => Task.FromResult(null); - public Task GetBancasAsync(string authToken, string distritoId, string seccionId) => Task.FromResult(null); - public Task?> GetTelegramasTotalizadosAsync(string authToken, string distritoId, string seccionId) => Task.FromResult?>(null); - public Task GetTelegramaFileAsync(string authToken, string mesaId) => Task.FromResult(null); - public Task GetResumenAsync(string authToken, string distritoId) => Task.FromResult(null); - public Task GetEstadoRecuentoGeneralAsync(string authToken, string distritoId) => Task.FromResult(null); + var (status, output) = await ExecuteCurlCommand(arguments); + + if (status != 200) { + _logger.LogError("Curl falló al obtener el token. Salida recibida: {Output}", output); + return null; + } + + try { + var jsonOptions = new JsonSerializerOptions { PropertyNameCaseInsensitive = true }; + var tokenResponse = JsonSerializer.Deserialize(output, jsonOptions); + + _logger.LogInformation("¡VICTORIA! Token obtenido exitosamente. La sincronización debería comenzar."); + return tokenResponse?.Data?.AccessToken; + } catch (JsonException ex) { + _logger.LogError(ex, "Falló la deserialización del JSON. El servidor respondió con un error HTML. Respuesta recibida: {Output}", output); + return null; + } + } + + // --- El resto de los métodos se mantienen igual (no se usarán en este primer paso) --- + public async Task?> GetCategoriasAsync(string authToken) { _logger.LogInformation("Obteniendo categorías..."); /* Aquí iría la lógica de curl */ await Task.Delay(1); return null; } + // ... (copia y pega el resto de los métodos vacíos que ya tenías) + public Task?> GetCatalogoCompletoAsync(string authToken) => Task.FromResult?>(null); + public Task?> GetAgrupacionesAsync(string authToken, string distritoId, int categoriaId) => Task.FromResult?>(null); + public Task GetResultadosAsync(string authToken, string distritoId, string seccionId, string municipioId) => Task.FromResult(null); + public Task GetBancasAsync(string authToken, string distritoId, string seccionId) => Task.FromResult(null); + public Task?> GetTelegramasTotalizadosAsync(string authToken, string distritoId, string seccionId) => Task.FromResult?>(null); + public Task GetTelegramaFileAsync(string authToken, string mesaId) => Task.FromResult(null); + public Task GetResumenAsync(string authToken, string distritoId) => Task.FromResult(null); + public Task GetEstadoRecuentoGeneralAsync(string authToken, string distritoId) => Task.FromResult(null); } \ No newline at end of file