From bd618ad83eec619a1c6997056ed90c8037c14020 Mon Sep 17 00:00:00 2001 From: mshe <666666666@666666666.666666666> Date: Mon, 15 Jun 2026 10:27:38 +0800 Subject: [PATCH] bak --- app.py | 305 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 288 insertions(+), 17 deletions(-) diff --git a/app.py b/app.py index 8e96f44..9e5c5d3 100755 --- a/app.py +++ b/app.py @@ -32,36 +32,307 @@ async def mail_qq_spider(account: str,display: int) -> str: return json.dumps(data, ensure_ascii=False) @mcp.tool() -async def start_xvnc_server(display: int, password="123456") -> str: - """启动XVNC服务 +async def start_xvnc_server(instance: int = 1, password: str = "123456") -> str: + """启动独立的 VNC + Chrome 实例 Args: - display: VNC 显示编号 - password: VNC 密码 + instance: 实例编号 (1-10),会自动计算显示编号和端口 + 实例1: display=99, VNC端口=5900 + 实例2: display=100, VNC端口=5901 + 以此类推 + password: VNC 连接密码,默认 123456 + + Returns: + 包含实例信息的 JSON 字符串 """ - data={"display": display} + data = { + "instance": instance, + "status": 200, + "action": "start" + } + try: - # 调用外部 start_browser.sh 脚本,传入 index 作为参数 + # 调用 browser-vnc.sh 脚本 process = await asyncio.create_subprocess_exec( - f"{SHELL_DIR}/start_browser.sh", - str(password), # VNC 密码 - str(5900), # VNC 端口 - str(display), # 显示编号 + f"{SHELL_DIR}/browser-vnc.sh", + "start", + str(instance), + password, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE ) + stdout, stderr = await process.communicate() - data["message"] = stdout.decode() - data["status"] = 200 if process.returncode == 0 else 500 + output = stdout.decode() if process.returncode == 0: - data["vnc_url"] = f"{VNC_SERVER_HOST}/vnc_lite.html?path=?token=user{display}" - return json.dumps(data, ensure_ascii=False) + # 解析输出获取信息 + public_ip = subprocess.getoutput("hostname -I | awk '{print $1}'") + vnc_port = 5900 + (instance - 1) + display_num = 98 + instance + + data["message"] = output + data["vnc_url"] = f"{VNC_SERVER_HOST}/vnc_lite.html?path=?token=user{instance}" + data["vnc_port"] = vnc_port + data["display"] = display_num + data["password"] = password + data["public_ip"] = public_ip.strip() else: - return json.dumps(data, ensure_ascii=False) - except Exception as e: data["status"] = 500 - return json.dumps(data, ensure_ascii=False) + data["message"] = stderr.decode() or output or "Unknown error" + + return json.dumps(data, ensure_ascii=False) + + except Exception as e: + data["status"] = 500 + data["message"] = str(e) + return json.dumps(data, ensure_ascii=False) + + +@mcp.tool() +async def stop_xvnc_server(instance: int = 1, keep_data: bool = False) -> str: + """停止指定的 VNC 实例 + + Args: + instance: 实例编号 (1-10) + keep_data: 是否保留用户数据,默认 False(删除数据) + + Returns: + 操作结果 + """ + data = { + "instance": instance, + "status": 200, + "action": "stop", + "keep_data": keep_data + } + + try: + # 选择命令:stop 或 stop-keep-data + cmd = "stop-keep-data" if keep_data else "stop" + + process = await asyncio.create_subprocess_exec( + f"{SHELL_DIR}/browser-vnc.sh", + cmd, + str(instance), + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE + ) + + stdout, stderr = await process.communicate() + output = stdout.decode() + + if process.returncode == 0: + data["message"] = output + else: + data["status"] = 500 + data["message"] = stderr.decode() or output or "Unknown error" + + return json.dumps(data, ensure_ascii=False) + + except Exception as e: + data["status"] = 500 + data["message"] = str(e) + return json.dumps(data, ensure_ascii=False) + + +@mcp.tool() +async def stop_all_xvnc_servers(keep_data: bool = False) -> str: + """停止所有 VNC 实例 + + Args: + keep_data: 是否保留用户数据,默认 False(删除所有数据) + + Returns: + 操作结果 + """ + data = { + "status": 200, + "action": "stop_all", + "keep_data": keep_data + } + + try: + # 选择命令:stop-all 或 stop-all-keep-data + cmd = "stop-all-keep-data" if keep_data else "stop-all" + + process = await asyncio.create_subprocess_exec( + f"{SHELL_DIR}/browser-vnc.sh", + cmd, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE + ) + + stdout, stderr = await process.communicate() + output = stdout.decode() + + if process.returncode == 0: + data["message"] = output + else: + data["status"] = 500 + data["message"] = stderr.decode() or output or "Unknown error" + + return json.dumps(data, ensure_ascii=False) + + except Exception as e: + data["status"] = 500 + data["message"] = str(e) + return json.dumps(data, ensure_ascii=False) + + +@mcp.tool() +async def list_xvnc_servers() -> str: + """列出所有运行中的 VNC 实例""" + data = { + "status": 200, + "action": "list", + "instances": [] + } + + try: + process = await asyncio.create_subprocess_exec( + f"{SHELL_DIR}/browser-vnc.sh", + "status", + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE + ) + + stdout, stderr = await process.communicate() + output = stdout.decode() + + # 解析输出,提取运行中的实例 + for line in output.split('\n'): + if "✅ Running" in line: + # 提取实例编号,例如 "Instance 1: ✅ Running" + import re + match = re.search(r'Instance (\d+):', line) + if match: + instance = int(match.group(1)) + data["instances"].append({ + "instance": instance, + "vnc_port": 5900 + (instance - 1), + "display": 98 + instance, + "vnc_url": f"{VNC_SERVER_HOST}/vnc_lite.html?path=?token=user{instance}" + }) + + data["count"] = len(data["instances"]) + data["raw_output"] = output + + return json.dumps(data, ensure_ascii=False) + + except Exception as e: + data["status"] = 500 + data["message"] = str(e) + return json.dumps(data, ensure_ascii=False) + + +@mcp.tool() +async def get_vnc_connection_info(instance: int = 1) -> str: + """获取指定实例的连接信息 + + Args: + instance: 实例编号 (1-10) + + Returns: + 包含连接信息的 JSON 字符串 + """ + data = { + "instance": instance, + "status": 200 + } + + try: + # 检查实例是否在运行 + process = await asyncio.create_subprocess_exec( + f"{SHELL_DIR}/browser-vnc.sh", + "status", + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE + ) + + stdout, _ = await process.communicate() + output = stdout.decode() + + # 检查实例状态 + instance_pattern = f"Instance {instance}:" + is_running = False + for line in output.split('\n'): + if instance_pattern in line: + if "✅ Running" in line: + is_running = True + break + + public_ip = subprocess.getoutput("hostname -I | awk '{print $1}'").strip() + vnc_port = 5900 + (instance - 1) + display_num = 98 + instance + + data["is_running"] = is_running + data["vnc_url"] = f"{VNC_SERVER_HOST}/vnc_lite.html?path=?token=user{instance}" + data["vnc_port"] = vnc_port + data["display"] = display_num + data["public_ip"] = public_ip + + if not is_running: + data["warning"] = "Instance is not running, start it with start_xvnc_server" + + return json.dumps(data, ensure_ascii=False) + + except Exception as e: + data["status"] = 500 + data["message"] = str(e) + return json.dumps(data, ensure_ascii=False) + + +@mcp.tool() +async def cleanup_xvnc_data(instance: Optional[int] = None) -> str: + """清理 VNC 实例的用户数据 + + Args: + instance: 实例编号,如果为 None 则清理所有实例的数据 + + Returns: + 操作结果 + """ + data = { + "status": 200, + "action": "cleanup" + } + + try: + if instance is not None: + # 清理指定实例 + process = await asyncio.create_subprocess_exec( + f"{SHELL_DIR}/browser-vnc.sh", + "cleanup", + str(instance), + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE + ) + data["instance"] = instance + else: + # 清理所有实例 + process = await asyncio.create_subprocess_exec( + f"{SHELL_DIR}/browser-vnc.sh", + "cleanup-all", + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE + ) + + stdout, stderr = await process.communicate() + output = stdout.decode() + + if process.returncode == 0: + data["message"] = output + else: + data["status"] = 500 + data["message"] = stderr.decode() or output or "Unknown error" + + return json.dumps(data, ensure_ascii=False) + + except Exception as e: + data["status"] = 500 + data["message"] = str(e) + return json.dumps(data, ensure_ascii=False) @mcp.tool() async def start_vnc_server(display: int) -> str: """启动VNC服务