Spaces:
Paused
Paused
Upload 13 files
Browse files- Dockerfile +7 -2
- README.md +15 -4
- app.py +88 -0
- app/sub_manager.py +2 -2
- entrypoint.sh +41 -6
Dockerfile
CHANGED
|
@@ -87,8 +87,13 @@ COPY app/ ./app/
|
|
| 87 |
COPY entrypoint.sh ./
|
| 88 |
RUN chmod +x ./entrypoint.sh
|
| 89 |
|
| 90 |
-
#
|
| 91 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 92 |
|
| 93 |
# 使用entrypoint脚本启动应用
|
| 94 |
ENTRYPOINT ["/app/entrypoint.sh"]
|
|
|
|
| 87 |
COPY entrypoint.sh ./
|
| 88 |
RUN chmod +x ./entrypoint.sh
|
| 89 |
|
| 90 |
+
# 暴露端口
|
| 91 |
+
# 7860: Web界面和API服务 (Hugging Face Spaces默认端口)
|
| 92 |
+
# 7890: Clash代理服务 (仅在本地/自托管部署时直接暴露)
|
| 93 |
+
# 9090: Clash内部API端口 (仅供内部服务通信使用)
|
| 94 |
+
EXPOSE 7860
|
| 95 |
+
EXPOSE 7890
|
| 96 |
+
# 注意:9090端口仅供内部使用,不对外暴露
|
| 97 |
|
| 98 |
# 使用entrypoint脚本启动应用
|
| 99 |
ENTRYPOINT ["/app/entrypoint.sh"]
|
README.md
CHANGED
|
@@ -4,7 +4,7 @@ emoji: 🚀
|
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: indigo
|
| 6 |
sdk: docker
|
| 7 |
-
app_port:
|
| 8 |
pinned: false
|
| 9 |
---
|
| 10 |
|
|
@@ -16,7 +16,10 @@ pinned: false
|
|
| 16 |
|
| 17 |
- 🚀 **轻量级**:基于Python Flask和Clash Core,最小化依赖
|
| 18 |
- 🔄 **机场订阅支持**:自动下载并转换您的机场订阅链接
|
| 19 |
-
- 🔌
|
|
|
|
|
|
|
|
|
|
| 20 |
- 🔒 **API认证**:通过API Key保护控制API
|
| 21 |
- 🔄 **动态切换节点**:通过API随时切换使用的节点
|
| 22 |
- 🐳 **容器化**:完整的Docker支持,便于部署
|
|
@@ -89,6 +92,7 @@ simple-clash-relay/
|
|
| 89 |
```
|
| 90 |
docker run -d \
|
| 91 |
-p 7860:7860 \
|
|
|
|
| 92 |
-e SUB_URL=你的订阅链接 \
|
| 93 |
-e API_KEY=你的API密钥 \
|
| 94 |
--name clash-relay \
|
|
@@ -193,14 +197,21 @@ POST /api/refresh
|
|
| 193 |
|
| 194 |
## 在应用中使用代理
|
| 195 |
|
| 196 |
-
|
| 197 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 198 |
- HTTP代理: `http://your-space-name.hf.space/proxy`
|
| 199 |
- SOCKS5代理: `socks5://your-space-name.hf.space/proxy`
|
| 200 |
|
| 201 |
### 在cursor-to-openai项目中配置
|
| 202 |
|
| 203 |
-
修改您的cursor-to-openai
|
|
|
|
|
|
|
| 204 |
|
| 205 |
## 注意事项
|
| 206 |
|
|
|
|
| 4 |
colorFrom: blue
|
| 5 |
colorTo: indigo
|
| 6 |
sdk: docker
|
| 7 |
+
app_port: 7860
|
| 8 |
pinned: false
|
| 9 |
---
|
| 10 |
|
|
|
|
| 16 |
|
| 17 |
- 🚀 **轻量级**:基于Python Flask和Clash Core,最小化依赖
|
| 18 |
- 🔄 **机场订阅支持**:自动下载并转换您的机场订阅链接
|
| 19 |
+
- 🔌 **多端口服务**:
|
| 20 |
+
- **7860**: Web界面和API服务(Hugging Face默认端口)
|
| 21 |
+
- **7890**: Clash代理服务
|
| 22 |
+
- **9090**: Clash内部API服务
|
| 23 |
- 🔒 **API认证**:通过API Key保护控制API
|
| 24 |
- 🔄 **动态切换节点**:通过API随时切换使用的节点
|
| 25 |
- 🐳 **容器化**:完整的Docker支持,便于部署
|
|
|
|
| 92 |
```
|
| 93 |
docker run -d \
|
| 94 |
-p 7860:7860 \
|
| 95 |
+
-p 7890:7890 \
|
| 96 |
-e SUB_URL=你的订阅链接 \
|
| 97 |
-e API_KEY=你的API密钥 \
|
| 98 |
--name clash-relay \
|
|
|
|
| 197 |
|
| 198 |
## 在应用中使用代理
|
| 199 |
|
| 200 |
+
您可以通过以下方式使用代理服务:
|
| 201 |
|
| 202 |
+
### 标准模式
|
| 203 |
+
- HTTP代理: `http://your-server-ip:7890`
|
| 204 |
+
- SOCKS5代理: `socks5://your-server-ip:7890`
|
| 205 |
+
|
| 206 |
+
### Hugging Face Spaces模式 (代理路径转发)
|
| 207 |
- HTTP代理: `http://your-space-name.hf.space/proxy`
|
| 208 |
- SOCKS5代理: `socks5://your-space-name.hf.space/proxy`
|
| 209 |
|
| 210 |
### 在cursor-to-openai项目中配置
|
| 211 |
|
| 212 |
+
修改您的cursor-to-openai项目配置,设置代理地址:
|
| 213 |
+
- 本地部署:`http://localhost:7890`
|
| 214 |
+
- Hugging Face部署:`http://your-space-name.hf.space/proxy`
|
| 215 |
|
| 216 |
## 注意事项
|
| 217 |
|
app.py
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
"""
|
| 2 |
+
Hugging Face Spaces 启动入口
|
| 3 |
+
"""
|
| 4 |
+
|
| 5 |
+
import os
|
| 6 |
+
import sys
|
| 7 |
+
import subprocess
|
| 8 |
+
import time
|
| 9 |
+
import signal
|
| 10 |
+
import atexit
|
| 11 |
+
|
| 12 |
+
def setup_environment():
|
| 13 |
+
"""设置必要的环境变量和目录"""
|
| 14 |
+
# 确保数据目录存在
|
| 15 |
+
os.makedirs("data", exist_ok=True)
|
| 16 |
+
|
| 17 |
+
# 设置执行权限
|
| 18 |
+
if os.path.exists("subconverter/subconverter"):
|
| 19 |
+
os.chmod("subconverter/subconverter", 0o755)
|
| 20 |
+
|
| 21 |
+
if os.path.exists("clash_core/clash.meta-linux-amd64"):
|
| 22 |
+
os.chmod("clash_core/clash.meta-linux-amd64", 0o755)
|
| 23 |
+
|
| 24 |
+
# 设置环境变量
|
| 25 |
+
os.environ["FLASK_PORT"] = "7860" # HF Spaces 要求的端口
|
| 26 |
+
|
| 27 |
+
# 如果没有设置 SUB_URL 环境变量,尝试从 .env 加载
|
| 28 |
+
if not os.environ.get("SUB_URL") and os.path.exists(".env"):
|
| 29 |
+
with open(".env", "r") as f:
|
| 30 |
+
for line in f:
|
| 31 |
+
line = line.strip()
|
| 32 |
+
if line and not line.startswith("#"):
|
| 33 |
+
key, value = line.split("=", 1)
|
| 34 |
+
os.environ[key] = value
|
| 35 |
+
|
| 36 |
+
def start_app():
|
| 37 |
+
"""启动应用程序"""
|
| 38 |
+
print("正在启动 Simple Clash Relay...")
|
| 39 |
+
|
| 40 |
+
# 使用 gunicorn 启动 Flask 应用
|
| 41 |
+
app_process = subprocess.Popen(
|
| 42 |
+
["gunicorn", "--bind", "0.0.0.0:7860", "--workers", "2", "--threads", "4", "--timeout", "120", "app.main:app"],
|
| 43 |
+
stdout=subprocess.PIPE,
|
| 44 |
+
stderr=subprocess.STDOUT,
|
| 45 |
+
universal_newlines=True
|
| 46 |
+
)
|
| 47 |
+
|
| 48 |
+
# 注册应用程序退出时的清理函数
|
| 49 |
+
def cleanup():
|
| 50 |
+
print("正在停止应用...")
|
| 51 |
+
app_process.terminate()
|
| 52 |
+
try:
|
| 53 |
+
app_process.wait(timeout=5)
|
| 54 |
+
except subprocess.TimeoutExpired:
|
| 55 |
+
app_process.kill()
|
| 56 |
+
|
| 57 |
+
atexit.register(cleanup)
|
| 58 |
+
|
| 59 |
+
# 信号处理
|
| 60 |
+
def signal_handler(sig, frame):
|
| 61 |
+
print(f"接收到信号 {sig},正在退出...")
|
| 62 |
+
cleanup()
|
| 63 |
+
sys.exit(0)
|
| 64 |
+
|
| 65 |
+
signal.signal(signal.SIGINT, signal_handler)
|
| 66 |
+
signal.signal(signal.SIGTERM, signal_handler)
|
| 67 |
+
|
| 68 |
+
# 输出应用程序日志
|
| 69 |
+
while True:
|
| 70 |
+
output = app_process.stdout.readline()
|
| 71 |
+
if output:
|
| 72 |
+
print(output, end="")
|
| 73 |
+
|
| 74 |
+
# 如果进程已经退出,退出循环
|
| 75 |
+
if app_process.poll() is not None:
|
| 76 |
+
break
|
| 77 |
+
|
| 78 |
+
# 获取剩余输出
|
| 79 |
+
remaining_output, _ = app_process.communicate()
|
| 80 |
+
if remaining_output:
|
| 81 |
+
print(remaining_output, end="")
|
| 82 |
+
|
| 83 |
+
return app_process.returncode
|
| 84 |
+
|
| 85 |
+
if __name__ == "__main__":
|
| 86 |
+
setup_environment()
|
| 87 |
+
exit_code = start_app()
|
| 88 |
+
sys.exit(exit_code)
|
app/sub_manager.py
CHANGED
|
@@ -122,8 +122,8 @@ class SubscriptionManager:
|
|
| 122 |
cmd = [
|
| 123 |
self.subconverter_path,
|
| 124 |
"-g", # 生成配置文件
|
| 125 |
-
"--target", "clash", # 输出格式为Clash (
|
| 126 |
-
"--
|
| 127 |
"--output", self.config_path, # 输出文件
|
| 128 |
"--include-remarks", ".*" # 包含所有节点
|
| 129 |
]
|
|
|
|
| 122 |
cmd = [
|
| 123 |
self.subconverter_path,
|
| 124 |
"-g", # 生成配置文件
|
| 125 |
+
"--target", "clash", # 输出格式为Clash (修正为 --target)
|
| 126 |
+
"--url", input_file, # 修正为 --url 参数
|
| 127 |
"--output", self.config_path, # 输出文件
|
| 128 |
"--include-remarks", ".*" # 包含所有节点
|
| 129 |
]
|
entrypoint.sh
CHANGED
|
@@ -2,6 +2,46 @@
|
|
| 2 |
# Exit immediately if a command exits with a non-zero status.
|
| 3 |
set -e
|
| 4 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 5 |
# 输出基本信息
|
| 6 |
echo "=========================="
|
| 7 |
echo " Simple Clash Relay"
|
|
@@ -17,18 +57,13 @@ echo "SUB_URL: [hidden]"
|
|
| 17 |
echo "API_KEY: [hidden]"
|
| 18 |
|
| 19 |
# 检查必要的环境变量
|
| 20 |
-
if [ -z "$SUB_URL" ]; then
|
| 21 |
-
echo "ERROR: Required environment variable SUB_URL is not set!"
|
| 22 |
-
exit 1
|
| 23 |
-
fi
|
| 24 |
-
|
| 25 |
if [ -z "$API_KEY" ]; then
|
| 26 |
echo "WARNING: API_KEY is not set. Using default value (insecure)!"
|
| 27 |
export API_KEY="changeme"
|
| 28 |
fi
|
| 29 |
|
| 30 |
# 启动Flask应用
|
| 31 |
-
echo "Starting Flask application
|
| 32 |
|
| 33 |
# 使用gunicorn启动Flask应用(生产环境推荐)
|
| 34 |
# 如果WORKER_COUNT未设置,使用CPU核心数+1的worker数量
|
|
|
|
| 2 |
# Exit immediately if a command exits with a non-zero status.
|
| 3 |
set -e
|
| 4 |
|
| 5 |
+
# 设置颜色输出
|
| 6 |
+
RED='\033[0;31m'
|
| 7 |
+
GREEN='\033[0;32m'
|
| 8 |
+
YELLOW='\033[1;33m'
|
| 9 |
+
NC='\033[0m' # No Color
|
| 10 |
+
|
| 11 |
+
echo "${GREEN}Starting Simple Clash Relay...${NC}"
|
| 12 |
+
|
| 13 |
+
# 确保数据目录存在并设置权限
|
| 14 |
+
mkdir -p /app/data
|
| 15 |
+
chmod -R 777 /app/data
|
| 16 |
+
|
| 17 |
+
# 确保subconverter有执行权限
|
| 18 |
+
chmod +x /app/subconverter/subconverter
|
| 19 |
+
|
| 20 |
+
# 确保Clash Core有执行权限
|
| 21 |
+
if [ -f "/app/clash_core/clash.meta-linux-amd64" ]; then
|
| 22 |
+
chmod +x /app/clash_core/clash.meta-linux-amd64
|
| 23 |
+
echo "${GREEN}Set executable permission for Clash Meta${NC}"
|
| 24 |
+
else
|
| 25 |
+
echo "${RED}Error: Clash Core executable not found!${NC}"
|
| 26 |
+
exit 1
|
| 27 |
+
fi
|
| 28 |
+
|
| 29 |
+
# 加载环境变量
|
| 30 |
+
if [ -f ".env" ]; then
|
| 31 |
+
echo "${GREEN}Loading environment variables from .env file...${NC}"
|
| 32 |
+
export $(grep -v '^#' .env | xargs -d '\n')
|
| 33 |
+
fi
|
| 34 |
+
|
| 35 |
+
# 检查必要的环境变量
|
| 36 |
+
if [ -z "$SUB_URL" ]; then
|
| 37 |
+
echo "${RED}Error: SUB_URL environment variable is not set!${NC}"
|
| 38 |
+
exit 1
|
| 39 |
+
fi
|
| 40 |
+
|
| 41 |
+
# 设置默认端口
|
| 42 |
+
export FLASK_PORT=${FLASK_PORT:-7860}
|
| 43 |
+
echo "${GREEN}Flask will listen on port ${FLASK_PORT}${NC}"
|
| 44 |
+
|
| 45 |
# 输出基本信息
|
| 46 |
echo "=========================="
|
| 47 |
echo " Simple Clash Relay"
|
|
|
|
| 57 |
echo "API_KEY: [hidden]"
|
| 58 |
|
| 59 |
# 检查必要的环境变量
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
if [ -z "$API_KEY" ]; then
|
| 61 |
echo "WARNING: API_KEY is not set. Using default value (insecure)!"
|
| 62 |
export API_KEY="changeme"
|
| 63 |
fi
|
| 64 |
|
| 65 |
# 启动Flask应用
|
| 66 |
+
echo "${GREEN}Starting Flask application...${NC}"
|
| 67 |
|
| 68 |
# 使用gunicorn启动Flask应用(生产环境推荐)
|
| 69 |
# 如果WORKER_COUNT未设置,使用CPU核心数+1的worker数量
|