diff --git a/.idea/MutiFunctionProgramProject.iml b/.idea/MutiFunctionProgramProject.iml
index d8b3f6c..f571432 100644
--- a/.idea/MutiFunctionProgramProject.iml
+++ b/.idea/MutiFunctionProgramProject.iml
@@ -2,7 +2,7 @@
-
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
index 1d3ce46..153e9c5 100644
--- a/.idea/misc.xml
+++ b/.idea/misc.xml
@@ -3,5 +3,5 @@
-
+
\ No newline at end of file
diff --git a/src/services/__pycache__/email_client_pop.cpython-312.pyc b/src/services/__pycache__/email_client_pop.cpython-312.pyc
new file mode 100644
index 0000000..61845b6
Binary files /dev/null and b/src/services/__pycache__/email_client_pop.cpython-312.pyc differ
diff --git a/src/services/__pycache__/threads_manager.cpython-312.pyc b/src/services/__pycache__/threads_manager.cpython-312.pyc
index 08978d3..78e9a4f 100644
Binary files a/src/services/__pycache__/threads_manager.cpython-312.pyc and b/src/services/__pycache__/threads_manager.cpython-312.pyc differ
diff --git a/src/services/email_client_pop.py b/src/services/email_client_pop.py
index 11cc23d..3689b66 100644
--- a/src/services/email_client_pop.py
+++ b/src/services/email_client_pop.py
@@ -19,6 +19,7 @@ class EmailClientPOP:
self.smtp_port = smtp_port
self.pop_conn = None
self.smtp_conn = None
+ self.running = True
# Ruta del archivo SQLite:
self.db_file = os.path.join("resources/db_email", "emails.db")
@@ -59,7 +60,7 @@ class EmailClientPOP:
def connect_pop(self):
"""Conexión al servidor POP"""
try:
- self.pop_conn = poplib.POP3(self.pop_server, self.pop_port)
+ self.pop_conn = poplib.POP3(self.pop_server, self.pop_port, timeout=10)
self.pop_conn.user(self.email)
self.pop_conn.pass_(self.password)
print("Conexión POP exitosa")
@@ -70,7 +71,7 @@ class EmailClientPOP:
def connect_smtp(self):
"""Conexión al servidor SMTP"""
try:
- self.smtp_conn = smtplib.SMTP(self.smtp_server, self.smtp_port)
+ self.smtp_conn = smtplib.SMTP(self.smtp_server, self.smtp_port, timeout=10)
self.smtp_conn.login(self.email, self.password)
print("Conexión SMTP exitosa")
except Exception as e:
@@ -84,8 +85,12 @@ class EmailClientPOP:
def reconnect(self):
"""Intenta reconectar a los servidores POP y SMTP"""
print("Intentando reconectar al servidor de correo...")
- self.connect_pop()
- self.connect_smtp()
+ if not self.running:
+ return
+ if self.pop_conn is None:
+ self.connect_pop()
+ if self.smtp_conn is None:
+ self.connect_smtp()
def fetch_unread_count(self):
"""Obtener el número de correos (POP3 no distingue entre leídos y no leídos)"""
@@ -203,7 +208,18 @@ class EmailClientPOP:
def close_connections(self):
"""Cierra las conexiones POP y SMTP"""
- if self.pop_conn:
- self.pop_conn.quit()
- if self.smtp_conn:
- self.smtp_conn.quit()
+ try:
+ if self.pop_conn:
+ self.pop_conn.quit()
+ self.pop_conn = None
+ print("Conexión POP cerrada.")
+ except Exception as e:
+ print(f"Error al cerrar conexión POP: {e}")
+
+ try:
+ if self.smtp_conn:
+ self.smtp_conn.quit()
+ self.smtp_conn = None
+ print("Conexión SMTP cerrada.")
+ except Exception as e:
+ print(f"Error al cerrar conexión SMTP: {e}")
diff --git a/src/services/threads_manager.py b/src/services/threads_manager.py
index 77b5605..caae0a1 100644
--- a/src/services/threads_manager.py
+++ b/src/services/threads_manager.py
@@ -9,6 +9,7 @@ from src.services.threaden_task import ThreadenTask
class ThreadsManager:
"""Constructor"""
+
def __init__(self, ui_instance, email_client):
self.ui_instance = ui_instance
self.email_client = email_client
@@ -16,23 +17,23 @@ class ThreadsManager:
self.radio_player = RadioPlayer()
self.tasks = {
"time": ThreadenTask(),
- "temperature": ThreadenTask(),
- "emails":ThreadenTask(),
- "email_client":ThreadenTask(),
- "tetris_game":ThreadenTask(),
- "scrapper":ThreadenTask(),
+ "temperature": ThreadenTask(),
+ "emails": ThreadenTask(),
+ "email_client": ThreadenTask(),
+ "tetris_game": ThreadenTask(),
+ "scrapper": ThreadenTask(),
"radio_player": ThreadenTask(),
}
self.system_monitor_tasks = {}
self.scrapper = Scrapper(ui_instance)
-
- def play_radio(self, url):
- """Inicia la reproducción de radio en un hilo."""
- if not self.tasks["radio_player"].running:
- self.tasks["radio_player"].start(self.radio_player.play, url)
- def stop_radio(self):
- """Detiene la reproducción de radio."""
+ def play_radio(self, url):
+ """Inicia la reproducción de radio en un hilo."""
+ if not self.tasks["radio_player"].running:
+ self.tasks["radio_player"].start(self.radio_player.play, url)
+
+ def stop_radio(self):
+ """Detiene la reproducción de radio."""
self.radio_player.stop()
def set_system_monitor(self, system_monitor):
@@ -58,13 +59,13 @@ class ThreadsManager:
if hasattr(self.ui_instance, "tetris_game"):
self.tasks["tetris_game"].start(self.update_tetris_game)
-
-
def stop_threads(self):
- """Recorre tasks y para los hilos"""
+ """Detiene todos los hilos y cierra las conexiones."""
for name, task in self.tasks.items():
task.stop()
print(f"Hilo '{name}' detenido")
+ if name == "email_client" and hasattr(self.email_client, "close_connections"):
+ self.email_client.close_connections()
for name, task in self.system_monitor_tasks.items():
task.stop()
@@ -73,7 +74,6 @@ class ThreadsManager:
if self.system_monitor:
self.system_monitor.running = False
-
def update_tetris_game(self):
"""Ciclo de actualizacion del tetris game"""
while self.tasks["tetris_game"].running:
@@ -84,25 +84,24 @@ class ThreadsManager:
except Exception as e:
print(f"Error en update_tetris_game: {e}")
break
-
- def update_system_metric(self, metric):
- """Actualiza una métrica específica del monitor del sistema."""
- while self.system_monitor_tasks[metric].running:
- try:
- self.system_monitor.update_metric(metric)
- time.sleep(self.system_monitor.metrics[metric]["interval"])
- except Exception as e:
- print(f"Error updating metric {metric}: {e}")
+ def update_system_metric(self, metric):
+ """Actualiza una métrica específica del monitor del sistema."""
+ while self.system_monitor_tasks[metric].running:
+ try:
+ self.system_monitor.update_metric(metric)
+ time.sleep(self.system_monitor.metrics[metric]["interval"])
+ except Exception as e:
+ print(f"Error updating metric {metric}: {e}")
-
-
def update_time(self):
while self.tasks["time"].running:
current_time = datetime.datetime.now().strftime('%H:%M:%S')
current_date = datetime.datetime.now().strftime('%d/%m/%Y')
- self.ui_instance.after(0, lambda: self.ui_instance.info_labels["hora"].configure(text=f"Hora: {current_time}"))
- self.ui_instance.after(0, lambda: self.ui_instance.info_labels["fecha"].configure(text=f"Fecha: {current_date}"))
+ self.ui_instance.after(0,
+ lambda: self.ui_instance.info_labels["hora"].configure(text=f"Hora: {current_time}"))
+ self.ui_instance.after(0, lambda: self.ui_instance.info_labels["fecha"].configure(
+ text=f"Fecha: {current_date}"))
time.sleep(1)
def update_temperature(self):
@@ -114,7 +113,8 @@ class ThreadsManager:
if temperature is not None:
self.ui_instance.after(
0,
- lambda: self.ui_instance.info_labels["temperatura"].configure(text=f"Temperatura local: {temperature}°C")
+ lambda: self.ui_instance.info_labels["temperatura"].configure(
+ text=f"Temperatura local: {temperature}°C")
)
except Exception as e:
print(f"Error al obtener la temperatura: {e}")
@@ -139,9 +139,12 @@ class ThreadsManager:
except Exception as e:
print(f"Error en el EmailClient: {e}")
time.sleep(10)
+ finally:
+ self.email_client.close_connections()
+ print("Cliente de correo detenido y conexiones cerradas")
def update_emails(self):
- """Actualiza la cantidad de correos no leidos en tiempo real"""
+ """Actualiza la cantidad de correos no leídos en tiempo real."""
while self.tasks["emails"].running:
try:
if not self.email_client.is_connected():
@@ -149,24 +152,16 @@ class ThreadsManager:
if self.email_client.is_connected():
unread_count = self.email_client.fetch_unread_count()
- self.ui_instance.after(
- 0,
- lambda: self.ui_instance.info_labels["emails"].configure(
- text=f"Correos sin leer: {unread_count}"
+ if self.ui_instance.winfo_exists(): # Verifica si la ventana aún existe
+ self.ui_instance.after(
+ 0,
+ lambda: self.ui_instance.info_labels["emails"].configure(
+ text=f"Correos sin leer: {unread_count}"
+ )
)
- )
else:
print("No hay conexión al servidor de correo")
- self.ui_instance.after(
- 0,
- lambda: self.ui_instance.info_labels["emails"].configure(
- text="Servidor no disponible"
- )
- )
except Exception as e:
print(f"Error en el hilo de correos: {e}")
time.sleep(60)
-
-
-
diff --git a/src/ui/__pycache__/centered_window.cpython-312.pyc b/src/ui/__pycache__/centered_window.cpython-312.pyc
index 30dbfa1..5f3a0c8 100644
Binary files a/src/ui/__pycache__/centered_window.cpython-312.pyc and b/src/ui/__pycache__/centered_window.cpython-312.pyc differ
diff --git a/src/ui/centered_window.py b/src/ui/centered_window.py
index 555ff3d..6cde708 100644
--- a/src/ui/centered_window.py
+++ b/src/ui/centered_window.py
@@ -64,24 +64,37 @@ class CenteredWindow(ctk.CTk):
def on_close(self):
"""Maneja el cierre de la ventana"""
- self.thread_manager.stop_threads()
+ try:
+ # Establecer bandera de cierre para el cliente de correo
+ if hasattr(self, "email_client") and self.email_client:
+ self.email_client.running = False
- if hasattr(self, "tetris_game") and self.tetris_game.running:
- self.tetris_game.stop_game()
+ # Detener todos los hilos
+ self.thread_manager.stop_threads()
- if "tetris_game" in self.thread_manager.tasks:
- self.thread_manager.tasks["tetris_game"].stop()
+ # Cancelar tareas programadas en Tkinter
+ for task in self.after_tasks:
+ try:
+ self.after_cancel(task)
+ except Exception as e:
+ print(f"Error al cancelar tarea programada: {e}")
- if hasattr(self.thread_manager, "scrapper"):
- self.thread_manager.scrapper.stop_scraping()
+ # Cerrar conexiones del cliente POP/SMTP
+ if hasattr(self, "email_client") and self.email_client:
+ self.email_client.close_connections()
- if self.system_monitor:
- self.system_monitor.running = False
+ # Detener tareas adicionales (Tetris, scraping)
+ if hasattr(self, "tetris_game") and self.tetris_game.running:
+ self.tetris_game.stop_game()
- for task in self.after_tasks:
- self.after_cancel(task)
+ if hasattr(self.thread_manager, "scrapper") and self.thread_manager.scrapper:
+ self.thread_manager.scrapper.stop_scraping()
- self.destroy()
+ # Destruir la ventana principal
+ self.destroy()
+ print("Aplicación cerrada correctamente.")
+ except Exception as e:
+ print(f"Error al cerrar la aplicación: {e}")
def create_left_panel(self):
# Panel izquierdo
@@ -335,7 +348,7 @@ class CenteredWindow(ctk.CTk):
listbox_frame.grid(row=0, column=0, sticky="nsew", padx=10, pady=10)
# Crear una lista de correos con un scrollbar
- self.email_listbox = ctk.CTkTextbox(listbox_frame, width=800, height=800)
+ self.email_listbox = ctk.CTkTextbox(listbox_frame, width=600, height=600)
self.email_listbox.grid(row=0, column=0, sticky="nsew", padx=10, pady=10)
self.email_listbox.configure(state="disabled") # Inicialmente deshabilitada
@@ -375,9 +388,11 @@ class CenteredWindow(ctk.CTk):
if self.email_client.is_connected():
emails = self.email_client.fetch_emails()
- self.email_listbox.delete(0, tk.END)
+ self.email_listbox.configure(state="normal")
+ self.email_listbox.delete("1.0", tk.END) # Borra todo el contenido actual
for email in emails:
- self.email_listbox.insert(tk.END, f"{email['subject']} - {email['from']}")
+ self.email_listbox.insert(tk.END, f"De: {email['sender']}\nAsunto: {email['subject']}\n\n")
+ self.email_listbox.configure(state="disabled")
else:
print("No hay conexión al servidor de correo.")
except Exception as e: