#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ 调试工具 - 用于分析 Clash Core 的运行环境 """ import os import sys import subprocess import logging import platform import json logger = logging.getLogger(__name__) def check_binary(binary_path): """检查二进制文件,并返回详细信息""" results = { "path": binary_path, "exists": os.path.exists(binary_path), "size": 0, "permissions": "", "file_type": "", "ldd_output": "", "system_info": get_system_info() } if results["exists"]: try: # 获取文件大小 results["size"] = os.path.getsize(binary_path) # 获取文件权限 results["permissions"] = oct(os.stat(binary_path).st_mode)[-3:] # 检查是否可执行 results["is_executable"] = os.access(binary_path, os.X_OK) # 获取文件类型 (file 命令) try: file_output = subprocess.check_output(["file", binary_path], universal_newlines=True) results["file_type"] = file_output.strip() except Exception as e: results["file_type_error"] = str(e) # 获取库依赖 (ldd 命令) try: ldd_output = subprocess.check_output(["ldd", binary_path], universal_newlines=True) results["ldd_output"] = ldd_output.strip() except Exception as e: results["ldd_error"] = str(e) # 尝试直接执行获取版本或帮助 try: version_output = subprocess.check_output([binary_path, "-v"], stderr=subprocess.STDOUT, universal_newlines=True, timeout=2) results["version_output"] = version_output.strip() except Exception as e: results["version_error"] = str(e) # 如果 -v 失败,尝试 --version try: version_output = subprocess.check_output([binary_path, "--version"], stderr=subprocess.STDOUT, universal_newlines=True, timeout=2) results["version_output"] = version_output.strip() except Exception as e2: results["version_error_alt"] = str(e2) except Exception as e: results["error"] = str(e) return results def get_system_info(): """获取系统信息""" info = { "platform": platform.platform(), "system": platform.system(), "release": platform.release(), "version": platform.version(), "architecture": platform.machine(), "python_version": sys.version, "cwd": os.getcwd(), "env": {key: value for key, value in os.environ.items()} } return info def check_clash_environment(clash_path, config_path): """检查 Clash 运行环境""" results = { "clash_binary": check_binary(clash_path), "config_file": { "path": config_path, "exists": os.path.exists(config_path), "size": 0, "content_preview": "" }, "directory_info": {} } # 检查配置文件 if results["config_file"]["exists"]: try: results["config_file"]["size"] = os.path.getsize(config_path) with open(config_path, 'r', encoding='utf-8') as f: content = f.read(1000) # 读取前1000个字符 results["config_file"]["content_preview"] = content except Exception as e: results["config_file"]["error"] = str(e) # 检查目录结构 dirs_to_check = [ os.path.dirname(clash_path), os.path.dirname(config_path), ".", "./data", "./clash_core", "./subconverter" ] for dir_path in dirs_to_check: try: if os.path.exists(dir_path): files = os.listdir(dir_path) results["directory_info"][dir_path] = { "exists": True, "files": files, "permissions": oct(os.stat(dir_path).st_mode)[-3:] } else: results["directory_info"][dir_path] = { "exists": False } except Exception as e: results["directory_info"][dir_path] = { "error": str(e) } return results def run_debug_diagnostics(clash_path, config_path): """运行调试诊断,并记录结果""" logger.info("运行调试诊断...") try: results = check_clash_environment(clash_path, config_path) logger.info("诊断完成") # 将结果保存到文件 diagnostics_file = "clash_diagnostics.json" with open(diagnostics_file, 'w', encoding='utf-8') as f: json.dump(results, f, indent=2, ensure_ascii=False) logger.info(f"诊断结果已保存到 {diagnostics_file}") # 打印关键信息 if results["clash_binary"]["exists"]: logger.info(f"Clash 二进制文件: {results['clash_binary']['path']}") logger.info(f" - 大小: {results['clash_binary']['size']} 字节") logger.info(f" - 权限: {results['clash_binary']['permissions']}") logger.info(f" - 文件类型: {results['clash_binary']['file_type']}") logger.info(f" - 可执行: {results['clash_binary'].get('is_executable', False)}") else: logger.error(f"Clash 二进制文件不存在: {results['clash_binary']['path']}") if results["config_file"]["exists"]: logger.info(f"配置文件: {results['config_file']['path']}") logger.info(f" - 大小: {results['config_file']['size']} 字节") preview = results["config_file"].get("content_preview", "") if preview: logger.info(f" - 内容预览: {preview[:100]}...") else: logger.error(f"配置文件不存在: {results['config_file']['path']}") return results except Exception as e: logger.error(f"诊断过程中出错: {str(e)}") return {"error": str(e)}