From cb0774fcb51b0a5239545f0cd18d611685069811 Mon Sep 17 00:00:00 2001 From: CesarAAR Date: Mon, 27 Jul 2026 18:24:14 -0700 Subject: [PATCH] Solucion reto nerve 08 --- .../soluciones/CesarAAR-Python/README.MD | 42 +++++++ .../soluciones/CesarAAR-Python/main.py | 103 ++++++++++++++++++ .../CesarAAR-Python/requirements.txt | Bin 0 -> 1940 bytes .../soluciones/CesarAAR-Python/test.py | 21 ++++ 4 files changed, 166 insertions(+) create mode 100644 retos/nerve/08-puente-http/soluciones/CesarAAR-Python/README.MD create mode 100644 retos/nerve/08-puente-http/soluciones/CesarAAR-Python/main.py create mode 100644 retos/nerve/08-puente-http/soluciones/CesarAAR-Python/requirements.txt create mode 100644 retos/nerve/08-puente-http/soluciones/CesarAAR-Python/test.py diff --git a/retos/nerve/08-puente-http/soluciones/CesarAAR-Python/README.MD b/retos/nerve/08-puente-http/soluciones/CesarAAR-Python/README.MD new file mode 100644 index 0000000..9a0ad9f --- /dev/null +++ b/retos/nerve/08-puente-http/soluciones/CesarAAR-Python/README.MD @@ -0,0 +1,42 @@ +# Solución Reto Nerve #08 Puente HTTP + +## Estructura +```text +CesarAAR-Python +├── main.py #Programa principal. Aquí está toda la logica. +├── requirements.txt #Requerimientos de instalación. +└── test.py #Programa secundario. Pograma para ejecutar para comprobar el funcionamiento de la api. +``` + +## Pasos de uso +1. Crear entorno virtual e instalar dependencias: + +```bash +python -m venv venv +source venv/bin/activate # Linux / Mac +venv\Scripts\activate # Windows + +pip install -r requirements.txt +``` +2. Ejecutar NERVE: +```bash +nerve start +``` + +3. Ejecutar la API: + +```bash +uvicorn main:app --reload +``` +e ingresar a la documentación: `http://127.0.0.1:8000/docs`. + +4. Ejecutar el oyente: +```bash +python test.py +``` +## Opciones de la API +- */*: Verifica el estado de la API +- */login*: Crea el cliente(usuario) en NERVE +- */enviar*: Envias un mensaje a un cliente destino (el de test.py = test2). +- */enviar-all*: Envias el mensaje a todos los clientes. +- */logout*: Desconectas al cliente. \ No newline at end of file diff --git a/retos/nerve/08-puente-http/soluciones/CesarAAR-Python/main.py b/retos/nerve/08-puente-http/soluciones/CesarAAR-Python/main.py new file mode 100644 index 0000000..df7bac8 --- /dev/null +++ b/retos/nerve/08-puente-http/soluciones/CesarAAR-Python/main.py @@ -0,0 +1,103 @@ +from fastapi import FastAPI, Response, status +from nerve import NexusClient +from fastapi.middleware.cors import CORSMiddleware + +client = NexusClient() + +app = FastAPI( + title="Reto 08 — Puente HTTP para Nerve (FastAPI) #8", + description="API Solución reto #8", + version="1.0.0", +) + +app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["*"], + allow_headers=["*"], +) + + +@app.get("/", summary="Probar conexion a la API.") +def test(response: Response): + response.status_code = status.HTTP_200_OK + return {"status": 200, "details": "API funcionando correctamente"} + + +@app.post("/login", summary="Conectarse a NERVE.") +def login(name_user: str, response: Response): + try: + if not name_user or not name_user.strip(): + raise ValueError("El name_user no puede estar vacío.") + + if not isinstance(name_user, str) or not isinstance(name_user, str): + raise TypeError("El name_user debe ser texto (str).") + + client.connect(name_user) + response.status_code = status.HTTP_200_OK + return {"status": 200, "details": f"Conectado con el user: {name_user}"} + + except (ValueError, TypeError) as ev: + response.status_code = status.HTTP_422_UNPROCESSABLE_CONTENT + return {"status": 422, "details": f"Error de Validación: {ev}"} + except Exception as e: + response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR + return {"status": 500, "details": str(e)} + + +@app.post("/enviar", summary="Enviar mensaje a otro usuario via NERVE.") +def enviar_nerve(destino: str, mensaje: str, response: Response): + try: + if not destino or not destino.strip(): + raise ValueError("El destino no puede estar vacío.") + if not mensaje or not mensaje.strip(): + raise ValueError("El mensaje no puede estar vacío.") + + if not isinstance(destino, str) or not isinstance(mensaje, str): + raise TypeError("Ambos campos deben ser texto (str).") + + msg_json = {"to": destino, "msg": mensaje} + + client.send(destino, msg_json) + response.status_code = status.HTTP_200_OK + return {"status": 200, "details": {"to": destino, "payload": msg_json}} + except (ValueError, TypeError) as ev: + response.status_code = status.HTTP_422_UNPROCESSABLE_CONTENT + return {"status": 422, "details": f"Error de Validación: {ev}"} + except Exception as e: + response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR + return {"status": 500, "details": str(e)} + + +@app.post("/enviar-all", summary="Enviar mensaje a TODOS los clientes via NERVE.") +def enviar_nerve_all(mensaje: str, response: Response): + try: + if not mensaje or not mensaje.strip(): + raise ValueError("El mensaje no puede estar vacío.") + + if not isinstance(mensaje, str): + raise TypeError("MENSAJE debe ser texto (str).") + + msg_json = {"msg": mensaje} + + client.broadcast(msg_json) + response.status_code = status.HTTP_200_OK + return {"status": 200, "details": {"to": "all", "payload": msg_json}} + except (ValueError, TypeError) as ev: + response.status_code = status.HTTP_422_UNPROCESSABLE_CONTENT + return {"status": 422, "details": f"Error de Validación: {ev}"} + except Exception as e: + response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR + return {"status": 500, "details": str(e)} + + +@app.delete("/logout", summary="Desconectarse de NERVE.") +def disconnect(response: Response): + try: + client.disconnect() + response.status_code = status.HTTP_200_OK + return {"status": 200, "details": "Desconexión exitosa."} + except Exception as e: + response.status_code = status.HTTP_500_INTERNAL_SERVER_ERROR + return {"status": 500, "details": str(e)} diff --git a/retos/nerve/08-puente-http/soluciones/CesarAAR-Python/requirements.txt b/retos/nerve/08-puente-http/soluciones/CesarAAR-Python/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..7551b6ee61fbd2953b68443700fa382d4b59322a GIT binary patch literal 1940 zcmZ`)O>fgs5Zp5oKgCh)rW6hwxFRYcapF`Z&WBBH$8wye`SZZcj-TI4)hcq5c6VoI zXFu}q@5&n6T4%MbEW_v427AW)SG;mt*d3nSKH3M^JG>4y;@b$14g5FwyL8_h`0-i3 z>pR-Tdc+-P|IZ#1urJ_naNE*z^1X1hH8`%2=gF;weS#(ODxLF)=p7#NF2F=y_l_Zy z5-9bI!rU=KiOdb20eMO`xNiTaX@YFXIrjJbnNdHbnWvdmElKkq&7wND1dL=F7tcRT6& zmgm7v-r4J@0uiAbF)FP()?I;5KIhB5TT-M#T_Y5s+5=Q0C&ex7i*pYite+iuYgU5K z%bcTdMKz_=uY*d&rfxZG?B93q*&kSn#1^{Co)4HW&hr`Z>@fSx?h#3o5<2@Zd7oha zh3~tm7WIkxGGhz06HpsRP@jT^t?$Cc9ufJ1Ox(aDa&k&kGj)lY_Q=BdU)kR4*gK|X zT+>Yt&KW0;QyR1t4*B$8LZ2P749>2`r?P3|(tH=N=f-odgvJTTT~qBiwMl)lsTS@~ zhPZUw6`OK-9eYGHr-PfdpI9j>Zt3fck5`jK@1;+h`27TfJ?f;kV}i)*5IRZ3u${VQ z>c#V{A5nwCsc(zkHqMvI5BNsKg&a3b_y=@O9S%Oyn_VHx-}cQO?1v-pwrNLc9bElt zV#Avkxd$7y*0wysJMvJSnnn8Vp+np|;>0^d^{LVTHW{?q%(s>sLQdMQBPMK%x_MF9 zrwX;V6Fc2xX|Ef_*;iNNu4^Y*TbPh|MG9Q7&>2~kCEQz0HfJPUQ&th@BaL}~v!uOr zCJ*f>D_Uc^*&+5kGCAQga|fuMZaA~vCEIz13L`u!{{>>rafgYe>vzWg*Rb#xlk*T} JQWrAr#(zEO9UcGx literal 0 HcmV?d00001 diff --git a/retos/nerve/08-puente-http/soluciones/CesarAAR-Python/test.py b/retos/nerve/08-puente-http/soluciones/CesarAAR-Python/test.py new file mode 100644 index 0000000..b2a672e --- /dev/null +++ b/retos/nerve/08-puente-http/soluciones/CesarAAR-Python/test.py @@ -0,0 +1,21 @@ +from nerve import NexusClient +import time + +client = NexusClient() + +client.connect("test2") + + +# Escuchar mensajes entrantes +def on_message(data): + print(f"Recibido: {data}") + + +print("Escuchando eventos en tiempo real... (Presiona Ctrl+C para salir)") +try: + while True: + client.listen(on_message) + time.sleep(1) +except KeyboardInterrupt: + print("\nDesconectando clientes...") + client.disconnect()