frps-install-1.1.sh

脚本
47.00 KB 修改于 2026-08-17
← 上一份下一份 →
#!/bin/bash

# 🎨 颜色定义
red() { echo -e "\033[0;31m$1\033[0m"; }
green() { echo -e "\033[0;32m$1\033[0m"; }
yellow() { echo -e "\033[0;33m$1\033[0m"; }
blue() { echo -e "\033[0;34m$1\033[0m"; }
purple() { echo -e "\033[0;35m$1\033[0m"; }
cyan() { echo -e "\033[0;36m$1\033[0m"; }

# 📌 系统变量
INSTALL_DIR="/etc/LunovaFrps"
CONFIG_FILE="$INSTALL_DIR/frps.toml"
SERVICE_NAME="LunovaFrps.service"
SERVICE_FILE="/etc/systemd/system/$SERVICE_NAME"
SCRIPT_VERSION="1.2.0"
CURRENT_VERSION_FILE="$INSTALL_DIR/version.txt"
DOWNLOAD_RETRIES=3
DOWNLOAD_TIMEOUT=180
MIN_FILE_SIZE=1000000

# 🌟 显示标题
show_header() {
    clear
    echo ""
    purple "=================================================="
    purple "            Lunanova Frps 管理脚本"
    purple "                版本: $SCRIPT_VERSION"
    purple "=================================================="
    echo ""
}

# 🌟 检查是否为 root 用户
check_root() {
    if [[ $(id -u) -ne 0 ]]; then
        red "❌ 请使用 root 用户运行此脚本!"
        exit 1
    fi
}

# 🔍 检查系统类型
check_os_type() {
    if [[ -f /etc/redhat-release ]]; then
        echo "centos"
    elif [[ -f /etc/debian_version ]]; then
        echo "debian"
    elif [[ -f /etc/arch-release ]]; then
        echo "arch"
    elif [[ -f /etc/alpine-release ]]; then
        echo "alpine"
    else
        echo "unknown"
    fi
}

# 🔍 检查并安装必要工具
check_dependencies() {
    yellow "🛠️ 检查必要工具..."
    
    local os_type=$(check_os_type)
    
    # 基础工具列表(所有系统通用)
    local base_tools=("curl" "tar" "unzip")
    
    case $os_type in
        centos|rhel|fedora)
            # CentOS/RHEL/Fedora 系统
            local packages=("curl" "tar" "unzip" "wget" "gzip" "bzip2" "xz")
            yellow "📦 检测到 CentOS/RHEL 系统"
            
            # 检查EPEL仓库
            if ! rpm -q epel-release &>/dev/null; then
                yellow "安装 EPEL 仓库..."
                yum install -y epel-release
            fi
            
            # 更新仓库缓存
            yum makecache fast
            
            # 安装缺失的包
            local install_list=()
            for pkg in "${packages[@]}"; do
                if ! rpm -q ${pkg} &>/dev/null; then
                    install_list+=("$pkg")
                fi
            done
            
            if [[ ${#install_list[@]} -gt 0 ]]; then
                yellow "安装缺失包: ${install_list[*]}"
                yum install -y "${install_list[@]}" || {
                    red "❌ 安装包失败,尝试继续..."
                }
            fi
            ;;
            
        debian|ubuntu)
            # Debian/Ubuntu 系统
            local packages=("curl" "tar" "unzip" "wget" "gzip" "bzip2" "xz-utils")
            yellow "📦 检测到 Debian/Ubuntu 系统"
            
            apt update
            
            local install_list=()
            for pkg in "${packages[@]}"; do
                if ! dpkg -l | grep -q "^ii  ${pkg} "; then
                    install_list+=("$pkg")
                fi
            done
            
            if [[ ${#install_list[@]} -gt 0 ]]; then
                yellow "安装缺失包: ${install_list[*]}"
                apt install -y "${install_list[@]}" || {
                    red "❌ 安装包失败,尝试继续..."
                }
            fi
            ;;
            
        arch)
            # Arch Linux 系统
            yellow "📦 检测到 Arch Linux 系统"
            pacman -Syu --noconfirm curl tar unzip wget gzip bzip2 xz
            ;;
            
        alpine)
            # Alpine Linux 系统
            yellow "📦 检测到 Alpine Linux 系统"
            apk add curl tar unzip wget gzip bzip2 xz
            ;;
            
        *)
            yellow "⚠️ 未知系统类型,尝试安装基本工具..."
            # 尝试通用安装方法
            for tool in "${base_tools[@]}"; do
                if ! command -v $tool &>/dev/null; then
                    yellow "尝试安装 $tool..."
                    if command -v apt-get &>/dev/null; then
                        apt-get install -y $tool
                    elif command -v yum &>/dev/null; then
                        yum install -y $tool
                    elif command -v dnf &>/dev/null; then
                        dnf install -y $tool
                    elif command -v pacman &>/dev/null; then
                        pacman -S --noconfirm $tool
                    elif command -v apk &>/dev/null; then
                        apk add $tool
                    fi
                fi
            done
            ;;
    esac
    
    # 最后检查必要的命令
    local essential_tools=("curl" "tar")
    local missing_essential=()
    
    for tool in "${essential_tools[@]}"; do
        if ! command -v $tool &>/dev/null; then
            missing_essential+=("$tool")
        fi
    done
    
    if [[ ${#missing_essential[@]} -gt 0 ]]; then
        red "❌ 缺少必要工具: ${missing_essential[*]}"
        echo ""
        yellow "请手动安装以下工具后重试:"
        for tool in "${missing_essential[@]}"; do
            case $os_type in
                centos) echo "  yum install $tool" ;;
                debian) echo "  apt install $tool" ;;
                arch)   echo "  pacman -S $tool" ;;
                alpine) echo "  apk add $tool" ;;
                *)      echo "  请安装 $tool" ;;
            esac
        done
        return 1
    fi
    
    green "✅ 所有必要工具已安装"
    return 0
}

# 🎲 生成随机字符串
generate_random_string() {
    LC_ALL=C tr -dc 'a-zA-Z0-9' </dev/urandom | head -c ${1:-16}
}

# 🛠 检测系统架构
check_system_arch() {
    case $(uname -m) in
        x86_64)  echo "amd64" ;;
        aarch64) echo "arm64" ;;
        armv7l)  echo "arm" ;;
        armv6l)  echo "arm" ;;
        i386|i686) echo "386" ;;
        *) 
            red "❌ 不支持的系统架构:$(uname -m)"
            return 1
            ;;
    esac
    return 0
}

# 📦 获取最新版本号(通过尝试下载文件)
get_latest_version() {
    local arch=$(check_system_arch)
    
    # 候选版本列表(从新到旧)
    local candidate_versions=("1.2.0" "1.1.7" "1.1.4" "1.1.3" "1.1.1" "1.1.0" "1.0.0")
    
    for version in "${candidate_versions[@]}"; do
        local filename="StellarCore_${version}_linux_${arch}.tar.gz"
        local test_url="https://resources.xplk.cn/downloads/frps/${version}/${filename}"
        
        # 静默测试文件是否存在
        if command -v curl &>/dev/null; then
            if curl -s --head --connect-timeout 5 --max-time 10 "$test_url" 2>/dev/null | head -1 | grep -q "200"; then
                echo "$version"
                return 0
            fi
        elif command -v wget &>/dev/null; then
            if wget -q --spider --timeout=5 "$test_url" 2>/dev/null; then
                echo "$version"
                return 0
            fi
        fi
    done
    
    # 如果都失败,使用默认版本 1.1.6
    echo "1.2.0"
    return 1
}

# 🔄 智能下载函数(支持curl和wget,带重试)
smart_download() {
    local url="$1"
    local output="$2"
    local retry_count=${3:-$DOWNLOAD_RETRIES}
    local timeout=${4:-$DOWNLOAD_TIMEOUT}
    
    local download_method=""
    local user_agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
    
    # 检查可用的下载工具
    if command -v curl &>/dev/null; then
        download_method="curl"
    elif command -v wget &>/dev/null; then
        download_method="wget"
    else
        red "❌ 没有可用的下载工具(curl/wget)"
        return 1
    fi
    
    yellow "📡 使用 $download_method 下载: $url"
    yellow "📁 保存到: $output"
    
    # 创建目录(如果不存在)
    mkdir -p "$(dirname "$output")"
    
    local attempt=1
    local success=false
    
    while [[ $attempt -le $retry_count ]] && [[ $success == false ]]; do
        echo ""
        cyan "🔄 尝试 $attempt/$retry_count..."
        
        # 清理可能存在的临时文件
        rm -f "$output.tmp" 2>/dev/null
        
        case $download_method in
            curl)
                # 使用curl下载(带进度条和详细输出)
                if curl -L --connect-timeout 30 --max-time $timeout \
                    --retry 2 --retry-delay 3 \
                    --user-agent "$user_agent" \
                    --fail --show-error \
                    --progress-bar "$url" -o "$output.tmp"; then
                    
                    if [[ -f "$output.tmp" ]]; then
                        # 检查文件大小
                        local file_size=$(wc -c < "$output.tmp" 2>/dev/null || echo 0)
                        yellow "📊 下载大小: $file_size 字节"
                        
                        if [[ $file_size -ge $MIN_FILE_SIZE ]]; then
                            mv "$output.tmp" "$output"
                            green "✅ 下载成功 ($file_size 字节)"
                            success=true
                        else
                            yellow "⚠️ 文件大小不足,可能下载不完整"
                            rm -f "$output.tmp"
                        fi
                    else
                        yellow "⚠️ 临时文件未创建"
                    fi
                else
                    yellow "⚠️ curl下载失败"
                    rm -f "$output.tmp" 2>/dev/null
                fi
                ;;
                
            wget)
                # 使用wget下载
                if wget --timeout=$timeout --tries=2 \
                    --user-agent="$user_agent" \
                    --show-progress -q "$url" -O "$output.tmp"; then
                    
                    if [[ -f "$output.tmp" ]]; then
                        local file_size=$(wc -c < "$output.tmp" 2>/dev/null || echo 0)
                        yellow "📊 下载大小: $file_size 字节"
                        
                        if [[ $file_size -ge $MIN_FILE_SIZE ]]; then
                            mv "$output.tmp" "$output"
                            green "✅ 下载成功 ($file_size 字节)"
                            success=true
                        else
                            yellow "⚠️ 文件大小不足,可能下载不完整"
                            rm -f "$output.tmp"
                        fi
                    fi
                else
                    yellow "⚠️ wget下载失败"
                    rm -f "$output.tmp" 2>/dev/null
                fi
                ;;
        esac
        
        if [[ $success == false ]] && [[ $attempt -lt $retry_count ]]; then
            local wait_time=$((attempt * 2))
            yellow "⏳ $wait_time秒后重试..."
            sleep $wait_time
        fi
        
        attempt=$((attempt + 1))
    done
    
    if [[ $success == true ]]; then
        # 最终验证文件
        if [[ -f "$output" ]]; then
            local final_size=$(wc -c < "$output" 2>/dev/null || echo 0)
            local file_type=$(file "$output" 2>/dev/null || echo "未知")
            
            echo ""
            green "📋 文件验证:"
            green "   大小: $final_size 字节"
            green "   类型: $file_type"
            
            if [[ $final_size -ge $MIN_FILE_SIZE ]]; then
                return 0
            else
                red "❌ 最终文件大小验证失败"
                rm -f "$output"
                return 1
            fi
        fi
    fi
    
    red "❌ 下载失败:$url"
    return 1
}

# 🌐 多源下载函数
multi_source_download() {
    local filename="$1"
    local output_dir="$2"
    local target_version="${3:-$(get_latest_version)}"
    local output_file="$output_dir/$filename"
    
    # 确保版本号是纯数字格式
    target_version=$(echo "$target_version" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -1)
    
    if [[ -z "$target_version" ]]; then
        target_version="1.2.0"
    fi
    
    # 下载源列表
    local download_sources=(
        "https://resources.xplk.cn/downloads/frps/${target_version}/${filename}"
    )
    
    echo ""
    blue "📡 目标版本: $target_version"
    blue "📦 文件名: $filename"
    echo ""
    
    # 尝试所有下载源
    for url in "${download_sources[@]}"; do
        cyan "📥 尝试下载: $url"
        if smart_download "$url" "$output_file"; then
            return 0
        fi
        echo ""
        sleep 1
    done
    
    red "❌ 所有下载源都失败!"
    return 1
}

# 📂 解压函数(支持多种格式)
try_extract() {
    local archive=$1
    local target_dir=$2
    
    yellow "📂 正在解压 $archive..."
    
    # 检查文件是否存在
    if [[ ! -f "$archive" ]]; then
        red "❌ 文件不存在: $archive"
        return 1
    fi
    
    # 检查文件大小
    local file_size=$(wc -c < "$archive" 2>/dev/null || echo 0)
    if [[ $file_size -lt $MIN_FILE_SIZE ]]; then
        red "❌ 文件太小可能已损坏: ${file_size}字节"
        return 1
    fi
    
    # 显示文件信息
    green "📋 文件信息:"
    file "$archive"
    echo ""
    
    # 创建目标目录
    mkdir -p "$target_dir"
    
    # 尝试不同解压方式
    echo "🔄 尝试解压..."
    
    # 定义解压函数数组
    local extract_commands=(
        "tar -zxf '$archive' -C '$target_dir' 2>/dev/null"        # tar.gz
        "tar -Jxf '$archive' -C '$target_dir' 2>/dev/null"        # tar.xz
        "tar -jxf '$archive' -C '$target_dir' 2>/dev/null"        # tar.bz2
        "tar -xf '$archive' -C '$target_dir' 2>/dev/null"         # tar
        "unzip -q '$archive' -d '$target_dir' 2>/dev/null"        # zip
        "gunzip -c '$archive' | tar -xf - -C '$target_dir' 2>/dev/null"  # gzip流
        "xz -dc '$archive' | tar -xf - -C '$target_dir' 2>/dev/null"     # xz流
        "bzip2 -dc '$archive' | tar -xf - -C '$target_dir' 2>/dev/null"  # bzip2流
    )
    
    local extract_names=(
        "gzip压缩包"
        "xz压缩包"
        "bzip2压缩包"
        "普通tar包"
        "zip压缩包"
        "gzip流式解压"
        "xz流式解压"
        "bzip2流式解压"
    )
    
    local success=false
    
    for i in "${!extract_commands[@]}"; do
        echo -n "尝试 ${extract_names[$i]}... "
        if eval "${extract_commands[$i]}"; then
            green "✅ 成功"
            success=true
            break
        else
            yellow "❌ 失败"
        fi
    done
    
    if [[ $success == false ]]; then
        red "❌ 所有解压方式均失败"
        echo ""
        yellow "📝 诊断信息:"
        echo "文件类型: $(file "$archive")"
        echo "文件大小: $file_size 字节"
        echo ""
        yellow "🔍 查看压缩包内容:"
        if file "$archive" | grep -q "tar archive"; then
            tar -tf "$archive" | head -10
        elif file "$archive" | grep -q "Zip archive"; then
            unzip -l "$archive" 2>/dev/null | head -10
        fi
        echo ""
        return 1
    fi
    
    green "✅ 解压完成"
    yellow "📂 解压目录内容:"
    ls -la "$target_dir/"
    echo ""
    
    return 0
}

# 🛠 下载二进制文件
download_binary() {
    local target_version="${1:-$(get_latest_version)}"
    
    # 获取系统架构并转换为正确的名称
    local arch=$(uname -m)
    local arch_name=""
    
    case $arch in
        x86_64)
            arch_name="amd64"
            ;;
        aarch64)
            arch_name="arm64"
            ;;
        armv7l)
            arch_name="arm"
            ;;
        armv6l)
            arch_name="arm"
            ;;
        i386|i686)
            arch_name="386"
            ;;
        *)
            red "❌ 不支持的系统架构:$arch"
            return 1
            ;;
    esac
    
    # 构建正确的文件名
    local filename="StellarCore_${target_version}_linux_${arch_name}.tar.gz"
    local download_path="/tmp/${filename}"
    
    green "✅ 系统架构:$arch ($arch_name)"
    green "✅ 目标版本:$target_version"
    green "📦 目标文件:$filename"
    echo ""
    
    # 清理旧文件
    rm -f "$download_path" 2>/dev/null
    
    # 使用多源下载函数
    if ! multi_source_download "$filename" "/tmp" "$target_version"; then
        red "❌ 文件下载失败"
        return 1
    fi
    
    # 创建安装目录
    mkdir -p "$INSTALL_DIR"
    
    # 使用解压函数
    if try_extract "$download_path" "$INSTALL_DIR"; then
        # 查找可执行文件
        local found_binary=""
        local executable_files=()
        
        yellow "🔍 查找可执行文件..."
        
        # 查找所有可执行文件
        while IFS= read -r file; do
    if [[ -f "$file" ]] && [[ -x "$file" ]]; then
        local filename_only=$(basename "$file")
        executable_files+=("$filename_only")
        
        # 优先选择 StellarCore(新解压的)
        if [[ "$filename_only" == "StellarCore" ]]; then
            found_binary="$filename_only"
            green "✅ 找到新版本文件: $filename_only"
        # 其次选择 stellarcore
        elif [[ "$filename_only" == "stellarcore" ]]; then
            if [[ -z "$found_binary" ]]; then
                found_binary="$filename_only"
                green "✅ 找到候选文件: $filename_only"
            fi
        # 其他可能的名称
        elif [[ "$filename_only" =~ ^(frps|stellar|frp_|frp-|Frp) ]]; then
            if [[ -z "$found_binary" ]]; then
                found_binary="$filename_only"
                green "✅ 找到候选文件: $filename_only"
            fi
        fi
    fi
