clash / app.py
clash-linux's picture
Upload 17 files
03d4200 verified
raw
history blame
4.59 kB
"""
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)