File size: 4,585 Bytes
99187f2
 
 
 
 
 
 
 
 
 
 
 
 
 
5b7de09
 
 
 
 
99187f2
03d4200
 
 
 
 
99187f2
03d4200
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
99187f2
 
 
 
 
 
5b7de09
 
 
 
 
 
 
 
 
 
99187f2
 
 
5b7de09
99187f2
 
 
 
 
 
 
 
 
 
 
5b7de09
99187f2
 
 
 
 
 
 
 
 
 
5b7de09
99187f2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
"""

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)