docs: Add file and line references to all code blocks in README
- Add specific line references to servidor.py code blocks - Add specific line references to app.py code blocks - Improve code traceability for email client documentation - Improve code traceability for game server documentation - Make documentation more navigable with precise locations
This commit is contained in:
parent
1006498c94
commit
1ad9ac98db
38
README.md
38
README.md
|
|
@ -378,7 +378,7 @@ El servidor **identifica a cada jugador mediante su dirección de socket**, que
|
||||||
#### ¿Cómo funciona en el mismo ordenador?
|
#### ¿Cómo funciona en el mismo ordenador?
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# servidor.py - Al aceptar conexión
|
# servidor.py:62-65 - Al aceptar conexión
|
||||||
conn, addr = s.accept() # addr = ('127.0.0.1', 49956)
|
conn, addr = s.accept() # addr = ('127.0.0.1', 49956)
|
||||||
|
|
||||||
# El sistema operativo asigna un puerto efímero ÚNICO
|
# El sistema operativo asigna un puerto efímero ÚNICO
|
||||||
|
|
@ -430,9 +430,10 @@ self.client_list = [] # Lista ordenada de direcciones
|
||||||
└─────────────────────────────────────────────────────────────────┘
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
```
|
```
|
||||||
|
|
||||||
#### Código de Verificación (servidor.py)
|
#### Código de Verificación
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
# servidor.py:222-232 - Verificación de turno al colocar bomba
|
||||||
elif msg_type == 'PLACE_BOMB':
|
elif msg_type == 'PLACE_BOMB':
|
||||||
if self.state == STATE_PLACING:
|
if self.state == STATE_PLACING:
|
||||||
# Obtener quién tiene el turno actual
|
# Obtener quién tiene el turno actual
|
||||||
|
|
@ -452,7 +453,8 @@ elif msg_type == 'PLACE_BOMB':
|
||||||
El cliente guarda su propia dirección al conectarse y la compara con los mensajes del servidor:
|
El cliente guarda su propia dirección al conectarse y la compara con los mensajes del servidor:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# app.py - Al conectarse
|
# app.py:1221-1240 - Identificación del cliente y manejo de turno
|
||||||
|
# Al conectarse
|
||||||
self.my_address = str(sock.getsockname()) # Ej: "('127.0.0.1', 49956)"
|
self.my_address = str(sock.getsockname()) # Ej: "('127.0.0.1', 49956)"
|
||||||
|
|
||||||
# Al recibir TURN_NOTIFY del servidor
|
# Al recibir TURN_NOTIFY del servidor
|
||||||
|
|
@ -499,7 +501,7 @@ El servidor usa un **Set de Python** para almacenar las coordenadas de las bomba
|
||||||
#### **Estructura de Datos: `self.bombs = set()`**
|
#### **Estructura de Datos: `self.bombs = set()`**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# servidor.py - Línea 32
|
# servidor.py:32 - Inicialización del set de bombas
|
||||||
class GameServer:
|
class GameServer:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.bombs = set() # Set de tuplas (x, y)
|
self.bombs = set() # Set de tuplas (x, y)
|
||||||
|
|
@ -507,9 +509,10 @@ class GameServer:
|
||||||
|
|
||||||
Un `set()` en Python **no permite elementos duplicados**. Si intentas agregar la misma tupla `(x, y)` dos veces, solo se guarda una vez.
|
Un `set()` en Python **no permite elementos duplicados**. Si intentas agregar la misma tupla `(x, y)` dos veces, solo se guarda una vez.
|
||||||
|
|
||||||
#### **Validación al Colocar Bomba (servidor.py líneas 222-246)**
|
#### **Validación al Colocar Bomba**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
# servidor.py:222-246 - Validación completa de colocación de bomba
|
||||||
elif msg_type == 'PLACE_BOMB':
|
elif msg_type == 'PLACE_BOMB':
|
||||||
if self.state == STATE_PLACING:
|
if self.state == STATE_PLACING:
|
||||||
# 1. Verificar que es el turno del jugador
|
# 1. Verificar que es el turno del jugador
|
||||||
|
|
@ -691,9 +694,10 @@ Grid final:
|
||||||
Total: 6 bombas únicas, sin duplicados
|
Total: 6 bombas únicas, sin duplicados
|
||||||
```
|
```
|
||||||
|
|
||||||
#### **Código del Cliente (app.py líneas 1310-1330)**
|
#### **Código del Cliente**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
# app.py:1310-1330 - Manejo de clic en casilla durante fase de colocación
|
||||||
def on_button_click(x, y):
|
def on_button_click(x, y):
|
||||||
"""Cuando el jugador hace clic en una casilla"""
|
"""Cuando el jugador hace clic en una casilla"""
|
||||||
if self.game_phase == 'PLACING':
|
if self.game_phase == 'PLACING':
|
||||||
|
|
@ -717,6 +721,7 @@ def on_button_click(x, y):
|
||||||
El servidor usa un `threading.Lock` para evitar condiciones de carrera cuando múltiples clientes envían mensajes simultáneamente:
|
El servidor usa un `threading.Lock` para evitar condiciones de carrera cuando múltiples clientes envían mensajes simultáneamente:
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
# servidor.py:28-47 - Sincronización con Lock
|
||||||
class GameServer:
|
class GameServer:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.lock = threading.Lock() # Mutex para sincronización
|
self.lock = threading.Lock() # Mutex para sincronización
|
||||||
|
|
@ -919,7 +924,7 @@ class GameServer:
|
||||||
Protocolo para **leer correos** del servidor. Puerto: **143** (sin TLS).
|
Protocolo para **leer correos** del servidor. Puerto: **143** (sin TLS).
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Conexión IMAP (app.py líneas 1578-1582)
|
# app.py:1578-1582 - Conexión IMAP
|
||||||
import imaplib
|
import imaplib
|
||||||
self.imap_connection = imaplib.IMAP4(host, port_num) # Puerto 143
|
self.imap_connection = imaplib.IMAP4(host, port_num) # Puerto 143
|
||||||
self.imap_connection.login(username, password)
|
self.imap_connection.login(username, password)
|
||||||
|
|
@ -937,7 +942,7 @@ self.imap_connection.login(username, password)
|
||||||
Protocolo para **enviar correos**. Puerto: **25** (sin TLS).
|
Protocolo para **enviar correos**. Puerto: **25** (sin TLS).
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Conexión SMTP (app.py líneas 2949-2955)
|
# app.py:2949-2955 - Conexión y envío SMTP
|
||||||
import smtplib
|
import smtplib
|
||||||
with smtplib.SMTP(smtp_host, smtp_port_num, timeout=15) as server:
|
with smtplib.SMTP(smtp_host, smtp_port_num, timeout=15) as server:
|
||||||
server.send_message(msg, to_addrs=recipients)
|
server.send_message(msg, to_addrs=recipients)
|
||||||
|
|
@ -950,7 +955,7 @@ with smtplib.SMTP(smtp_host, smtp_port_num, timeout=15) as server:
|
||||||
#### **Guardado Automático con Base64**
|
#### **Guardado Automático con Base64**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# GUARDAR (app.py líneas 1540-1557)
|
# app.py:1540-1557 - Función _save_mail_credentials()
|
||||||
import base64
|
import base64
|
||||||
config = {
|
config = {
|
||||||
'imap_host': '10.10.0.101',
|
'imap_host': '10.10.0.101',
|
||||||
|
|
@ -964,7 +969,7 @@ json.dump(config, open('.mail_config.json', 'w'), indent=2)
|
||||||
```
|
```
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# CARGAR (app.py líneas 1512-1520)
|
# app.py:1512-1520 - Función _load_mail_credentials()
|
||||||
config = json.load(open('.mail_config.json', 'r'))
|
config = json.load(open('.mail_config.json', 'r'))
|
||||||
password = base64.b64decode(config['password']).decode() # Decodificar
|
password = base64.b64decode(config['password']).decode() # Decodificar
|
||||||
```
|
```
|
||||||
|
|
@ -1138,6 +1143,7 @@ fetch(mail_id, '(BODY.PEEK[] FLAGS)')
|
||||||
Después de enviar un correo por SMTP, se guarda una copia en la carpeta "Sent" del servidor IMAP para que aparezca en Webmin y otros clientes.
|
Después de enviar un correo por SMTP, se guarda una copia en la carpeta "Sent" del servidor IMAP para que aparezca en Webmin y otros clientes.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
# app.py:2990-3015 - Guardar correo en carpeta Sent del servidor
|
||||||
# Intentar múltiples nombres de carpeta
|
# Intentar múltiples nombres de carpeta
|
||||||
sent_folders = ['Sent', 'INBOX.Sent', 'Enviados', 'INBOX.Enviados', 'Sent Items']
|
sent_folders = ['Sent', 'INBOX.Sent', 'Enviados', 'INBOX.Enviados', 'Sent Items']
|
||||||
|
|
||||||
|
|
@ -1199,9 +1205,10 @@ if not folder_found:
|
||||||
|
|
||||||
### 👥 Envío a Múltiples Destinatarios
|
### 👥 Envío a Múltiples Destinatarios
|
||||||
|
|
||||||
#### **Validación y Parsing (líneas 2703-2740)**
|
#### **Validación y Parsing**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
# app.py:2703-2740 - Validación de múltiples destinatarios
|
||||||
# Entrada del usuario
|
# Entrada del usuario
|
||||||
to_addr_raw = "marcos@psp.es, user2@example.com; user3@test.org"
|
to_addr_raw = "marcos@psp.es, user2@example.com; user3@test.org"
|
||||||
|
|
||||||
|
|
@ -1282,6 +1289,7 @@ self._send_mail_with_attachments(recipients, subject, body, attachments)
|
||||||
#### **Adjuntar Archivos**
|
#### **Adjuntar Archivos**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
# app.py:2568-2590 - Adjuntar archivos con diálogo
|
||||||
# Usuario hace clic en "📎 Adjuntar archivo"
|
# Usuario hace clic en "📎 Adjuntar archivo"
|
||||||
file_paths = filedialog.askopenfilenames(
|
file_paths = filedialog.askopenfilenames(
|
||||||
title='Seleccionar archivos',
|
title='Seleccionar archivos',
|
||||||
|
|
@ -1296,7 +1304,7 @@ file_paths = filedialog.askopenfilenames(
|
||||||
# Se guardan en lista
|
# Se guardan en lista
|
||||||
attachments.append(file_path)
|
attachments.append(file_path)
|
||||||
|
|
||||||
# Al enviar, se procesan:
|
# Al enviar, se procesan (app.py:2895-2920):
|
||||||
for file_path in attachments:
|
for file_path in attachments:
|
||||||
file_name = os.path.basename(file_path) # "documento.pdf"
|
file_name = os.path.basename(file_path) # "documento.pdf"
|
||||||
file_ext = os.path.splitext(file_path)[1] # ".pdf"
|
file_ext = os.path.splitext(file_path)[1] # ".pdf"
|
||||||
|
|
@ -1313,6 +1321,7 @@ for file_path in attachments:
|
||||||
#### **Imágenes Inline con Ctrl+V**
|
#### **Imágenes Inline con Ctrl+V**
|
||||||
|
|
||||||
```python
|
```python
|
||||||
|
# app.py:2609-2645 - Pegar imagen desde portapapeles
|
||||||
# Usuario copia una imagen y presiona Ctrl+V
|
# Usuario copia una imagen y presiona Ctrl+V
|
||||||
def on_paste(event):
|
def on_paste(event):
|
||||||
try:
|
try:
|
||||||
|
|
@ -1394,7 +1403,8 @@ def on_paste(event):
|
||||||
### 🔵 Sistema de Indicadores Visuales
|
### 🔵 Sistema de Indicadores Visuales
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Al cargar correos (líneas 1775-1790)
|
# app.py:1775-1790 - Indicadores visuales de correos leídos/no leídos
|
||||||
|
# Al cargar correos
|
||||||
for mail in mail_list:
|
for mail in mail_list:
|
||||||
if is_seen:
|
if is_seen:
|
||||||
# Correo leído
|
# Correo leído
|
||||||
|
|
@ -1451,7 +1461,7 @@ self.unread_label.config(text=f'Correos sin leer: {self.unread_count}')
|
||||||
### 🛡️ Manejo de Errores y Log
|
### 🛡️ Manejo de Errores y Log
|
||||||
|
|
||||||
```python
|
```python
|
||||||
# Función de log (líneas 4304-4315)
|
# app.py:4304-4315 - Función _log() con verificación de widget
|
||||||
def _log(self, text: str) -> None:
|
def _log(self, text: str) -> None:
|
||||||
# Verificar si estamos en hilo principal
|
# Verificar si estamos en hilo principal
|
||||||
if threading.current_thread() is not threading.main_thread():
|
if threading.current_thread() is not threading.main_thread():
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue