Spaces:
Paused
Paused
| # 调试模式 | |
| set -x | |
| # 添加诊断函数 | |
| check_target_server() { | |
| local url="$1" | |
| local host="${url#*://}" | |
| host="${host%%/*}" | |
| echo "========== 网络诊断 ==========" | |
| echo "- 检查目标主机: $host" | |
| # 尝试解析主机名 | |
| if host "$host" > /dev/null 2>&1; then | |
| ip=$(host "$host" | grep "has address" | head -1 | awk '{print $4}') | |
| echo "- 主机解析成功: $host -> $ip" | |
| else | |
| echo "- 警告: 无法解析主机名 $host" | |
| fi | |
| # 尝试 ping 目标主机 | |
| if ping -c 1 -W 2 "$host" > /dev/null 2>&1; then | |
| echo "- Ping 测试成功" | |
| else | |
| echo "- 警告: Ping 测试失败 (可能被防火墙阻止)" | |
| fi | |
| # 尝试 TCP 连接到 443 端口 | |
| if nc -z -w2 "$host" 443 > /dev/null 2>&1; then | |
| echo "- TCP 连接成功 (443端口)" | |
| else | |
| echo "- 警告: 无法连接到 $host:443" | |
| fi | |
| # 尝试 TCP 连接到 80 端口 | |
| if nc -z -w2 "$host" 80 > /dev/null 2>&1; then | |
| echo "- TCP 连接成功 (80端口)" | |
| else | |
| echo "- 警告: 无法连接到 $host:80" | |
| fi | |
| # 检查是否与当前主机相同 | |
| current_host=$(hostname -f 2>/dev/null || hostname) | |
| if [[ "$host" == *"$current_host"* || "$current_host" == *"$host"* ]]; then | |
| echo "- 严重错误: 目标主机似乎是当前主机自身,这将导致循环代理!" | |
| echo "- 当前主机: $current_host" | |
| echo "- 目标主机: $host" | |
| echo "- 请检查环境变量 URL 是否设置正确" | |
| fi | |
| echo "==============================" | |
| } | |
| # 显示欢迎信息 | |
| echo "======================================" | |
| echo " WebSocket Proxy Converter (by gost)" | |
| echo "======================================" | |
| echo "Starting service at port 7860..." | |
| # 显示环境变量调试信息 | |
| echo "环境变量:" | |
| echo "- URL = $URL" | |
| echo "- TARGET_WSPROXY_URL = $TARGET_WSPROXY_URL" | |
| echo "- HOSTNAME = $(hostname)" | |
| # 检查目标 URL 是否已设置(兼容两种环境变量名) | |
| if [ -n "$URL" ]; then | |
| # 用户设置了 URL 环境变量(Hugging Face Secret) | |
| TARGET_BASE_URL="$URL" | |
| echo "使用 URL 环境变量: $TARGET_BASE_URL" | |
| elif [ -n "$TARGET_WSPROXY_URL" ]; then | |
| # 用户直接设置了完整的 WebSocket URL | |
| TARGET_BASE_URL="$TARGET_WSPROXY_URL" | |
| echo "使用 TARGET_WSPROXY_URL 环境变量: $TARGET_BASE_URL" | |
| else | |
| echo "Error: Neither URL nor TARGET_WSPROXY_URL environment variable is set." | |
| echo "Please set URL to your first Space URL, like: https://your-first-space.hf.space" | |
| exit 1 | |
| fi | |
| # 检查是否已经包含 /wsproxy 路径 | |
| if [[ "$TARGET_BASE_URL" != */wsproxy ]]; then | |
| # 添加 /wsproxy 路径 | |
| TARGET_BASE_URL="${TARGET_BASE_URL}/wsproxy" | |
| echo "添加 /wsproxy 路径: $TARGET_BASE_URL" | |
| fi | |
| # 检查是否需要转换 https:// 到 wss:// 或 http:// 到 ws:// | |
| if [[ "$TARGET_BASE_URL" == https://* ]]; then | |
| # 替换 https:// 为 wss:// | |
| TARGET_WSPROXY_URL="${TARGET_BASE_URL/https:\/\//wss:\/\/}" | |
| echo "转换 HTTPS 到 WSS: $TARGET_WSPROXY_URL" | |
| elif [[ "$TARGET_BASE_URL" == http://* ]]; then | |
| # 替换 http:// 为 ws:// | |
| TARGET_WSPROXY_URL="${TARGET_BASE_URL/http:\/\//ws:\/\/}" | |
| echo "转换 HTTP 到 WS: $TARGET_WSPROXY_URL" | |
| else | |
| # 假设已经是正确的 WebSocket URL | |
| TARGET_WSPROXY_URL="$TARGET_BASE_URL" | |
| echo "使用原始 URL (未转换): $TARGET_WSPROXY_URL" | |
| fi | |
| echo "最终目标 WebSocket 代理: $TARGET_WSPROXY_URL" | |
| # 执行网络诊断 | |
| check_target_server "$TARGET_BASE_URL" | |
| # 创建状态页面目录 (使用 /tmp) | |
| HTML_DIR="/tmp/html" | |
| mkdir -p "$HTML_DIR" | |
| if [ $? -ne 0 ]; then | |
| echo "Error: Failed to create directory $HTML_DIR" | |
| exit 1 | |
| fi | |
| # 创建状态页面文件 (写入 /tmp/html) | |
| HTML_FILE="$HTML_DIR/index.html" | |
| cat > "$HTML_FILE" << EOF | |
| <!DOCTYPE html> | |
| <html> | |
| <head> | |
| <title>Proxy Converter Status</title> | |
| <style> | |
| body { | |
| font-family: Arial, sans-serif; | |
| max-width: 800px; | |
| margin: 0 auto; | |
| padding: 20px; | |
| line-height: 1.6; | |
| } | |
| .status { | |
| padding: 15px; | |
| background-color: #d4edda; | |
| border-radius: 5px; | |
| color: #155724; | |
| margin: 20px 0; | |
| border-left: 4px solid #28a745; | |
| } | |
| h1 { | |
| color: #333; | |
| border-bottom: 1px solid #eee; | |
| padding-bottom: 10px; | |
| } | |
| code { | |
| background: #f4f4f4; | |
| padding: 2px 5px; | |
| border-radius: 3px; | |
| } | |
| .info { | |
| background-color: #e9f5ff; | |
| border-left: 4px solid #0088ff; | |
| padding: 15px; | |
| margin: 20px 0; | |
| border-radius: 5px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <h1>WebSocket 代理转换器状态</h1> | |
| <div class="status"> | |
| <strong>状态:</strong> 代理转换器正在运行 | |
| </div> | |
| <div class="info"> | |
| <h3>代理信息:</h3> | |
| <ul> | |
| <li><strong>HTTP 代理监听内部端口:</strong> <code>7860</code></li> | |
| <li><strong>目标 WebSocket 代理:</strong> <code>${TARGET_WSPROXY_URL}</code></li> | |
| <li><strong>源自URL:</strong> <code>${TARGET_BASE_URL}</code></li> | |
| </ul> | |
| </div> | |
| <h3>使用说明</h3> | |
| <p>将您的应用配置为使用此 Space 的地址作为 HTTP 代理:</p> | |
| <ul> | |
| <li><strong>主机:</strong> <code>$(hostname)</code> 或 <code>您的Space地址.hf.space</code></li> | |
| <li><strong>端口:</strong> <code>443</code> (推荐, HTTPS) 或 <code>80</code> (HTTP)</li> | |
| <li><strong>类型:</strong> <code>HTTP / HTTPS</code></li> | |
| </ul> | |
| <p><em>状态页面 (端口 7861) 每30秒自动刷新</em></p> | |
| <script> | |
| setTimeout(function() { | |
| location.reload(); | |
| }, 30000); | |
| </script> | |
| </body> | |
| </html> | |
| EOF | |
| if [ $? -ne 0 ]; then | |
| echo "Error: Failed to write to $HTML_FILE" | |
| exit 1 | |
| fi | |
| # 设置 gost 日志级别 (info, warn, error, debug, fatal) | |
| # LOG_LEVEL="warn" # 注释掉,因为 gost v2.11.5 不支持 -loglevel | |
| # --- curl 内部测试 (AFTER gost start,现在测试 SOCKS5) --- | |
| echo "====== 开始内部 Curl 测试 (Gost将启动为SOCKS5) ======" | |
| INTERNAL_PROXY_URL="socks5://127.0.0.1:7860" # 使用 SOCKS5 | |
| TEST_TARGET="https://httpbin.org/ip" | |
| echo "测试代理: $INTERNAL_PROXY_URL -> $TEST_TARGET" | |
| # curl 对 SOCKS5 的支持可能需要 socks5h 以便代理服务器解析域名 | |
| curl -v -k --socks5-hostname "$INTERNAL_PROXY_URL" "$TEST_TARGET" --connect-timeout 15 | |
| if [ $? -eq 0 ]; then | |
| echo "内部 Curl 测试成功 (Gost已启动为SOCKS5)" | |
| else | |
| echo "内部 Curl 测试失败 (Gost已启动为SOCKS5) (退出码 $?)" | |
| fi | |
| echo "====== 结束内部 Curl 测试 (Gost已启动为SOCKS5) ======" | |
| # --- 创建健康检查文件 --- | |
| # 健康检查服务仍然使用HTTP,因为它只检查端口是否开放 | |
| mkdir -p /tmp/health | |
| echo "OK" > /tmp/health/healthz | |
| cd /tmp/health && python3 -m http.server 7862 & | |
| HEALTH_PID=$! | |
| # --- 启动gost (改为监听 SOCKS5) --- | |
| echo "启动gost SOCKS5 代理 (监听 7860,转发到 $TARGET_WSPROXY_URL)..." | |
| /usr/local/bin/gost -L socks5://:7860 -F "$TARGET_WSPROXY_URL" -D & | |
| GOST_PID=$! | |
| echo "Gost PID: $GOST_PID" | |
| echo "等待5秒让gost完全启动..." | |
| sleep 5 | |
| # --- curl 内部测试 (AFTER SOCKS5 gost start) --- | |
| echo "====== 再次运行内部 Curl 测试 (Gost SOCKS5已启动) ======" | |
| curl -v -k --socks5-hostname "$INTERNAL_PROXY_URL" "$TEST_TARGET" --connect-timeout 15 | |
| if [ $? -eq 0 ]; then | |
| echo "内部 Curl SOCKS5 测试成功 (Gost已启动)" | |
| else | |
| echo "内部 Curl SOCKS5 测试失败 (Gost已启动) (退出码 $?)" | |
| fi | |
| echo "====== 结束内部 Curl SOCKS5 测试 (Gost已启动) ======" | |
| # --- 启动状态页面服务 (改为监听7861) --- | |
| # 确保状态页面监听不同端口 | |
| HTML_DIR="/tmp/html" | |
| echo "Starting status page server (port 7861)..." | |
| (cd "$HTML_DIR" && python3 -m http.server 7861) & | |
| STATUS_PID=$! | |
| sleep 1 | |
| # --- 进程检查 --- | |
| echo "Checking if gost process (PID: $GOST_PID) started..." | |
| if ! kill -0 $GOST_PID > /dev/null 2>&1; then | |
| echo "Error: Failed to start or find gost process (PID: $GOST_PID). Exiting." | |
| exit 1 | |
| fi | |
| echo "Checking if status page server (PID: $STATUS_PID) started..." | |
| if ! kill -0 $STATUS_PID > /dev/null 2>&1; then | |
| echo "Warning: Failed to start or find status page server (PID: $STATUS_PID). Status page might be unavailable." | |
| fi | |
| echo "Checking if health check server (PID: $HEALTH_PID) started..." | |
| if ! kill -0 $HEALTH_PID > /dev/null 2>&1; then | |
| echo "Warning: Failed to start or find health check server (PID: $HEALTH_PID). Health checks might fail." | |
| fi | |
| # --- 运行信息 --- | |
| echo "Proxy converter is running..." | |
| echo "- Main SOCKS5 proxy listening internally at port 7860" | |
| echo "- Status page server running internally at port 7861" | |
| echo "- Health check server running internally at port 7862" | |
| echo "- Connected to target WebSocket: $TARGET_WSPROXY_URL" | |
| # --- 信号处理与等待 --- | |
| trap "echo 'Shutting down...'; kill $GOST_PID $STATUS_PID $HEALTH_PID; exit" SIGINT SIGTERM | |
| # 等待 gost 进程结束 (主服务进程) | |
| wait $GOST_PID | |
| EXIT_CODE=$? | |
| echo "Gost process exited with code $EXIT_CODE." | |
| # 清理后台进程 | |
| kill $STATUS_PID $HEALTH_PID > /dev/null 2>&1 | |
| exit $EXIT_CODE |