Spaces:
Paused
Paused
| """ | |
| Hugging Face Spaces 启动入口 | |
| """ | |
| import os | |
| import sys | |
| import subprocess | |
| import time | |
| import signal | |
| import atexit | |
| def setup_environment(): | |
| """设置必要的环境变量和目录""" | |
| # 确保数据目录存在 | |
| try: | |
| os.makedirs("data", exist_ok=True) | |
| print("✅ 数据目录已创建") | |
| except Exception as e: | |
| print(f"⚠️ 创建数据目录失败: {str(e)}") | |
| # 打印环境诊断信息 | |
| print("🔍 系统信息:") | |
| print(f" - Python: {sys.version}") | |
| print(f" - 工作目录: {os.getcwd()}") | |
| print(f" - 用户: {os.getuid() if hasattr(os, 'getuid') else 'N/A'}") | |
| # 检查二进制文件 | |
| for binary in ["subconverter/subconverter", "clash_core/clash.meta-linux-amd64"]: | |
| if os.path.exists(binary): | |
| try: | |
| # 文件信息 | |
| print(f"✅ 发现二进制文件: {binary}") | |
| print(f" - 大小: {os.path.getsize(binary)} 字节") | |
| print(f" - 权限: {oct(os.stat(binary).st_mode)[-3:]}") | |
| print(f" - 可执行: {os.access(binary, os.X_OK)}") | |
| # 尝试获取文件类型 | |
| try: | |
| file_type = subprocess.check_output(["file", binary], universal_newlines=True) | |
| print(f" - 类型: {file_type.strip()}") | |
| except Exception as e: | |
| print(f" - 获取文件类型失败: {str(e)}") | |
| # 设置执行权限 | |
| os.chmod(binary, 0o755) | |
| print(f"✅ {binary}权限已设置") | |
| except Exception as e: | |
| print(f"⚠️ 检查{binary}时出错: {str(e)}") | |
| else: | |
| print(f"❌ 找不到二进制文件: {binary}") | |
| # 尝试执行 Clash 来获取版本信息 | |
| clash_path = "clash_core/clash.meta-linux-amd64" | |
| if os.path.exists(clash_path): | |
| try: | |
| version_output = subprocess.check_output([clash_path, "-v"], stderr=subprocess.STDOUT, universal_newlines=True, timeout=2) | |
| print(f"✅ Clash版本信息: {version_output.strip()}") | |
| except Exception as e: | |
| print(f"⚠️ 获取Clash版本信息失败: {str(e)}") | |
| # 设置环境变量 | |
| os.environ["FLASK_PORT"] = "7860" # HF Spaces 要求的端口 | |
| # 如果没有设置 SUB_URL 环境变量,尝试从 .env 加载 | |
| if not os.environ.get("SUB_URL") and os.path.exists(".env"): | |
| try: | |
| with open(".env", "r") as f: | |
| for line in f: | |
| line = line.strip() | |
| if line and not line.startswith("#"): | |
| key, value = line.split("=", 1) | |
| os.environ[key] = value | |
| print("✅ 从.env加载了环境变量") | |
| except Exception as e: | |
| print(f"⚠️ 加载.env失败: {str(e)}") | |
| def start_app(): | |
| """启动应用程序""" | |
| print("🚀 正在启动 Simple Clash Relay...") | |
| # 使用 gunicorn 启动 Flask 应用 | |
| app_process = subprocess.Popen( | |
| ["gunicorn", "--bind", "0.0.0.0:7860", "--workers", "2", "--threads", "4", "--timeout", "120", "app.main:app"], | |
| stdout=subprocess.PIPE, | |
| stderr=subprocess.STDOUT, | |
| universal_newlines=True | |
| ) | |
| # 注册应用程序退出时的清理函数 | |
| def cleanup(): | |
| print("🛑 正在停止应用...") | |
| app_process.terminate() | |
| try: | |
| app_process.wait(timeout=5) | |
| except subprocess.TimeoutExpired: | |
| app_process.kill() | |
| atexit.register(cleanup) | |
| # 信号处理 | |
| def signal_handler(sig, frame): | |
| print(f"📢 接收到信号 {sig},正在退出...") | |
| cleanup() | |
| sys.exit(0) | |
| signal.signal(signal.SIGINT, signal_handler) | |
| signal.signal(signal.SIGTERM, signal_handler) | |
| # 输出应用程序日志 | |
| while True: | |
| output = app_process.stdout.readline() | |
| if output: | |
| print(output, end="") | |
| # 如果进程已经退出,退出循环 | |
| if app_process.poll() is not None: | |
| break | |
| # 获取剩余输出 | |
| remaining_output, _ = app_process.communicate() | |
| if remaining_output: | |
| print(remaining_output, end="") | |
| return app_process.returncode | |
| if __name__ == "__main__": | |
| setup_environment() | |
| exit_code = start_app() | |
| sys.exit(exit_code) |