done < <(find "$INSTALL_DIR" -maxdepth 1 -type f)
        
        # 如果没找到优先选择的文件,用第一个可执行文件
        if [[ -z "$found_binary" ]] && [[ ${#executable_files[@]} -gt 0 ]]; then
            found_binary="${executable_files[0]}"
            yellow "⚠️ 使用第一个可执行文件: $found_binary"
        fi
        
        if [[ -n "$found_binary" ]]; then
            # 重命名为标准名称
            if [[ "$found_binary" != "stellarcore" ]]; then
                mv "$INSTALL_DIR/$found_binary" "$INSTALL_DIR/stellarcore"
                green "✅ 重命名为: stellarcore"
            fi
            
            chmod +x "$INSTALL_DIR/stellarcore"
            # 保存版本信息
            echo "$target_version" > "$CURRENT_VERSION_FILE"
            
            # 清理临时文件
            rm -f "$download_path"
            
            # 验证二进制文件
            green "✅ 验证可执行文件..."
            if "$INSTALL_DIR/stellarcore" --version 2>&1 | head -1; then
                green "✅ 二进制文件验证成功"
            elif "$INSTALL_DIR/stellarcore" -v 2>&1 | head -1; then
                green "✅ 二进制文件验证成功"
            else
                yellow "⚠️ 无法获取版本信息,但文件可执行"
                echo "📋 文件信息:"
                file "$INSTALL_DIR/stellarcore"
            fi
            
            return 0
        else
            red "❌ 未找到可执行文件"
            yellow "📂 解压目录内容:"
            ls -la "$INSTALL_DIR/"
            rm -f "$download_path"
            return 1
        fi
    else
        rm -f "$download_path"
        return 1
    fi
}

# 📝 生成配置文件
generate_config() {
    green "✨ 正在生成配置文件..."
    local bind_port min_port max_port dash_port dash_user random_pwd enable_http enable_https

    echo ""
    yellow "请输入以下配置信息(按Enter使用默认值)"
    echo ""

    # 配置端口与凭据
    read -p "绑定端口 (默认7000): " bind_port
    bind_port=${bind_port:-7000}
    read -p "最小开放端口范围 (默认20000): " min_port
    min_port=${min_port:-20000}
    read -p "最大开放端口范围 (默认30000): " max_port
    max_port=${max_port:-30000}
    read -p "面板端口 (默认7500): " dash_port
    dash_port=${dash_port:-7500}

    # 配置 HTTP 和 HTTPS 代理
    read -p "启用 HTTP 代理端口 (默认80端口)?[Y/n]: " enable_http
    read -p "启用 HTTPS 代理端口 (默认443端口)?[Y/n]: " enable_https

    # 生成随机凭据
    dash_user="admin"
    random_pwd="password_$(generate_random_string 12)"

    # 写入配置文件
    cat > "$CONFIG_FILE" << EOF
bindPort = $bind_port
allowPorts = [
  { start = $min_port, end = $max_port }
]
webServer.addr = "0.0.0.0"
webServer.port = $dash_port
webServer.user = "$dash_user"
webServer.password = "$random_pwd"
EOF

    # 添加 HTTP 和 HTTPS 代理配置
    [[ "$enable_http" =~ ^[Yy]$ ]] || [[ -z "$enable_http" ]] && echo "vhostHTTPPort = 80" >> "$CONFIG_FILE"
    [[ "$enable_https" =~ ^[Yy]$ ]] || [[ -z "$enable_https" ]] && echo "vhostHTTPSPort = 443" >> "$CONFIG_FILE"

    # 添加 `httpPlugins` 配置
    cat >> "$CONFIG_FILE" << EOF

[[httpPlugins]]
addr = "https://f943f0985186805e44c898cc3aa2ce9a.api.xplk.cn"
path = "/api/v1/proxy/auth"
ops = ["Login", "NewProxy", "CloseProxy"]
EOF

    green "✅ 配置文件已生成:$CONFIG_FILE"
    
    # 显示访问信息
    echo ""
    green "=============================================="
    green "📊 FRPS 配置信息"
    green "=============================================="
    green "管理面板地址: http://服务器IP:$dash_port"
    green "用户名: $dash_user"
    green "密码: $random_pwd"
    green "绑定端口: $bind_port"
    green "端口范围: $min_port - $max_port"
    [[ "$enable_http" =~ ^[Yy]$ ]] || [[ -z "$enable_http" ]] && green "HTTP 代理端口: 80"
    [[ "$enable_https" =~ ^[Yy]$ ]] || [[ -z "$enable_https" ]] && green "HTTPS 代理端口: 443"
    green "配置文件: $CONFIG_FILE"
    green "=============================================="
    yellow "⚠️ 请妥善保存以上信息,特别是密码!"
    echo ""
    
    return 0
}

# 🚀 配置并安装服务
install_service() {
    green "🚀 配置并安装服务..."
    
    # 停止可能存在的服务
    if systemctl is-active --quiet "$SERVICE_NAME"; then
        yellow "发现正在运行的服务,正在停止..."
        systemctl stop "$SERVICE_NAME"
    fi
    
    # 创建 systemd 服务文件
    cat > "$SERVICE_FILE" << EOF
[Unit]
Description=LunovaFrps Server Service
After=network.target

[Service]
Type=simple
User=root
Restart=on-failure
RestartSec=5s
ExecStart=$INSTALL_DIR/stellarcore -c $CONFIG_FILE
WorkingDirectory=$INSTALL_DIR
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF

    systemctl daemon-reload
    systemctl enable "$SERVICE_NAME"
    systemctl start "$SERVICE_NAME"

    # 等待服务启动
    sleep 3
    
    green "🎉 服务安装完成!"
    echo ""
    
    # 检查服务状态
    if systemctl is-active --quiet "$SERVICE_NAME"; then
        green "✅ 服务运行正常!"
        echo ""
        systemctl status "$SERVICE_NAME" --no-pager -l | tail -10
    else
        red "❌ 服务启动失败,请检查日志:"
        journalctl -u "$SERVICE_NAME" -n 20 --no-pager
    fi
    
    echo ""
    yellow "📋 常用管理命令:"
    yellow "启动服务: systemctl start $SERVICE_NAME"
    yellow "停止服务: systemctl stop $SERVICE_NAME"
    yellow "重启服务: systemctl restart $SERVICE_NAME"
    yellow "查看状态: systemctl status $SERVICE_NAME"
    yellow "查看日志: journalctl -u $SERVICE_NAME -f"
    echo ""
    
    return 0
}

# 🔄 更新 FRPS
update_frps() {
    show_header
    blue "🔄 更新 Lunova FRPS"
    echo ""
    
    # 检查是否已安装
    if [[ ! -f "$INSTALL_DIR/stellarcore" ]]; then
        red "❌ 未检测到已安装的 FRPS"
        yellow "请先安装 FRPS"
        sleep 2
        return 1
    fi
    
    # 显示当前版本
    local current_version="未知"
    if [[ -f "$CURRENT_VERSION_FILE" ]]; then
        current_version=$(cat "$CURRENT_VERSION_FILE")
    fi
    green "📌 当前版本: $current_version"
    
    # 获取最新版本
    echo ""
    yellow "🔍 正在检测可用版本..."
    local latest_version=$(get_latest_version)
    green "✅ 找到最新版本: $latest_version"
    echo ""
    
    # 比较版本
    if [[ "$current_version" == "$latest_version" ]]; then
        green "✅ 当前已是最新版本,无需更新"
        echo ""
        read -p "是否要重新安装当前版本?[y/N]: " reinstall
        if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then
            return 0
        fi
    else
        yellow "🆕 发现新版本!"
    fi
    
    # 确认更新
    echo ""
    read -p "确定要更新 FRPS 吗?[y/N]: " confirm
    if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
        yellow "取消更新"
        return 1
    fi
    
    # 备份当前版本
    yellow "📦 正在备份当前版本..."
    local backup_dir="/tmp/LunovaFrps_backup_$(date +%Y%m%d_%H%M%S)"
    mkdir -p "$backup_dir"
    
    if [[ -f "$INSTALL_DIR/stellarcore" ]]; then
        cp "$INSTALL_DIR/stellarcore" "$backup_dir/stellarcore.bak"
        green "✅ 二进制文件已备份到: $backup_dir/stellarcore.bak"
    fi
    
    if [[ -f "$CONFIG_FILE" ]]; then
        cp "$CONFIG_FILE" "$backup_dir/frps.toml.bak"
        green "✅ 配置文件已备份到: $backup_dir/frps.toml.bak"
    fi
    
    # 询问是否保留配置文件
    local keep_config="yes"
    echo ""
    yellow "⚠️ 配置文件处理"
    read -p "是否保留现有的配置文件 frps.toml?[Y/n]: " keep_config
    if [[ "$keep_config" =~ ^[Nn]$ ]]; then
        yellow "将在更新后重新生成配置文件"
    else
        green "✅ 将保留现有配置文件"
    fi
    
    # 停止服务
    yellow "⏸️ 停止服务..."
    if systemctl is-active --quiet "$SERVICE_NAME"; then
        systemctl stop "$SERVICE_NAME"
        green "✅ 服务已停止"
    fi
    
    # 备份旧的二进制文件
    if [[ -f "$INSTALL_DIR/stellarcore" ]]; then
        mv "$INSTALL_DIR/stellarcore" "$INSTALL_DIR/stellarcore.old"
        green "✅ 旧版本已备份"
    fi
    
    # 下载新版本
    echo ""
    yellow "📥 开始下载新版本..."
    if ! download_binary "$latest_version"; then
        red "❌ 新版本下载失败"
        
        # 恢复旧版本
        yellow "🔄 正在恢复旧版本..."
        if [[ -f "$INSTALL_DIR/stellarcore.old" ]]; then
            mv "$INSTALL_DIR/stellarcore.old" "$INSTALL_DIR/stellarcore"
            green "✅ 已恢复旧版本"
        fi
        
        # 恢复配置文件
        if [[ -f "$backup_dir/frps.toml.bak" ]] && [[ ! -f "$CONFIG_FILE" ]]; then
            cp "$backup_dir/frps.toml.bak" "$CONFIG_FILE"
        fi
        
        # 尝试重启服务
        if systemctl start "$SERVICE_NAME" 2>/dev/null; then
            yellow "服务已恢复"
        fi
        
        sleep 2
        return 1
    fi
    
    # 处理配置文件
    if [[ "$keep_config" =~ ^[Nn]$ ]]; then
        # 备份旧配置文件
        if [[ -f "$CONFIG_FILE" ]]; then
            mv "$CONFIG_FILE" "$CONFIG_FILE.old.$(date +%Y%m%d%H%M%S)"
            green "✅ 旧配置文件已备份"
        fi
        
        # 生成新配置文件
        if ! generate_config; then
            red "❌ 配置文件生成失败"
            # 恢复旧配置
            if [[ -f "$CONFIG_FILE.old" ]]; then
                mv "$CONFIG_FILE.old" "$CONFIG_FILE"
                yellow "已恢复旧配置文件"
            fi
            return 1
        fi
    else
        # 检查配置文件兼容性
        if [[ -f "$CONFIG_FILE" ]]; then
            green "✅ 保留现有配置文件: $CONFIG_FILE"
            
            # 简单验证配置文件
            if grep -q "bindPort" "$CONFIG_FILE"; then
                green "✅ 配置文件验证通过"
            else
                yellow "⚠️ 配置文件可能不完整,建议检查"
            fi
        else
            yellow "⚠️ 配置文件不存在,将生成新配置"
            generate_config
        fi
    fi
    
    # 清理旧文件
    if [[ -f "$INSTALL_DIR/stellarcore.old" ]]; then
        rm -f "$INSTALL_DIR/stellarcore.old"
        green "✅ 已清理旧版本备份"
    fi
    
    # 重启服务
    echo ""
    yellow "🔄 正在重启服务..."
    if systemctl restart "$SERVICE_NAME"; then
        sleep 2
        
        if systemctl is-active --quiet "$SERVICE_NAME"; then
            green "✅ 服务启动成功!"
            echo ""
            systemctl status "$SERVICE_NAME" --no-pager -l | head -10
        else
            red "❌ 服务启动失败"
            yellow "查看日志: journalctl -u $SERVICE_NAME -n 20"
        fi
    else
        red "❌ 服务重启失败"
    fi
    
    # 更新完成
    echo ""
    green "=============================================="
    green "🎉 FRPS 更新完成!"
    green "=============================================="
    green "📌 旧版本: $current_version"
    green "📌 新版本: $latest_version"
    
    if [[ "$keep_config" =~ ^[Nn]$ ]]; then
        green "📝 配置文件: 已重新生成"
    else
        green "📝 配置文件: 已保留原配置"
    fi
    
    green "📦 备份目录: $backup_dir"
    green "=============================================="
    
    # 询问是否测试API
    echo ""
    read -p "是否要测试API连接?[Y/n]: " test_api
    if [[ ! "$test_api" =~ ^[Nn]$ ]]; then
        test_api_connection
    fi
    
    echo ""
    yellow "按 Enter 键继续..."
    read
    return 0
}

# 🧪 API连接测试
test_api_connection() {
    local api_url="${1:-https://f943f0985186805e44c898cc3aa2ce9a.api.xplk.cn}"
    local health_endpoint="${api_url}/health"
    local auth_endpoint="${api_url}/api/v1/proxy/auth"
    
    show_header
    blue "🧪 API 连接测试"
    echo ""
    
    # 如果没有提供URL参数,从配置文件读取
    if [[ -z "$1" ]]; then
        if [[ -f "$CONFIG_FILE" ]]; then
            local config_addr=$(grep "^addr" "$CONFIG_FILE" | head -1 | cut -d'"' -f2)
            if [[ -n "$config_addr" ]]; then
                api_url="$config_addr"
                health_endpoint="${api_url}/health"
                auth_endpoint="${api_url}/api/v1/proxy/auth"
                green "📋 使用配置文件中的API地址: $api_url"
            else
                yellow "⚠️ 未在配置文件中找到API地址"
                read -p "请输入要测试的API地址 (例如: https://api.example.com): " custom_url
                if [[ -n "$custom_url" ]]; then
                    api_url="$custom_url"
                    health_endpoint="${api_url}/health"
                    auth_endpoint="${api_url}/api/v1/proxy/auth"
                else
                    red "❌ 未提供API地址"
                    return 1
                fi
            fi
        else
            yellow "⚠️ 配置文件不存在"
            read -p "请输入要测试的API地址 (例如: https://api.example.com): " custom_url
            if [[ -n "$custom_url" ]]; then
                api_url="$custom_url"
                health_endpoint="${api_url}/health"
                auth_endpoint="${api_url}/api/v1/proxy/auth"
            else
                red "❌ 未提供API地址"
                return 1
            fi
        fi
    fi
    
    echo ""
    yellow "🔗 测试端点: ${auth_endpoint}?op=Login&version=0.1.0"
    echo ""
    
    # ========== 1. 测试健康检查端点 ==========
    blue "📊 测试1: 健康检查"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    
    local response=""
    local http_code=""
    local temp_file=$(mktemp)
    
    if command -v curl &>/dev/null; then
        http_code=$(curl -s -o "$temp_file" -w "%{http_code}" \
            --connect-timeout 10 \
            --max-time 30 \
            -H "User-Agent: LunovaFrps-Script/$SCRIPT_VERSION" \
            "$health_endpoint" 2>/dev/null)
        response=$(cat "$temp_file")
    else
        red "❌ 没有可用的HTTP客户端(curl/wget)"
        rm -f "$temp_file"
        return 1
    fi
    
    if [[ "$http_code" == "200" ]]; then
        green "✅ 健康检查通过 (HTTP $http_code)"
    else
        red "❌ 健康检查失败 (HTTP $http_code)"
        rm -f "$temp_file"
        return 1
    fi
    
    rm -f "$temp_file"
    
    # ========== 2. 测试认证请求 ==========
    echo ""
    blue "📊 测试2: 认证端点测试"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    yellow "📝 发送 Login 请求..."
    
    # 生成测试数据(模拟真实客户端)
    local test_run_id=$(generate_random_string 16)
    local test_timestamp=$(date +%s)
    local test_privilege_key=$(generate_random_string 32)
    
    # 构建请求体
    local request_body=$(cat <<EOF
{
  "content": {
    "arch": "$(check_system_arch)",
    "client_address": "127.0.0.1:12345",
    "client_spec": {},
    "metas": {
      "token": "test_token_$(generate_random_string 8)"
    },
    "os": "$(uname -s | tr '[:upper:]' '[:lower:]')",
    "pool_count": 1,
    "privilege_key": "$test_privilege_key",
    "run_id": "$test_run_id",
    "timestamp": $test_timestamp,
    "user": "test_user",
    "version": "0.64.0"
  },
  "op": "Login",
  "version": "0.1.0"
}
EOF
)
    
    # 发送认证请求
    local auth_response_file=$(mktemp)
    local auth_http_code=$(curl -s -o "$auth_response_file" -w "%{http_code}" \
        --connect-timeout 10 \
        --max-time 30 \
        -H "Content-Type: application/json" \
        -H "User-Agent: Go-http-client/1.1" \
        -X POST \
        "${auth_endpoint}?op=Login&version=0.1.0" \
        -d "$request_body" 2>/dev/null)
    
    local auth_response=$(cat "$auth_response_file" 2>/dev/null)
    rm -f "$auth_response_file"
    
    # 显示结果(简化版)
    echo ""
    if [[ "$auth_http_code" == "200" ]]; then
        green "✅ 认证请求成功 (HTTP $auth_http_code)"
        
        # 检查是否返回了预期的响应格式
        if [[ "$auth_response" == *"\"reject\""* ]]; then
            green "✅ API端点工作正常(已收到认证响应)"
        else
            green "✅ API响应正常"
        fi
    else
        red "❌ 认证请求失败 (HTTP $auth_http_code)"
        return 1
    fi
    
    # ========== 3. 性能测试(可选,快速版) ==========
    echo ""
    blue "📊 测试3: 响应速度"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    
    # 快速测试(只测1次)
    local start_time=$(date +%s%N)
    curl -s -o /dev/null --connect-timeout 5 --max-time 10 \
        -X POST \
        "${auth_endpoint}?op=Login&version=0.1.0" \
        -d "$request_body" 2>/dev/null
    local end_time=$(date +%s%N)
    local elapsed=$((($end_time - $start_time) / 1000000))
    
    if [[ $elapsed -lt 50 ]]; then
        green "✅ 响应时间: ${elapsed}ms (优秀)"
    elif [[ $elapsed -lt 200 ]]; then
        green "✅ 响应时间: ${elapsed}ms (良好)"
    elif [[ $elapsed -lt 500 ]]; then
        yellow "⚠️ 响应时间: ${elapsed}ms (一般)"
    else
        yellow "⚠️ 响应时间: ${elapsed}ms (较慢)"
    fi
    
    # ========== 测试总结 ==========
    echo ""
    blue "📊 测试总结"
    echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
    
    if [[ "$http_code" == "200" ]] && [[ "$auth_http_code" == "200" ]]; then
        green "✅ API服务运行正常"
        green "✅ 认证端点工作正常"
        echo ""
        green "🎉 API配置正确,可以正常使用!"
    else
        red "❌ API测试失败,请检查配置"
    fi
    
    echo ""
    return 0
}

# 📦 安装 FRPS
install_frps() {
    show_header
    blue "开始安装 Lunova FRPS..."
    
    check_dependencies || return 1
    
    # 获取最新版本
    echo ""
    yellow "🔍 正在检测可用版本..."
    local latest_version=$(get_latest_version)
    green "✅ 将安装版本: $latest_version"
    echo ""
    
    # 检查是否已安装
    if [[ -f "$INSTALL_DIR/stellarcore" ]]; then
        local current_version=$(cat "$CURRENT_VERSION_FILE" 2>/dev/null || echo "未知")
        yellow "⚠️ 检测到已安装的 FRPS (版本: $current_version)"
        read -p "是否重新安装到 $latest_version 版本?[y/N]: " reinstall
        if [[ ! "$reinstall" =~ ^[Yy]$ ]]; then
            yellow "取消安装"
            return 1
        fi
    fi
    
    # 下载二进制文件(使用最新版本)
    if ! download_binary "$latest_version"; then
        red "❌ 二进制文件下载失败"
        return 1
    fi
    
    # 生成配置文件
    if ! generate_config; then
        red "❌ 配置文件生成失败"
        return 1
    fi
    
    # 安装服务
    if ! install_service; then
        red "❌ 服务安装失败"
        return 1
    fi
    
    green "🎉 FRPS 安装完成!"
    
    # 询问是否测试API
    echo ""
    read -p "是否要测试API连接?[Y/n]: " test_api
    if [[ ! "$test_api" =~ ^[Nn]$ ]]; then
        test_api_connection
        echo ""
        yellow "按 Enter 键继续..."
        read
    fi
    
    return 0
}

# 🗑 删除 FRPS
uninstall_frps() {
    show_header
    red "⚠️ 警告:即将删除 FRPS!"
    echo ""
    
    # 显示当前安装信息
    if [[ -f "$INSTALL_DIR/stellarcore" ]]; then
        green "检测到已安装的 FRPS:"
        if [[ -f "$CURRENT_VERSION_FILE" ]]; then
            green "版本: $(cat "$CURRENT_VERSION_FILE")"
        fi
        if [[ -f "$CONFIG_FILE" ]]; then
            green "配置文件: $CONFIG_FILE"
        fi
        echo ""
    else
        yellow "未检测到 FRPS 安装"
    fi
    
    read -p "确定要完全删除 FRPS 吗?[y/N]: " confirm
    if [[ ! "$confirm" =~ ^[Yy]$ ]]; then
        yellow "取消删除"
        return 1
    fi
    
    # 停止服务
    if systemctl is-active --quiet "$SERVICE_NAME"; then
        systemctl stop "$SERVICE_NAME"
        green "✅ 服务已停止"
    fi
    
    # 禁用服务
    if systemctl is-enabled --quiet "$SERVICE_NAME" 2>/dev/null; then
        systemctl disable "$SERVICE_NAME"
        green "✅ 服务已禁用"
    fi
    
    # 删除服务文件
    if [[ -f "$SERVICE_FILE" ]]; then
        rm -f "$SERVICE_FILE"
        green "✅ 服务文件已删除"
    fi
    
    # 删除安装目录
    if [[ -d "$INSTALL_DIR" ]]; then
        rm -rf "$INSTALL_DIR"
        green "✅ 安装目录已删除"
    fi
    
    # 重新加载 systemd
    systemctl daemon-reload
    
    green "🎉 FRPS 已完全删除!"
    return 0
}

# 🔧 显示当前状态
show_status() {
    show_header
    blue "FRPS 状态检查"
    echo ""
    
    # 检查二进制文件
    if [[ -f "$INSTALL_DIR/stellarcore" ]]; then
        green "✅ FRPS 已安装"
        if [[ -f "$CURRENT_VERSION_FILE" ]]; then
            green "   版本: $(cat "$CURRENT_VERSION_FILE")"
        fi
    else
        red "❌ FRPS 未安装"
    fi
    
    # 检查配置文件
    if [[ -f "$CONFIG_FILE" ]]; then
        green "✅ 配置文件存在"
    else
        yellow "⚠️ 配置文件不存在"
    fi
    
    # 检查服务状态
    echo ""
    blue "服务状态:"
    if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
        green "✅ 服务正在运行"
    elif systemctl is-enabled --quiet "$SERVICE_NAME" 2>/dev/null; then
        yellow "⚠️ 服务已启用但未运行"
    else
        red "❌ 服务未运行"
    fi
    
    # 显示配置文件信息(如果存在)
    if [[ -f "$CONFIG_FILE" ]]; then
        echo ""
        blue "配置信息:"
        local bind_port=$(grep "bindPort" "$CONFIG_FILE" | cut -d'=' -f2 | tr -d ' ' | head -1)
        local dash_port=$(grep "webServer.port" "$CONFIG_FILE" | cut -d'=' -f2 | tr -d ' ' | head -1)
        local dash_user=$(grep "webServer.user" "$CONFIG_FILE" | cut -d'=' -f2 | tr -d ' "' | head -1)
        
        if [[ -n "$bind_port" ]]; then
            green "绑定端口: $bind_port"
        fi
        if [[ -n "$dash_port" ]]; then
            green "面板端口: $dash_port"
        fi
        if [[ -n "$dash_user" ]]; then
            green "面板用户: $dash_user"
        fi
    fi
    
    echo ""
    yellow "按 Enter 键返回菜单..."
    read
}

# 🔧 修改API地址
modify_api_address() {
    show_header
    blue "修改 API 地址"
    echo ""
    
    # 检查配置文件是否存在
    if [[ ! -f "$CONFIG_FILE" ]]; then
        red "❌ 配置文件不存在: $CONFIG_FILE"
        yellow "请先安装 FRPS"
        sleep 2
        return 1
    fi
    
    # 显示当前 API 地址
    echo "📄 当前配置文件: $CONFIG_FILE"
    echo ""
    blue "当前配置:"
    
    # 提取并显示当前的 [[httpPlugins]] 块
    local in_plugin_block=0
    local current_addr=""
    local line_num=0
    
    while IFS= read -r line; do
        if [[ "$line" =~ ^\[\[httpPlugins\]\]$ ]]; then
            in_plugin_block=1
            echo ""
            cyan "找到 [[httpPlugins]] 配置:"
            echo "  $line"
        elif [[ $in_plugin_block -eq 1 ]]; then
            if [[ "$line" =~ ^addr[[:space:]]*=[[:space:]]*\"(.*)\"$ ]]; then
                current_addr="${BASH_REMATCH[1]}"
                green "  addr = \"$current_addr\""
            elif [[ "$line" =~ ^path[[:space:]]*=[[:space:]]*\"(.*)\"$ ]]; then
                echo "  path = \"${BASH_REMATCH[1]}\""
            elif [[ "$line" =~ ^ops[[:space:]]*=[[:space:]]*\[(.*)\]$ ]]; then
                echo "  ops = [${BASH_REMATCH[1]}]"
            elif [[ -z "$line" ]] || [[ "$line" =~ ^[[:space:]]*$ ]]; then
                in_plugin_block=0
            fi
        fi
    done < "$CONFIG_FILE"
    
    echo ""
    
    if [[ -z "$current_addr" ]]; then
        yellow "⚠️ 未找到 addr 配置"
        echo ""
        read -p "是否要添加新的 [[httpPlugins]] 配置?[Y/n]: " add_new
        if [[ "$add_new" =~ ^[Nn]$ ]]; then
            return 1
        fi
    else
        green "当前 API 地址: $current_addr"
    fi
    
    echo ""
    yellow "请输入新的 API 地址"
    echo "示例: https://api.example.com/v1/proxy/auth"
    echo ""
    read -p "新地址: " new_addr
    
    if [[ -z "$new_addr" ]]; then
        red "❌ 地址不能为空"
        sleep 2
        return 1
    fi
    
    # 备份配置文件
    local backup_file="${CONFIG_FILE}.bak.$(date +%Y%m%d%H%M%S)"
    cp "$CONFIG_FILE" "$backup_file"
    green "✅ 已备份原配置: $backup_file"
    
    # 修改配置文件
    if [[ -n "$current_addr" ]]; then
        # 更新现有配置
        sed -i "s|^addr[[:space:]]*=[[:space:]]*\".*\"|addr = \"$new_addr\"|" "$CONFIG_FILE"
        green "✅ 已更新 API 地址"
    else
        # 检查是否已有 [[httpPlugins]] 块但没有 addr
        if grep -q "^\[\[httpPlugins\]\]" "$CONFIG_FILE"; then
            # 在第一个 [[httpPlugins]] 块后添加 addr
            sed -i "/^\[\[httpPlugins\]\]/a addr = \"$new_addr\"" "$CONFIG_FILE"
            green "✅ 已添加 addr 配置"
        else
            # 在文件末尾添加新的 [[httpPlugins]] 块
            cat >> "$CONFIG_FILE" << EOF

[[httpPlugins]]
addr = "$new_addr"
path = "/api/v1/proxy/auth"
ops = ["Login", "NewProxy", "CloseProxy"]
EOF
            green "✅ 已添加新的 [[httpPlugins]] 配置块"
        fi
    fi
    
    # 显示更新后的配置
    echo ""
    blue "更新后的配置:"
    grep -A 4 "^\[\[httpPlugins\]\]" "$CONFIG_FILE" | head -5
    
    # 重启服务
    echo ""
    yellow "🔄 正在重启服务..."
    
    if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
        systemctl restart "$SERVICE_NAME"
        sleep 2
        
        if systemctl is-active --quiet "$SERVICE_NAME"; then
            green "✅ 服务重启成功"
            echo ""
            systemctl status "$SERVICE_NAME" --no-pager -l | head -5
        else
            red "❌ 服务重启失败"
            yellow "查看日志: journalctl -u $SERVICE_NAME -n 20"
        fi
    else
        yellow "服务未运行,尝试启动..."
        systemctl start "$SERVICE_NAME"
    fi
    
    echo ""
    green "🎉 API 地址修改完成!"
    
    # 询问是否测试新API
    echo ""
    read -p "是否要测试新的API连接?[Y/n]: " test_new
    if [[ ! "$test_new" =~ ^[Nn]$ ]]; then
        test_api_connection "$new_addr"
        echo ""
        yellow "按 Enter 键继续..."
        read
    fi
    
    sleep 2
}

# 📜 显示菜单
show_menu() {
    while true; do
        show_header
        
        # 显示当前状态
        if [[ -f "$INSTALL_DIR/stellarcore" ]]; then
            cyan "📊 当前状态: 已安装"
            if [[ -f "$CURRENT_VERSION_FILE" ]]; then
                cyan "版本: $(cat "$CURRENT_VERSION_FILE")"
            fi
        else
            cyan "📊 当前状态: 未安装"
        fi
        echo ""
        
        # 显示系统信息
        local os_type=$(check_os_type)
        local arch=$(check_system_arch 2>/dev/null || echo "未知")
        cyan "系统: $os_type | 架构: $arch"
        echo ""
        
        # 菜单选项
        purple "请选择操作:"

        echo ""
        green "1. 安装 FRPS"
        green "2. 删除 FRPS"
        green "3. 查看状态"
        green "4. 重启服务"
        green "5. 查看日志"
        green "6. 更新 FRPS"
        green "7. 修改 API 地址"
        green "8. 测试API连接"
        green "0. 退出脚本"
        echo ""
        
        read -p "请输入选项 [0-8]: " choice
        
        case $choice in
            1)
                install_frps
                ;;
            2)
                uninstall_frps
                ;;
            3)
                show_status
                ;;
            4)
                if systemctl restart "$SERVICE_NAME"; then
                    green "✅ 服务重启成功"
                else
                    red "❌ 服务重启失败"
                fi
                sleep 2
                ;;
            5)
                if systemctl is-active --quiet "$SERVICE_NAME" 2>/dev/null; then
                    echo ""
                    yellow "按 Ctrl+C 退出日志查看"
                    echo ""
                    journalctl -u "$SERVICE_NAME" -f
                else
                    red "❌ 服务未运行,无法查看日志"
                    sleep 2
                fi
                ;;
            6)
                update_frps
                ;;
            7)
                modify_api_address
                ;;
            8)
                test_api_connection
                echo ""
                yellow "按 Enter 键返回菜单..."
                read
                ;;
            0)
                green "👋 再见!"
                echo ""
                exit 0
                ;;
            *)
                red "❌ 无效选项,请重新输入"
                sleep 2
                ;;
        esac
        
        echo ""
        yellow "按 Enter 键继续..."
        read
    done
}

# 🏁 脚本入口
main() {
    check_root
    show_menu
}

# 运行主函数
main "$@"