using RoboSharp; using System.Diagnostics; using System.Runtime.InteropServices; using System.Drawing.Drawing2D; using System.Net.NetworkInformation; using System.Text; namespace UpdateIETPX { public partial class Form1 : Form { #region Modo Oscuro [DllImport("dwmapi.dll")] private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize); private const int DWMWA_USE_IMMERSIVE_DARK_MODE = 20; #endregion #region Campos privados private readonly OperacionesRed _operacionesRed; private readonly Tareas _tareas; private EstadoProceso _estadoActual = EstadoProceso.Idle; //Token de cancelación para el monitoreo private CancellationTokenSource _ctsMonitoreo; //Timer con Windows Forms (se ejecutan en el hilo de la interfaz de usuario) private System.Windows.Forms.Timer _timerVPN; private System.Windows.Forms.Timer _timerMapeo; private System.Windows.Forms.Timer _timerInternet; //Robocopy private RoboCommand _roboCommand; //Para cancelar operaciones asíncronas private CancellationTokenSource _cancellationTokenSource; #endregion #region Constructor y métodos de inicialización public Form1() { InitializeComponent(); //Inicializar las variables _operacionesRed = new OperacionesRed(); _tareas = new Tareas(); Logger.Info($"Aplicación iniciada - Equipo: '{Environment.MachineName}' Usuario: '{Environment.UserName}'"); //Vincular eventos del menú lateral VincularEventosMenu(); //Configurar timers y formulario //ConfigurarTimers(); ConfigurarFormulario(); ConfigurarFormularioLogs(); //Iniciar monitoreo de conexiones IniciarMonitoreo(); } //Funcion para vincular eventos a los paneles del menú lateral private void VincularEventosMenu() { VincularEventosAlPanel(panelMenuHome, lblHome); VincularEventosAlPanel(panelMenuLogs, lblLogs); VincularEventosAlPanel(panelMenuInfo, lblInfo); VincularEventosAlPanel(panelMenuSettings, lblSettings); } //Funcion para vincular eventos a un panel y su label asociada private void VincularEventosAlPanel(Panel panel, Label label) { panel.Tag = label; //Eventos del panel panel.MouseEnter += PanelMenu_MouseEnter; panel.MouseLeave += PanelMenu_MouseLeave; panel.Click += PanelLateral_Click; //Eventos de los hijos del panel foreach (Control control in panel.Controls) { control.Tag = panel; control.MouseEnter +=Hijo_MouseEnter; control.MouseLeave += Hijo_MouseLeave; control.Click += PanelLateral_Click; } } //Configuración inicial del formulario private void ConfigurarFormulario() { //Modo oscuro si es posible int useDarkMode = 1; DwmSetWindowAttribute(this.Handle, DWMWA_USE_IMMERSIVE_DARK_MODE, ref useDarkMode, sizeof(int)); //Configuracion inicial del formulario lblCopiando.Visible = false; btnCancel.Enabled = false; //Tooltip para indicadores var toolTip = new ToolTip(); toolTip.SetToolTip(lblVPN1, "Estado de la conexion VPN"); toolTip.SetToolTip(pbNAS, "Estado de mapeo NAS"); //Mostrar la vista Home por defecto MostrarVistaHome(); //Configurar la guía de usuario ConfigurarGuiaBurros(); //Redondear botones (de momento lo quito porque no me gusta nada) //RedondearBoton(btnActualizar, 20); //RedondearBoton(btnFlysmart, 20); } private void ConfigurarFormularioLogs() { //Configurar la ruta de logs tboxRutaLogs.Text = AppConfig.RUTA_LOG_PRINCIPAL; //Configurar el RichTextBox de logs rtxtboxLogs.ReadOnly = true; rtxtboxLogs.BackColor = Color.FromArgb(32, 32, 32); rtxtboxLogs.ForeColor = Color.White; //Suscribirse al evento de logs Logger.OnLogRegistrado += MostrarLogEnRichTextBox; } //Función para configurar los timers private void ConfigurarTimers() { //Timer para VPN (2 segundos) _timerVPN = new System.Windows.Forms.Timer { Interval = 2000, Enabled = true }; _timerVPN.Tick += ManejarEventoTiempoVPN; //Timer para mapeo (2 segundos) _timerMapeo = new System.Windows.Forms.Timer { Interval = 2000, Enabled = true }; _timerMapeo.Tick += ManejarEventoTiempoMapeo; //Timer para internet (5 segundos) _timerInternet = new System.Windows.Forms.Timer { Interval = 5000, Enabled = true }; _timerInternet.Tick += ManejarEventoTiempoInternet; } private void ActualizarPanelSettings() { try { StringBuilder info = new StringBuilder(); // INFORMACIÓN DEL EQUIPO info.AppendLine("INFORMACIÓN DEL EQUIPO"); info.AppendLine("═════════════════════════════════════════"); info.AppendLine($"Equipo: {Environment.MachineName}"); info.AppendLine($"Usuario: {Environment.UserName}"); info.AppendLine($"SO: {GetNombreWindows()}"); info.AppendLine($"Versión .NET: 8.0"); info.AppendLine($"Hora del sistema: {DateTime.Now:dd/MM/yyyy HH:mm:ss}"); info.AppendLine(); // ÚLTIMA ACTUALIZACIÓN info.AppendLine("ÚLTIMA ACTUALIZACIÓN"); info.AppendLine("═════════════════════════════════════════"); string ultimaActualizacion = ObtenerUltimaActualizacion(); info.AppendLine(!string.IsNullOrEmpty(ultimaActualizacion) ? ultimaActualizacion : "Sin actualizaciones registradas"); info.AppendLine(); // ESTADO DE CONEXIONES info.AppendLine("ESTADO DE CONEXIONES"); info.AppendLine("═════════════════════════════════════════"); bool vpnConectada = Checker.EstaConectadoVPN(); bool nasConectado = Checker.EstaMapeada(AppConfig.NAS_RUTA_LOCAL); bool internetDisponible = NetworkInterface.GetIsNetworkAvailable(); info.AppendLine($"VPN: {(vpnConectada ? "✓ CONECTADA" : "✗ DESCONECTADA")}"); info.AppendLine($"NAS: {(nasConectado ? "✓ CONECTADO" : "✗ DESCONECTADO")}"); info.AppendLine($"Internet: {(internetDisponible ? "✓ DISPONIBLE" : "✗ NO DISPONIBLE")}"); info.AppendLine(); // RUTAS CONFIGURADAS info.AppendLine("RUTAS CONFIGURADAS"); info.AppendLine("═════════════════════════════════════════"); info.AppendLine($"NAS (Local): {AppConfig.NAS_RUTA_LOCAL}"); info.AppendLine($"IETPX (Destino): {AppConfig.RUTA_DESTINO_IETPX}"); info.AppendLine($"FlySmart (Local): {AppConfig.FLYSMART_RUTA_LOCAL}"); info.AppendLine($"Logs: {AppConfig.RUTA_LOG_PRINCIPAL}"); info.AppendLine(); rtxtboxINFO.Text = info.ToString(); rtxtboxINFO.ReadOnly = true; rtxtboxINFO.BackColor = Color.FromArgb(32, 32, 32); rtxtboxINFO.ForeColor = Color.White; } catch (Exception ex) { Logger.Error($"Error al actualizar panel INFO: {ex.Message}", ex); } } private string GetNombreWindows() { try { var osVersion = Environment.OSVersion; if (osVersion.Platform == PlatformID.Win32NT) { if (osVersion.Version.Major == 10) { if (osVersion.Version.Build >= 22000) return "Windows 11"; return "Windows 10"; } else if (osVersion.Version.Major == 6) { if (osVersion.Version.Minor == 3) return "Windows 8.1"; if (osVersion.Version.Minor == 2) return "Windows 8"; if (osVersion.Version.Minor == 1) return "Windows 7"; } } return $"Windows {osVersion.VersionString}"; } catch { return "Windows (versión desconocida)"; } } private string ObtenerUltimaActualizacion() { try { string rutaRegistro = AppConfig.RUTA_REGISTRO_ACTUALIZACION; if (!File.Exists(rutaRegistro)) return string.Empty; var lineas = File.ReadAllLines(rutaRegistro); if (lineas.Length <= 1) return string.Empty; string ultimaLinea = lineas[lineas.Length - 1]; var campos = ultimaLinea.Split(','); if (campos.Length >= 5) { string equipo = campos[0].Trim(); string usuario = campos[1].Trim(); string fechaHora = campos[2].Trim(); string resultado = campos[4].Trim(); return $"Equipo: {equipo}\nUsuario: {usuario}\nFecha: {fechaHora}\nResultado: {resultado}"; } } catch (Exception ex) { Logger.Error($"Error al obtener última actualización: {ex.Message}", ex); } return string.Empty; } private void ConfigurarGuiaBurros() { try { StringBuilder guia = new StringBuilder(); guia.AppendLine("═══════════════════════════════════════════════════════"); guia.AppendLine(" PASOS PARA ACTUALIZAR:"); guia.AppendLine(); guia.AppendLine(" 1. Inicie la actualización pulsando el botón correspondiente."); guia.AppendLine(" 2. Compruebe que los 3 indicadores estén en verde."); guia.AppendLine(" 3. Espere a que el proceso termine."); guia.AppendLine(); guia.AppendLine("═══════════════════════════════════════════════════════"); guia.AppendLine(" REQUISITOS PARA ACTUALIZAR:"); guia.AppendLine(); guia.AppendLine(" Los 3 indicadores deben estar en VERDE:"); guia.AppendLine(" • VPN: Conectada"); guia.AppendLine(" • NAS: Conectado"); guia.AppendLine(" • Internet: Conectado"); guia.AppendLine(); guia.AppendLine("═══════════════════════════════════════════════════════"); guia.AppendLine(); guia.AppendLine(" SOLUCIÓN DE PROBLEMAS:"); guia.AppendLine(); guia.AppendLine(" • Si algo falla durante la actualización:"); guia.AppendLine(" → Ve a la pestaña 'LOGS' para ver detalles"); guia.AppendLine(); guia.AppendLine(" • Si se requiere hacer la conexión manual:"); guia.AppendLine(" → Primero conectar VPN"); guia.AppendLine(" → Después mapear NAS"); guia.AppendLine(); guia.AppendLine(" • Si un indicador está en rojo:"); guia.AppendLine(" → VPN: Verifica tu conexión de red"); guia.AppendLine(" → NAS: Usa el botón 'MAPEAR' si es necesario"); guia.AppendLine(" → Internet: Revisa tu conexión WiFi/Ethernet"); guia.AppendLine(); guia.AppendLine("═══════════════════════════════════════════════════════"); guia.AppendLine(); guia.AppendLine(" CONSEJOS:"); guia.AppendLine(); guia.AppendLine(" • No cierres la aplicación durante la copia"); guia.AppendLine(" • Puedes cancelar con el botón 'CANCELAR'"); guia.AppendLine(); guia.AppendLine("═══════════════════════════════════════════════════════"); // Configurar el RichTextBox guiaBurros.Text = guia.ToString(); guiaBurros.Font = new Font("Segoe UI", 9, FontStyle.Regular); } catch (Exception ex) { Logger.Error($"Error al configurar guía de usuario: {ex.Message}", ex); } } private void MostrarLogEnRichTextBox(string tipo, string mensaje) { if (rtxtboxLogs.InvokeRequired) { rtxtboxLogs.Invoke(() => MostrarLogEnRichTextBox(tipo, mensaje)); return; } try { string linea = $"{DateTime.Now:HH:mm:ss} [{tipo}] {mensaje}\n"; rtxtboxLogs.AppendText(linea); // Asignar color según tipo int inicio = rtxtboxLogs.TextLength - linea.Length; int longitud = linea.Length; rtxtboxLogs.Select(inicio, longitud); switch (tipo) { case "INFO": rtxtboxLogs.SelectionColor = Color.White; break; case "ERROR": rtxtboxLogs.SelectionColor = Color.Red; break; case "WARNING": rtxtboxLogs.SelectionColor = Color.Orange; break; case "DEBUG": rtxtboxLogs.SelectionColor = Color.Gray; break; default: rtxtboxLogs.SelectionColor = Color.White; break; } // Scroll hacia abajo rtxtboxLogs.Select(rtxtboxLogs.TextLength, 0); rtxtboxLogs.ScrollToCaret(); } catch (Exception ex) { // Silenciar errores para evitar bucles System.Diagnostics.Debug.WriteLine($"Error al mostrar log: {ex.Message}"); } } #endregion #region Metodos compartidos de conexión private async Task ConectarVPNAsync(CancellationToken token) { Logger.Info("Verificando conexión VPN..."); token.ThrowIfCancellationRequested(); var (exito, mensaje) = await _operacionesRed.ConectarVPNAsync(); if (!exito) { Logger.Error($"Error VPN: {mensaje}"); MessageBox.Show($"No se pudo conectar a la VPN. \n\n{mensaje}", "Error de conexión VPN", MessageBoxButtons.OK, MessageBoxIcon.Error); return false; } Logger.Info("VPN conectada correctamente"); return true; } private async Task ConectarNASAsync(CancellationToken token) { Logger.Info("Conectando al NAS..."); token.ThrowIfCancellationRequested(); var (exito, _) = await _operacionesRed.ConectarNASAsync(); return exito; } private async Task ConectarFlySmartAsync() { Logger.Info("Conectando FlySmart..."); var (exito, _) = await _operacionesRed.ConectarFlySmartAsync(); return exito; } private async Task VerificarMapeoAsync(CancellationToken token) { Logger.Info("Verificando mapeo del NAS..."); token.ThrowIfCancellationRequested(); return await Checker.EsperarMapeoAsync(AppConfig.NAS_RUTA_LOCAL, AppConfig.MAX_INTENTOS_MAPEO); } private async Task VerificarFlySmartAsync() { Logger.Info("Verificando mapeo de FlySmart..."); return await Checker.EsperarMapeoAsync(AppConfig.FLYSMART_RUTA_LOCAL, AppConfig.MAX_INTENTOS_MAPEO); } private async Task EjecutarActualizacionAsync() { Logger.Info("Iniciando copia RoboCopy..."); _roboCommand = _tareas.CrearComandoRoboCopy( AppConfig.NAS_RUTA_LOCAL, AppConfig.RUTA_DESTINO_IETPX, AppConfig.RUTA_LOG_ROBOCOPY, progressBar1, lblCopiando); await _roboCommand.StartAsync(); } private async Task EjecutarActualizacionFlySmartAsync() { Logger.Info("Iniciando copia RoboCopy..."); _roboCommand = _tareas.CrearComandoRoboCopy( AppConfig.FLYSMART_RUTA_LOCAL, AppConfig.RUTA_DESTINO_FLYSMART, AppConfig.RUTA_LOG_ROBOCOPY, progressBar1, lblCopiando); await _roboCommand.StartAsync(); } #endregion #region Actualización IETPX private async void btnActualizar_Click(object sender, EventArgs e) { Logger.Info("Usuario presionó: ACTUALIZAR IETPX"); ActualizarUI(EstadoProceso.Ejecutando); //Preparar la cancelación _cancellationTokenSource?.Dispose(); _cancellationTokenSource = new CancellationTokenSource(); var token = _cancellationTokenSource.Token; try { //Paso 1: Conectar VPN if (!await ConectarVPNAsync(token)) { ActualizarUI(EstadoProceso.Error); return; } //Paso 2: Conectar NAS if (!await ConectarNASAsync(token)) return; //Paso 3: Verificar mapeo con reintentos if (!await VerificarMapeoAsync(token)) { Logger.Warning("No se pudo verificar el mapeo del NAS después de varios intentos"); MessageBox.Show("No se pudo verificar el mapo del NAS después de varios intentos.", "Error de mapeo", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } //Paso 4: Actualización await EjecutarActualizacionAsync(); //Paso 5: Registrar (Revisar la funcion RegistrarActualizacion) Tareas.RegistrarActualizacion("Actualización completa", "Issue X"); Logger.Info("Actualización finalizada exitosamente"); ActualizarUI(EstadoProceso.Exito); } catch (OperationCanceledException) { Logger.Info("Operación cancelada por el usuario"); MessageBox.Show("Operación cancelada", "Información", MessageBoxButtons.OK, MessageBoxIcon.Information); ActualizarUI(EstadoProceso.Cancelado); } catch (Exception ex) { Logger.Error($"Error durante la actualización: {ex.Message}"); MessageBox.Show($"Ha ocurrido un error al realizar la actualización:\n{ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); Tareas.RegistrarActualizacion($"Error: {ex.Message}"); ActualizarUI(EstadoProceso.Error); } finally { _cancellationTokenSource?.Dispose(); _cancellationTokenSource = null; } } #endregion #region Actualizar FlySmart private async void BtnFlysmart_Click(object sender, EventArgs e) { Logger.Info("Usuario presionó: ACTUALIZAR FLYSMART+"); btnFlysmart.Enabled= false; OcultarProgreso(); _cancellationTokenSource?.Dispose(); _cancellationTokenSource = new CancellationTokenSource(); var token = _cancellationTokenSource.Token; // Confirmar acción var resultado = MessageBox.Show("Al continuar se eliminará la carga de FlySmart.\n\n¿Está seguro de continuar?", "Confirmación", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (resultado != DialogResult.Yes) { Logger.Info("Usuario canceló la confirmación de FlySmart"); return; } Logger.Info("Usuario confirmó eliminar FlySmart"); btnFlysmart.Enabled = false; try { // Paso 1: Limpiar carpeta FlySmart await LimpiarCarpetaFlySmartAsync(); // Paso 2: Conectar VPN if (!await ConectarVPNAsync(token)) { return; } // Paso 3. Conectar NAS if (!await ConectarFlySmartAsync()) { return; } // Paso 4: Verificar mapeo FlySmart if (!await VerificarFlySmartAsync()) { Logger.Warning("No se pudo verificar el mapeo de FlySmart después de varios intentos"); MessageBox.Show("No se pudo verificar el mapeo de FlySmart después de varios intentos.", "Error de mapeo", MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } // Paso 4: Esperar estabilización //Logger.Info("Esperando estabilización de FlySmart..."); //await Task.Delay(3000); // Paso 5: Preparar UI MostrarProgreso(); //Paso 6. Ejecutar Robocopy await EjecutarActualizacionFlySmartAsync(); Logger.Info("Proceso FlySmart iniciado correctamente"); } catch (OperationCanceledException) { Logger.Info("Operación cancelada por el usuario"); MessageBox.Show("Operación cancelada", "Información", MessageBoxButtons.OK, MessageBoxIcon.Information); } catch (Exception ex) { Logger.Error($"Error durante la actualización: {ex.Message}"); MessageBox.Show($"Ha ocurrido un error al realizar la actualización:\n{ex.Message}", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); Tareas.RegistrarActualizacion($"Error: {ex.Message}"); } finally { btnFlysmart.Enabled = true; _cancellationTokenSource?.Dispose(); _cancellationTokenSource = null; } } //Funcion para borrar el contenido de la carpeta FlySmart private async Task LimpiarCarpetaFlySmartAsync() { Logger.Info($"Limpiando carpeta FlySmart: {AppConfig.RUTA_DESTINO_FLYSMART}"); await Task.Run(() => { try { if (!Directory.Exists(AppConfig.RUTA_DESTINO_FLYSMART)) { Logger.Warning("La carpeta FlySmart no existe"); return; } // Eliminar archivos foreach (string archivo in Directory.GetFiles(AppConfig.RUTA_DESTINO_FLYSMART)) { File.Delete(archivo); } // Eliminar subdirectorios foreach (string directorio in Directory.GetDirectories(AppConfig.RUTA_DESTINO_FLYSMART)) { Directory.Delete(directorio, true); } Logger.Info("Carpeta FlySmart limpiada correctamente"); } catch (Exception ex) { Logger.Error($"Error al limpiar FlySmart: {ex.Message}", ex); throw; } }); } #endregion #region Gestión de UI public enum EstadoProceso { Idle, Ejecutando, Exito, Error, Cancelado } private void MostrarProgreso() { if (InvokeRequired) { Invoke(MostrarProgreso); return; } lblCopiando.Visible = true; } private void OcultarProgreso() { if (InvokeRequired) { Invoke(OcultarProgreso); return; } lblCopiando.Visible = false; } private void ActualizarUI(EstadoProceso nuevoEstado) { // Si no estamos en el hilo de UI, redirigir la llamada if (InvokeRequired) { Invoke(() => ActualizarUI(nuevoEstado)); return; } _estadoActual = nuevoEstado; switch (nuevoEstado) { case EstadoProceso.Idle: btnActualizar.Enabled = true; btnFlysmart.Enabled = true; btnCancel.Enabled = false; lblCopiando.Visible = false; lblCopiando.ForeColor = Color.White; break; case EstadoProceso.Ejecutando: btnActualizar.Enabled = false; btnFlysmart.Enabled = false; btnCancel.Enabled = true; lblCopiando.Visible = true; lblCopiando.Text = "Preparando..."; lblCopiando.ForeColor = Color.Yellow; break; case EstadoProceso.Exito: btnCancel.Enabled = false; lblCopiando.Visible = true; lblCopiando.Text = "✓ Completado"; lblCopiando.ForeColor = Color.Lime; Task.Delay(5000).ContinueWith(_ => ActualizarUI(EstadoProceso.Idle)); break; case EstadoProceso.Error: btnCancel.Enabled = false; lblCopiando.Visible = true; lblCopiando.Text = "✗ Error"; lblCopiando.ForeColor = Color.Red; Task.Delay(5000).ContinueWith(_ => ActualizarUI(EstadoProceso.Idle)); break; case EstadoProceso.Cancelado: btnCancel.Enabled = false; lblCopiando.Visible = true; lblCopiando.Text = "¡Cancelado!"; lblCopiando.ForeColor = Color.Orange; Task.Delay(5000).ContinueWith(_ => ActualizarUI(EstadoProceso.Idle)); break; } } // Método auxiliar para centralizar el control de botones private void SetUIEstado(bool enProgreso) { btnActualizar.Enabled = !enProgreso; btnFlysmart.Enabled = !enProgreso; btnCancel.Enabled = enProgreso; } private void RedondearBoton(Button boton, int radio) { GraphicsPath gp = new GraphicsPath(); gp.AddArc(0, 0, radio, radio, 180, 90); gp.AddArc(boton.Width - radio, 0, radio, radio, 270, 90); gp.AddArc(boton.Width - radio, boton.Height - radio, radio, radio, 0, 90); gp.AddArc(0, boton.Height - radio, radio, radio, 90, 90); gp.CloseAllFigures(); boton.Region = new Region(gp); } #endregion #region Botones de Control private void btnCancel_Click(object sender, EventArgs e) { Logger.Info("Usuario presionó: CANCELAR"); try { _cancellationTokenSource?.Cancel(); _roboCommand?.Stop(); OcultarProgreso(); //Logger.Info("Operación cancelada por el usuario"); } catch (Exception ex) { Logger.Error($"Error al cancelar operación: {ex.Message}", ex); } } private void btnMapeo_Click(object sender, EventArgs e) { Logger.Info("Usuario presionó: MAPEO"); try { _operacionesRed.ConectarNAS(); } catch (Exception ex) { Logger.Error($"Error al mapear: {ex.Message}", ex); MessageBox.Show($"Error al mapear: {ex.Message}", "Error",MessageBoxButtons.OK, MessageBoxIcon.Error); } } private void btnDesmapeo2_Click(object sender, EventArgs e) { Logger.Info("Usuario presionó: DESMAPEO"); try { Logger.Info("Intentando desmapear NAS..."); _operacionesRed.DesconectarNAS(); Logger.Info("NAS desmapeado correctamente"); } catch (Exception ex) { Logger.Error($"Error al desmapear: {ex.Message}", ex); MessageBox.Show($"Error al desmapear: {ex.Message}", "Error",MessageBoxButtons.OK, MessageBoxIcon.Error); } } #endregion #region Eventos de Interfaz private void PanelMenu_MouseEnter(object sender, EventArgs e) { if (sender is Panel panel && panel.Tag is Label label) { panel.BackColor = Color.FromArgb(55, 55, 55); label.ForeColor = Color.FromArgb(0, 164, 239); } } private void PanelMenu_MouseLeave(object sender, EventArgs e) { if (sender is Panel panel && panel.Tag is Label label) { panel.BackColor = Color.Transparent; label.ForeColor = Color.White; } } private void Hijo_MouseEnter(object sender, EventArgs e) { Control hijo = (Control)sender; Panel padre = (Panel)hijo.Tag; PanelMenu_MouseEnter(padre, e); } private void Hijo_MouseLeave(object sender, EventArgs e) { Control hijo = (Control)sender; Panel padre = (Panel)hijo.Tag; PanelMenu_MouseLeave(padre, e); } private void PanelLateral_Click(object sender, EventArgs e) { Control controlClicado = (Control)sender; Panel panelPadre; if (controlClicado is Panel) { panelPadre = (Panel)controlClicado; } else { panelPadre = (Panel)controlClicado.Tag; } // Resetear color de todos los paneles del menú panelMenuHome.BackColor = Color.Transparent; panelMenuLogs.BackColor = Color.Transparent; panelMenuInfo.BackColor = Color.Transparent; panelMenuSettings.BackColor = Color.Transparent; // Destacar el panel seleccionado panelPadre.BackColor = Color.FromArgb(40, 40, 40); switch (panelPadre.Name) { case "panelMenuHome": MostrarVista(panelVistaHome); break; case "panelMenuLogs": MostrarVista(panelVistaLogs); break; case "panelMenuInfo": MostrarVista(panelVistaInfo); break; case "panelMenuSettings": MostrarVista(panelVistaSettings); break; } } private void MostrarVista(Panel vistaMostrar) { // Ocultar todas las vistas panelVistaHome.Visible = false; panelVistaLogs.Visible = false; panelVistaInfo.Visible = false; panelVistaSettings.Visible = false; // Mostrar la vista seleccionada vistaMostrar.Visible = true; vistaMostrar.BringToFront(); // Si es la vista INFO, actualizar la información if (vistaMostrar.Name == "panelVistaSettings") { ActualizarPanelSettings(); } Logger.Info($"Mostrando vista: {vistaMostrar.Name}"); } private void MostrarVistaHome() { MostrarVista(panelVistaHome); } private void ActualizarIndicadorInternet(bool conectado) { if (InvokeRequired) { Invoke(() => ActualizarIndicadorInternet(conectado)); return; } try { if (conectado) { lblInternet.Text = "Conectado"; pInternet.BackColor = Color.Lime; } else { lblInternet.Text = "Sin Internet"; pInternet.BackColor = Color.Orange; } } catch (Exception ex) { Logger.Error($"Error al actualizar indicador de internet: {ex.Message}", ex); } } private void ActualizarIndicadorVPN(bool conectada) { if (InvokeRequired) { Invoke(() => ActualizarIndicadorVPN(conectada)); return; } try { if (conectada) { pVPN.BackColor = Color.Lime; lblVPN.Text = "Conectada"; } else { pVPN.BackColor = Color.Red; lblVPN.Text = "Desconectada"; } } catch (Exception ex) { Logger.Error($"Error al actualizar indicador VPN: {ex.Message}", ex); } } private void ActualizarIndicadorMapeo(bool nasMapeado, bool flyMapeado) { if (InvokeRequired) { Invoke(() => ActualizarIndicadorMapeo(nasMapeado, flyMapeado)); return; } try { if (nasMapeado || flyMapeado) { lblMapeo.BackColor = Color.Lime; pNAS.BackColor = Color.Lime; if (nasMapeado) lblNAS.Text = "Y: Conectada"; else if (flyMapeado) lblNAS.Text = "X: Conectada"; } else { lblMapeo.BackColor = Color.Red; pNAS.BackColor = Color.Red; lblNAS.Text = "Desconectado"; } } catch (Exception ex) { Logger.Error($"Error al actualizar indicador de mapeo: {ex.Message}", ex); } } #endregion #region Monitoreo de estado private void IniciarMonitoreo() { _ctsMonitoreo = new CancellationTokenSource(); //Cada comprobacion en teoria corre en su propio bucle _= MonitorearInternetAsync(_ctsMonitoreo.Token); _= MonitorearVPNAsync(_ctsMonitoreo.Token); _= MonitorearMapeoAsync(_ctsMonitoreo.Token); } //Bucle independiente para Internet private async Task MonitorearInternetAsync(CancellationToken token) { while (!token.IsCancellationRequested) { try { //Ejecutar ping en hilo separado var tarea = Task.Run(() => ComprobarInternetConTimeout(1200), token); //Timeout adicional por si acaso var completada= await Task.WhenAny(tarea, Task.Delay(2000, token)); bool internet = false; if (completada == tarea && tarea.IsCompletedSuccessfully) { internet = await tarea; } //Actualizar UI ActualizarIndicadorInternet(internet); } catch (Exception ex) when (ex is not OperationCanceledException) { Logger.Error($"Error en monitoreo de Internet: {ex.Message}", ex); ActualizarIndicadorInternet(false); } try { await Task.Delay(5000, token); } catch(OperationCanceledException) { break; } } Logger.Debug("Monitoreo de Internet detenido"); } //Bucle independiente para VPN private async Task MonitorearVPNAsync(CancellationToken token) { while (!token.IsCancellationRequested) { try { var vpnConectada = await Task.Run(() => Checker.EstaConectadoVPN(), token); ActualizarIndicadorVPN(vpnConectada); } catch (Exception ex) when (ex is not OperationCanceledException) { Logger.Error($"Error en monitoreo de VPN: {ex.Message}", ex); ActualizarIndicadorVPN(false); } try { await Task.Delay(2000, token); } catch (OperationCanceledException) { break; } } Logger.Debug("Monitoreo de VPN detenido"); } //Bucle independiente para Mapeo private async Task MonitorearMapeoAsync(CancellationToken token) { while (!token.IsCancellationRequested) { try { // Ejecutar ambas comprobaciones en paralelo var tareas = new[] { Task.Run(() => Checker.EstaMapeada(AppConfig.NAS_RUTA_LOCAL), token), Task.Run(() => Checker.EstaMapeada(AppConfig.FLYSMART_RUTA_LOCAL), token) }; await Task.WhenAll(tareas); bool nasMapeado = tareas[0].Result; bool flyMapeado = tareas[1].Result; ActualizarIndicadorMapeo(nasMapeado, flyMapeado); } catch (Exception ex) when (ex is not OperationCanceledException) { Logger.Error($"Error en monitoreo de mapeo: {ex.Message}", ex); ActualizarIndicadorMapeo(false, false); } try { await Task.Delay(2000, token); } catch (OperationCanceledException) { break; } } Logger.Debug("Monitoreo de Mapeo detenido"); } //Ping con timeout agresivo y manejo robusto private bool ComprobarInternetConTimeout(int timeoutMs) { try { using var ping = new Ping(); var reply = ping.Send("8.8.8.8", timeoutMs); return reply?.Status == IPStatus.Success; } catch (PingException) { return false; } catch (Exception) { return false; } } private void ManejarEventoTiempoVPN(object? sender, EventArgs e) { try { bool vpnConectada = Checker.EstaConectadoVPN(); if (vpnConectada) { pVPN.BackColor = Color.Lime; lblVPN.Text = "Conectada"; } else { pVPN.BackColor = Color.Red; lblVPN.Text = "Desconectada"; } } catch (Exception ex) { Logger.Error($"Error al verificar estado VPN: {ex.Message}", ex); } } private void ManejarEventoTiempoMapeo(object? sender, EventArgs e) { try { bool nasMapeado = Checker.EstaMapeada(AppConfig.NAS_RUTA_LOCAL); bool flysmartMapeado= Checker.EstaMapeada(AppConfig.FLYSMART_RUTA_LOCAL); if (nasMapeado || flysmartMapeado) { lblMapeo.BackColor = Color.Lime; pNAS.BackColor = Color.Lime; if (nasMapeado) { lblNAS.Text = "Y: Conectada"; } else if (flysmartMapeado) { lblNAS.Text= "X: Conectada"; } } else { lblMapeo.BackColor = Color.Red; pNAS.BackColor = Color.Red; lblNAS.Text = "Desconectado"; } } catch (Exception ex) { Logger.Error($"Error al verificar mapeo: {ex.Message}", ex); } } private async void ManejarEventoTiempoInternet(object? sender, EventArgs e) { try { bool internetDisponible = await Task.Run(() => ComprobarInternetReal()); if (internetDisponible) { lblInternet.Text = "Conectado"; pInternet.BackColor = Color.Lime; return; } else { lblInternet.Text = "Sin Internet"; pInternet.BackColor = Color.Orange; } } catch (Exception ex) { Logger.Error($"Error al verificar estado de Internet: {ex.Message}", ex); } } private bool ComprobarInternetReal() { try { using (Ping ping = new Ping()) { PingReply reply = ping.Send("8.8.8.8", 1500); return reply.Status == IPStatus.Success; } } catch { return false; } } #endregion #region Cierre y Limpieza private async void Form1_FormClosing(object sender, FormClosingEventArgs e) { Logger.Info("Cerrando aplicación..."); //Cancelar monitoreo _ctsMonitoreo?.Cancel(); //Dar tiempo a que terminen los bucles //await Task.Delay(1000); // Cancelar operaciones en curso _cancellationTokenSource?.Cancel(); try { // Detener timers //_timerVPN?.Stop(); //_timerMapeo?.Stop(); //_timerInternet?.Stop(); // Desconectar recursos _operacionesRed.DesconectarNAS(); _operacionesRed.DesconectarVPN(); _operacionesRed.DesconectarFlySmart(); Logger.Info("Aplicación cerrada correctamente"); } catch (Exception ex) { Logger.Error($"Error al cerrar aplicación: {ex.Message}", ex); } } #endregion } }