Files
Nexus/server/infrastructure/guacamole/tunnel.py
T

59 lines
1.7 KiB
Python
Raw Normal View History

"""Async WebSocket ↔ guacd TCP bridge (Guacamole protocol relay)."""
from __future__ import annotations
import asyncio
import logging
from fastapi import WebSocket, WebSocketDisconnect
logger = logging.getLogger("nexus.guacamole.tunnel")
async def bridge_websocket_to_guacd(
websocket: WebSocket,
guacd_host: str,
guacd_port: int,
) -> None:
"""Relay Guacamole instructions between browser and guacd."""
reader: asyncio.StreamReader
writer: asyncio.StreamWriter
reader, writer = await asyncio.open_connection(guacd_host, guacd_port)
async def ws_to_guacd() -> None:
try:
while True:
data = await websocket.receive_text()
writer.write(data.encode("utf-8"))
await writer.drain()
except WebSocketDisconnect:
pass
except Exception as exc:
logger.debug("RDP WS→guacd ended: %s", exc)
async def guacd_to_ws() -> None:
try:
while True:
chunk = await reader.read(8192)
if not chunk:
break
await websocket.send_text(chunk.decode("utf-8", errors="replace"))
except Exception as exc:
logger.debug("RDP guacd→WS ended: %s", exc)
ws_task = asyncio.create_task(ws_to_guacd())
guacd_task = asyncio.create_task(guacd_to_ws())
try:
await asyncio.wait(
[ws_task, guacd_task],
return_when=asyncio.FIRST_COMPLETED,
)
finally:
for task in (ws_task, guacd_task):
task.cancel()
writer.close()
try:
await writer.wait_closed()
except Exception:
pass