133 lines
5.4 KiB
Python
133 lines
5.4 KiB
Python
import threading
|
|
from vista.chat.chat_base import ChatBase
|
|
from logica.red.servidor import iniciar_servidor, autenticar_cliente
|
|
from logica.red.selector import obtener_ip_local
|
|
|
|
PREFIJO_NOMBRE = "__NOMBRE__:"
|
|
|
|
|
|
class ChatServidorPanel(ChatBase):
|
|
"""Vista de chat para el rol de servidor."""
|
|
|
|
def __init__(self, parent, root, *args, **kwargs):
|
|
super().__init__(parent, root, *args, **kwargs)
|
|
self.servidor = None
|
|
self.clientes = []
|
|
self.clave_acceso = None
|
|
self.broadcast_stop = None
|
|
self.contador_clientes = 0
|
|
self.crear_interfaz_chat(
|
|
self, titulo="Chat - Servidor",
|
|
boton_accion_texto="Cerrar Servidor",
|
|
boton_accion_callback=self.cerrar_y_volver
|
|
)
|
|
self.iniciar()
|
|
|
|
def iniciar(self):
|
|
ip = obtener_ip_local()
|
|
self.servidor, puerto, contrasena_alfa, self.broadcast_stop = iniciar_servidor()
|
|
self.clave_acceso = f"{puerto}#{contrasena_alfa}"
|
|
print(f"[DEBUG SRV-GUI] Servidor iniciado: ip={ip} puerto={puerto} clave={self.clave_acceso}")
|
|
self.agregar_mensaje_sistema(f"Servidor iniciado en {ip}")
|
|
self.agregar_mensaje_sistema(f"Clave de acceso: {self.clave_acceso}")
|
|
self.agregar_mensaje_sistema("Esperando clientes...")
|
|
|
|
hilo = threading.Thread(target=self.aceptar_clientes, daemon=True)
|
|
hilo.start()
|
|
|
|
def aceptar_clientes(self):
|
|
print("[DEBUG SRV-GUI] Esperando conexiones de clientes...")
|
|
while self.servidor:
|
|
try:
|
|
conn, addr = self.servidor.accept()
|
|
print(f"[DEBUG SRV-GUI] Conexion entrante de {addr[0]}:{addr[1]}")
|
|
datos = conn.recv(1024).decode("utf-8")
|
|
print(f"[DEBUG SRV-GUI] Datos de autenticacion recibidos: {datos!r}")
|
|
if autenticar_cliente(datos, self.clave_acceso):
|
|
conn.sendall("OK".encode("utf-8"))
|
|
self.contador_clientes += 1
|
|
nombre = f"Cliente {self.contador_clientes}"
|
|
conn.sendall(f"{PREFIJO_NOMBRE}{nombre}".encode("utf-8"))
|
|
print(f"[DEBUG SRV-GUI] Cliente autenticado como {nombre!r}, enviado OK + nombre")
|
|
self.clientes.append(conn)
|
|
self.root.after(0, self.agregar_mensaje_sistema, f"{nombre} conectado")
|
|
hilo = threading.Thread(target=self.recibir_de_cliente, args=(conn, nombre), daemon=True)
|
|
hilo.start()
|
|
else:
|
|
conn.sendall("DENIED".encode("utf-8"))
|
|
conn.close()
|
|
etiqueta = f"{addr[0]}:{addr[1]}"
|
|
print(f"[DEBUG SRV-GUI] Cliente {etiqueta} rechazado (clave incorrecta)")
|
|
self.root.after(0, self.agregar_mensaje_sistema, f"Cliente {etiqueta} rechazado")
|
|
except OSError as e:
|
|
print(f"[DEBUG SRV-GUI] Error en accept: {e}")
|
|
break
|
|
|
|
def recibir_de_cliente(self, conn, nombre):
|
|
print(f"[DEBUG SRV-GUI] Hilo de recepcion iniciado para {nombre}")
|
|
try:
|
|
while True:
|
|
datos = conn.recv(4096)
|
|
if not datos:
|
|
print(f"[DEBUG SRV-GUI] {nombre} envio datos vacios (desconexion)")
|
|
break
|
|
mensaje = datos.decode("utf-8")
|
|
print(f"[DEBUG SRV-GUI] Mensaje de {nombre}: {mensaje!r}")
|
|
self.root.after(0, self.agregar_mensaje, nombre, mensaje)
|
|
self.difundir(mensaje, nombre, conn)
|
|
except (ConnectionResetError, OSError) as e:
|
|
print(f"[DEBUG SRV-GUI] Error recibiendo de {nombre}: {e}")
|
|
finally:
|
|
if conn in self.clientes:
|
|
self.clientes.remove(conn)
|
|
conn.close()
|
|
self.root.after(0, self.agregar_mensaje_sistema, f"{nombre} desconectado")
|
|
|
|
def difundir(self, mensaje, remitente, origen):
|
|
"""Envia un mensaje a todos los clientes excepto al que lo envio."""
|
|
datos = f"{remitente}: {mensaje}".encode("utf-8")
|
|
for cliente in self.clientes[:]:
|
|
if cliente is not origen:
|
|
try:
|
|
cliente.sendall(datos)
|
|
except OSError:
|
|
self.clientes.remove(cliente)
|
|
|
|
def enviar_mensaje(self, event=None):
|
|
mensaje = self.chat_input_entry.get().strip()
|
|
if not mensaje:
|
|
return "break" if event else None
|
|
|
|
self.chat_input_entry.delete(0, "end")
|
|
self.agregar_mensaje("SERVIDOR", mensaje)
|
|
|
|
datos = f"SERVIDOR: {mensaje}".encode("utf-8")
|
|
for cliente in self.clientes[:]:
|
|
try:
|
|
cliente.sendall(datos)
|
|
except OSError:
|
|
self.clientes.remove(cliente)
|
|
|
|
return "break" if event else None
|
|
|
|
def cerrar_y_volver(self):
|
|
"""Cierra el servidor y vuelve al selector."""
|
|
self.cerrar_conexion()
|
|
parent = self.master
|
|
self.destroy()
|
|
if hasattr(parent, 'volver_al_selector'):
|
|
parent.volver_al_selector()
|
|
|
|
def cerrar_conexion(self):
|
|
if self.broadcast_stop:
|
|
self.broadcast_stop.set()
|
|
if self.servidor:
|
|
self.servidor.close()
|
|
self.servidor = None
|
|
for cliente in self.clientes:
|
|
try:
|
|
cliente.close()
|
|
except OSError:
|
|
pass
|
|
self.clientes.clear()
|