diff --git a/gateway/scripts/dashboard.py b/gateway/scripts/dashboard.py index 58b7a06..2f8f09b 100644 --- a/gateway/scripts/dashboard.py +++ b/gateway/scripts/dashboard.py @@ -22,7 +22,7 @@ TEMPLATES_DIR = _SCRIPT_DIR / "templates" CONFIG_DIR = _PROJECT_DIR / "config" LOGS_DIR = _GATEWAY_DIR / "logs" TEMP_DIR = _GATEWAY_DIR / "temp" -XMPP_BRIDGE_URL = os.environ.get("XMPP_BRIDGE_URL", "http://127.0.0.1:5802") +XMPP_BRIDGE_URL = os.environ.get("XMPP_BRIDGE_URL", "http://192.168.1.16:5802") EJABBERD_HOST = os.environ.get("EJABBERD_HOST", "192.168.1.246") # On Linux (mohe), dashboard runs from systemd with different paths. Support explicit override. @@ -814,41 +814,51 @@ def api_expected(): def port_open(port): + """Check if a port is listening. Works on both Linux and Windows.""" try: - r = subprocess.run(["netstat", "-ano"], capture_output=True, text=True, timeout=5, - creationflags=subprocess.CREATE_NO_WINDOW) - return any(f":{port} " in line and "LISTENING" in line for line in r.stdout.splitlines()) + import socket + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.settimeout(2) + result = s.connect_ex(("127.0.0.1", port)) + s.close() + return result == 0 except: return False +# EasyTier/RDP API key for xmpp_bot on Windows +_BRIDGE_KEY = "xxm_bridge_8f3a2c" + +def _bridge_post(path, payload, timeout=15): + """POST to xmpp_bot HTTP bridge on Windows.""" + req = urllib.request.Request( + f"{XMPP_BRIDGE_URL}{path}", + data=json.dumps(payload).encode(), + headers={"Content-Type": "application/json", "X-Api-Key": _BRIDGE_KEY}, + method="POST") + resp = urllib.request.urlopen(req, timeout=timeout) + return json.loads(resp.read()) + + # ════════════════════════════════════════════════════════════ # EasyTier VPN + RDP 远程桌面控制 # ════════════════════════════════════════════════════════════ @app.route("/api/easytier") def api_easytier_status(): - """EasyTier VPN 状态""" + """EasyTier VPN 状态 — proxy to xmpp_bot on Windows.""" try: - r = subprocess.run(["tasklist", "/FI", "IMAGENAME eq easytier-core.exe", "/NH"], - capture_output=True, text=True, timeout=5, - creationflags=subprocess.CREATE_NO_WINDOW) - windows_running = "easytier-core" in r.stdout - # Proxy to xmpp_bot for 246 status (via POST /easytier with action=status) + windows_running = False status_246 = "unknown" try: - req = urllib.request.Request("http://127.0.0.1:5802/easytier", - data=b'{"action":"status"}', - headers={"Content-Type": "application/json", "X-Api-Key": "xxm_bridge_8f3a2c"}, - method="POST") - resp = urllib.request.urlopen(req, timeout=5) - data = json.loads(resp.read()) + data = _bridge_post("/easytier", {"action": "status"}, timeout=5) + windows_running = data.get("running", False) status_246 = "running" if data.get("running") else "stopped" except: pass return jsonify({ "ok": True, "status": {"windows": "running" if windows_running else "stopped", "246": status_246}, - "virtual_ips": {"windows": "10.144.144.2", "246": "10.144.144.1"}, + "virtual_ips": {"windows": "10.144.144.3", "246": "10.144.144.1"}, "windows_running": windows_running, }) except Exception as e: @@ -857,19 +867,13 @@ def api_easytier_status(): @app.route("/api/easytier/toggle", methods=["POST"]) def api_easytier_toggle(): - """EasyTier VPN 开关""" + """EasyTier VPN 开关 — proxy to xmpp_bot on Windows.""" try: body = json.loads(request.data) action = body.get("action", "") if action not in ("start", "stop"): return jsonify({"ok": False, "error": "action must be start|stop"}) - # Proxy to xmpp_bot which handles EasyTier via subprocess - req = urllib.request.Request(f"http://127.0.0.1:5802/easytier", - data=json.dumps({"action": action}).encode(), - headers={"Content-Type": "application/json", "X-Api-Key": "xxm_bridge_8f3a2c"}, - method="POST") - resp = urllib.request.urlopen(req, timeout=15) - data = json.loads(resp.read()) + data = _bridge_post("/easytier", {"action": action}, timeout=15) return jsonify({"ok": data.get("ok", False), "message": data.get("message", "")}) except Exception as e: return jsonify({"ok": False, "error": str(e)}) @@ -877,21 +881,16 @@ def api_easytier_toggle(): @app.route("/api/rdp") def api_rdp_status(): - """RDP 远程桌面状态""" + """RDP 远程桌面状态 — proxy to xmpp_bot on Windows.""" try: - # Check if RDP port 3389 is accessible rdp_enabled = False + tunnel_running = False try: - s = urllib.request.urlopen("http://127.0.0.1:5802/rdp", - data=b'{"action":"status"}', - headers={"Content-Type": "application/json", "X-Api-Key": "xxm_bridge_8f3a2c"}, - timeout=5) - data = json.loads(s.read()) - rdp_enabled = data.get("ok", False) + data = _bridge_post("/rdp", {"action": "status"}, timeout=5) + rdp_enabled = data.get("rdp_enabled", False) + tunnel_running = data.get("tunnel_running", False) except: pass - # Check SSH tunnel (port 8080) - tunnel_running = port_open(8080) return jsonify({ "ok": True, "rdp_enabled": rdp_enabled, @@ -906,18 +905,13 @@ def api_rdp_status(): @app.route("/api/rdp/toggle", methods=["POST"]) def api_rdp_toggle(): - """RDP 远程桌面开关""" + """RDP 远程桌面开关 — proxy to xmpp_bot on Windows.""" try: body = json.loads(request.data) action = body.get("action", "") if action not in ("start", "stop"): return jsonify({"ok": False, "error": "action must be start|stop"}) - req = urllib.request.Request(f"http://127.0.0.1:5802/rdp", - data=json.dumps({"action": action}).encode(), - headers={"Content-Type": "application/json", "X-Api-Key": "xxm_bridge_8f3a2c"}, - method="POST") - resp = urllib.request.urlopen(req, timeout=15) - data = json.loads(resp.read()) + data = _bridge_post("/rdp", {"action": action}, timeout=15) return jsonify({"ok": data.get("ok", False), "message": data.get("message", "")}) except Exception as e: return jsonify({"ok": False, "error": str(e)})