Procházet zdrojové kódy

fix: serve.py 添加 WebSocket 代理支持,控制台连接正常

- serve.py 使用 websockets 库代理 /ws/* 到后端
- 新增 frontend/requirements.txt 依赖
- install.sh 自动安装前端 Python 依赖
Hermes Agent před 1 týdnem
rodič
revize
3e365a04fd
3 změnil soubory, kde provedl 49 přidání a 7 odebrání
  1. 1 0
      frontend/requirements.txt
  2. 43 7
      frontend/serve.py
  3. 5 0
      install.sh

+ 1 - 0
frontend/requirements.txt

@@ -0,0 +1 @@
+websockets>=10.0

+ 43 - 7
frontend/serve.py

@@ -1,5 +1,8 @@
-"""Simple static file server for the KVM frontend with API proxy"""
+"""Simple static file server with API and WebSocket proxy"""
+import asyncio
 import http.server
+import websockets
+import threading
 import urllib.request
 import urllib.error
 import os
@@ -8,6 +11,7 @@ import json
 PORT = 8006
 DIST_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "dist")
 API_BASE = "http://127.0.0.1:8004"
+WS_BASE = "ws://127.0.0.1:8004"
 
 
 class KVMHandler(http.server.SimpleHTTPRequestHandler):
@@ -21,7 +25,6 @@ class KVMHandler(http.server.SimpleHTTPRequestHandler):
             self.path = "/index.html"
             super().do_GET()
         else:
-            # SPA fallback: if file doesn't exist, serve index.html
             file_path = os.path.join(DIST_DIR, self.path.lstrip("/"))
             if os.path.isfile(file_path):
                 super().do_GET()
@@ -48,14 +51,12 @@ class KVMHandler(http.server.SimpleHTTPRequestHandler):
             self.send_error(404)
 
     def _proxy(self, method):
-        """Proxy API requests to backend"""
         content_length = int(self.headers.get("Content-Length", 0))
         body = self.rfile.read(content_length) if content_length > 0 else None
 
         url = f"{API_BASE}{self.path}"
         req = urllib.request.Request(url, data=body, method=method)
-        
-        # Forward headers
+
         for key in ["Content-Type", "Authorization"]:
             if key in self.headers:
                 req.add_header(key, self.headers[key])
@@ -82,10 +83,45 @@ class KVMHandler(http.server.SimpleHTTPRequestHandler):
             self.wfile.write(json.dumps({"error": str(e)}).encode())
 
     def log_message(self, format, *args):
-        pass  # Suppress logs
+        pass
+
+
+async def websocket_proxy(websocket, path):
+    """Proxy WebSocket connections to backend"""
+    ws_url = f"{WS_BASE}{path}"
+    try:
+        async with websockets.connect(ws_url) as backend_ws:
+            async def forward_to_backend():
+                async for msg in websocket:
+                    await backend_ws.send(msg)
+
+            async def forward_to_frontend():
+                async for msg in backend_ws:
+                    await websocket.send(msg)
+
+            await asyncio.gather(
+                forward_to_backend(),
+                forward_to_frontend()
+            )
+    except Exception as e:
+        print(f"WebSocket proxy error: {e}")
+
+
+async def ws_handler(websocket, path):
+    await websocket_proxy(websocket, path)
+
+
+def run_websocket_server():
+    asyncio.run(websockets.serve(ws_handler, "0.0.0.0", PORT))
 
 
 if __name__ == "__main__":
+    # Start WebSocket server in background thread
+    ws_thread = threading.Thread(target=run_websocket_server, daemon=True)
+    ws_thread.start()
+    print(f"WebSocket proxy listening on ws://0.0.0.0:{PORT}")
+
+    # Start HTTP server
     server = http.server.HTTPServer(("0.0.0.0", PORT), KVMHandler)
-    print(f"KVM Frontend serving on http://0.0.0.0:{PORT}")
+    print(f"Static file server serving on http://0.0.0.0:{PORT}")
     server.serve_forever()

+ 5 - 0
install.sh

@@ -100,6 +100,11 @@ cd "$FRONTEND_DIR"
 npm install
 npm run build
 
+# 安装前端 Python 依赖 (serve.py 需要 websockets)
+if ! pip show websockets &>/dev/null; then
+    pip install -r requirements.txt
+fi
+
 echo -e "${YELLOW}[5/5] 验证前端...${NC}"
 if [[ -d "dist" ]]; then
     echo -e "${GREEN}    ✓ 前端编译成功, dist/ 已生成${NC}"