File size: 3,936 Bytes
de0e55d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
#!/usr/bin/env bash
# ============================================================================
# tunnel_api.sh — 为 Spark API (默认8080) 开 aitun.cc 公网隧道
# 位置: /content/drive/MyDrive/spark-t4/tunnel_api.sh
#
# 原理: 直接运行 aitun-client 二进制,并用独立的 HOME (= /root/.aitun-api)
#       注册,完全不触碰现有 Flask 桥接隧道的 /root/.aitun 配置,
#       两隧道互不影响。免费模式自动分配隧道码和公网 URL。
#
# 用法:
#   bash tunnel_api.sh start    # 开隧道并打印公网 URL(约10~20秒)
#   bash tunnel_api.sh status
#   bash tunnel_api.sh stop
#   自定义: PORT=8080 bash tunnel_api.sh start
# ============================================================================
set -euo pipefail

PORT="${PORT:-8080}"
CLIENT_BIN="/usr/local/lib/python3.13/dist-packages/aitun/bin/aitun-client-linux-amd64"
API_HOME="/root/.aitun-api"                # 独立配置目录,保护桥接隧道
LOG_FILE="/content/aitun-api-tunnel.log"
PID_FILE="/content/aitun-api-tunnel.pid"

GREEN='\033[0;32m'; YELLOW='\033[1;33m'; RED='\033[0;31m'; CYAN='\033[0;36m'; NC='\033[0m'
info() { echo -e "${GREEN}[隧道]${NC} $*"; }
fail() { echo -e "${RED}[隧道]${NC} $*"; exit 1; }

[[ -x "$CLIENT_BIN" ]] || fail "未找到 aitun 客户端: $CLIENT_BIN (本机需已安装 aitun)"

extract_url() {
    grep -oE "https://aitun\.cc/[A-Za-z0-9]+" "$LOG_FILE" 2>/dev/null | tail -1
}

do_start() {
    do_stop 2>/dev/null || true
    mkdir -p "$API_HOME"
    info "启动隧道 (本地 :$PORT → 公网)..."
    HOME="$API_HOME" nohup "$CLIENT_BIN" -s aitun.cc:6639 -p "$PORT" \
        > "$LOG_FILE" 2>&1 &
    echo $! > "$PID_FILE"

    for i in $(seq 1 12); do
        sleep 5
        URL="$(extract_url)"
        if [[ -n "$URL" ]]; then
            kill -0 "$(cat "$PID_FILE")" 2>/dev/null || fail "隧道进程退出,日志: $(tail -10 "$LOG_FILE")"
            info "隧道已建立!"
            echo -e "${CYAN}──────────────────────────────────────────────────${NC}"
            echo -e "  公网 API:  $URL/v1/chat/completions"
            echo -e "  健康检查:  $URL/health"
            echo -e "  模型列表:  $URL/v1/models"
            if [[ -s "/content/drive/MyDrive/spark-t4/.api_key" ]]; then
                echo -e "  API Key:   $(cat /content/drive/MyDrive/spark-t4/.api_key)"
                echo -e "  调用时带:  Authorization: Bearer <API Key>"
            fi
            echo -e "${CYAN}──────────────────────────────────────────────────${NC}"
            echo -e "  curl 示例:"
            echo -e "  curl -N $URL/v1/chat/completions \\"
            echo -e "    -H 'Content-Type: application/json' \\"
            if [[ -s "/content/drive/MyDrive/spark-t4/.api_key" ]]; then
                echo -e "    -H \"Authorization: Bearer \$(cat /content/drive/MyDrive/spark-t4/.api_key)\" \\"
            fi
            echo -e "    -d '{\"messages\":[{\"role\":\"user\",\"content\":\"你好\"}],\"stream\":true}'"
            return 0
        fi
    done
    fail "60 秒未取得公网 URL,日志: $(tail -15 "$LOG_FILE")"
}

do_stop() {
    if [[ -f "$PID_FILE" ]] && kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then
        kill "$(cat "$PID_FILE")" && info "隧道已停止 (PID $(cat "$PID_FILE"))"
    fi
    rm -f "$PID_FILE"
}

do_status() {
    URL="$(extract_url)"
    if [[ -f "$PID_FILE" ]] && kill -0 "$(cat "$PID_FILE")" 2>/dev/null; then
        info "隧道运行中 (PID $(cat "$PID_FILE"))  URL: ${URL:-未知}"
    else
        echo "隧道未运行"
    fi
}

case "${1:-help}" in
    start)  do_start ;;
    stop)   do_stop ;;
    status) do_status ;;
    *)      grep '^#   ' "$0" | sed 's/^#   //' ;;
esac