Files
Nexus/server/infrastructure/guacamole/tunnel.py
T
Nexus Agent dabfc128b3 feat: 浏览器 RDP、推送提示音与子机指标等多项功能
- 3389远程页 + guacd 侧车 WebSocket 桥(无 RDP 会话审计)
- 文件推送完成独立提示音,至少一台成功即播放
- 子机列表展开 CPU/内存/磁盘 sparkline 与指标采样落库
- 终端全量服务器列表、连接中状态;告警 Telegram 公网 IP
- SSH 密钥凭据 UI 简化;子机搜索未设路径筛选

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-10 01:37:32 +08:00

59 lines
1.7 KiB
Python

"""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