#!/bin/bash

# 极限压力测试脚本
# 专注于高并发探测，支持1000次/秒级别的并发请求

# 默认配置
DEFAULT_URL="https://zrp233.top"
DEFAULT_CONCURRENT=100
DEFAULT_INTERVAL=1
DEFAULT_DURATION=60

# 全局变量
PROBE_URL="${1:-$DEFAULT_URL}"
CONCURRENT_COUNT="${2:-$DEFAULT_CONCURRENT}"
INTERVAL="${3:-$DEFAULT_INTERVAL}"
DURATION="${4:-$DEFAULT_DURATION}"
LOG_FILE=""
STATS_FILE=""
START_TIME=$(date +%s)
TOTAL_REQUESTS=0
SUCCESS_COUNT=0
ERROR_COUNT=0
RUNNING=true

# 简化的User-Agent池
USER_AGENTS=(
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"
    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36"
    "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36"
    "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:89.0) Gecko/20100101"
)

# 生成文件名
generate_filenames() {
    local timestamp=$(date +"%Y%m%d_%H%M%S")
    local random_num=$(printf "%04d" $((RANDOM % 10000)))
    LOG_FILE="extreme_${timestamp}_${random_num}.log"
    STATS_FILE="extreme_stats_${timestamp}_${random_num}.log"
}

# 获取随机User-Agent
get_random_ua() {
    echo "${USER_AGENTS[$((RANDOM % ${#USER_AGENTS[@]}))]}"
}

# 单次请求函数（优化版）
single_request() {
    local thread_id=$1
    local ua=$(get_random_ua)
    local start_time=$(date +%s%3N)
    
    local response=$(curl -s -o /dev/null -w "%{http_code}" \
        -H "User-Agent: $ua" \
        -H "Connection: close" \
        --connect-timeout 3 \
        --max-time 10 \
        --no-keepalive \
        "$PROBE_URL" 2>/dev/null)
    
    local end_time=$(date +%s%3N)
    local response_time=$((end_time - start_time))
    
    if [ -z "$response" ]; then
        response="000"
        response_time=0
    fi
    
    # 原子性更新统计
    {
        flock -x 200
        local current_total=$(cat /tmp/extreme_total.tmp 2>/dev/null || echo "0")
        local current_success=$(cat /tmp/extreme_success.tmp 2>/dev/null || echo "0")
        local current_error=$(cat /tmp/extreme_error.tmp 2>/dev/null || echo "0")
        
        current_total=$((current_total + 1))
        if [ "$response" = "200" ]; then
            current_success=$((current_success + 1))
        else
            current_error=$((current_error + 1))
        fi
        
        # 更新临时统计文件
        echo "$current_total" > /tmp/extreme_total.tmp
        echo "$current_success" > /tmp/extreme_success.tmp
        echo "$current_error" > /tmp/extreme_error.tmp
        
        # 写入日志（每50次请求记录一次以减少I/O）
        if [ $((current_total % 50)) -eq 0 ]; then
            local current_time=$(date +"%Y/%m/%d/%H/%M/%S.%3N")
            echo "[$current_time] 线程$thread_id | 状态码: $response | 响应时间: ${response_time}ms | 总计: $current_total | 成功: $current_success" >> "$LOG_FILE"
        fi
    } 200>>/tmp/extreme.lock
}

# 批量并发请求
batch_concurrent_requests() {
    local batch_size=$1
    local pids=()
    
    echo "$(date +"%H:%M:%S") - 启动 $batch_size 个并发请求..."
    
    # 启动并发请求
    for ((i=1; i<=batch_size; i++)); do
        single_request $i &
        pids+=($!)
        
        # 控制启动速度，避免系统过载
        if [ $((i % 50)) -eq 0 ]; then
            sleep 0.01
        fi
    done
    
    # 等待所有请求完成
    for pid in "${pids[@]}"; do
        wait $pid 2>/dev/null
    done
    
    echo "$(date +"%H:%M:%S") - 批次完成，共 $batch_size 个请求"
}

# 显示实时统计
show_realtime_stats() {
    local current_total=$(cat /tmp/extreme_total.tmp 2>/dev/null || echo "0")
    local current_success=$(cat /tmp/extreme_success.tmp 2>/dev/null || echo "0")
    local current_error=$(cat /tmp/extreme_error.tmp 2>/dev/null || echo "0")
    local success_rate=0
    
    if [ $current_total -gt 0 ]; then
        success_rate=$((current_success * 100 / current_total))
    fi
    
    local elapsed=$(($(date +%s) - START_TIME))
    local rps=0
    if [ $elapsed -gt 0 ]; then
        rps=$((current_total / elapsed))
    fi
    
    printf "\r实时统计: 总计%d | 成功%d | 失败%d | 成功率%d%% | RPS:%d | 运行%ds" \
        $current_total $current_success $current_error $success_rate $rps $elapsed
}

# 更新详细统计文件
update_stats_file() {
    local current_total=$(cat /tmp/extreme_total.tmp 2>/dev/null || echo "0")
    local current_success=$(cat /tmp/extreme_success.tmp 2>/dev/null || echo "0")
    local current_error=$(cat /tmp/extreme_error.tmp 2>/dev/null || echo "0")
    local success_rate=0
    
    if [ $current_total -gt 0 ]; then
        success_rate=$((current_success * 100 / current_total))
    fi
    
    local elapsed=$(($(date +%s) - START_TIME))
    local rps=0
    if [ $elapsed -gt 0 ]; then
        rps=$((current_total / elapsed))
    fi
    
    cat > "$STATS_FILE" << EOF
========================================
极限压力测试统计报告
========================================
测试时间: $(date +"%Y/%m/%d %H:%M:%S")
目标URL: $PROBE_URL
并发配置: ${CONCURRENT_COUNT}次/${INTERVAL}秒
测试时长: ${elapsed}秒 / ${DURATION}秒
========================================
总请求数: $current_total
成功请求: $current_success
失败请求: $current_error
成功率: ${success_rate}%
平均RPS: $rps
========================================
性能指标:
- 目标并发: ${CONCURRENT_COUNT}次/${INTERVAL}秒
- 实际RPS: $rps
- 并发效率: $((rps * 100 / CONCURRENT_COUNT))%
========================================
EOF
}

# 显示使用说明
show_usage() {
    echo "极限压力测试脚本"
    echo "用法: $0 [URL] [并发数] [间隔秒] [持续时间]"
    echo ""
    echo "参数说明:"
    echo "  URL       - 目标URL (默认: $DEFAULT_URL)"
    echo "  并发数    - 每次并发请求数量 (默认: $DEFAULT_CONCURRENT)"
    echo "  间隔秒    - 每批次间隔秒数 (默认: $DEFAULT_INTERVAL)"
    echo "  持续时间  - 测试持续秒数 (默认: $DEFAULT_DURATION)"
    echo ""
    echo "高并发示例:"
    echo "  $0 https://example.com 1000 1 60    # 每秒1000次，持续60秒"
    echo "  $0 https://example.com 500 0.5 30   # 每0.5秒500次，持续30秒"
    echo "  $0 https://example.com 2000 2 120   # 每2秒2000次，持续120秒"
    echo ""
    echo "注意事项:"
    echo "  - 高并发测试需要足够的系统资源"
    echo "  - 建议先用较小并发数测试"
    echo "  - 请确保有测试目标的授权"
    echo ""
    echo "按 Ctrl+C 停止测试"
}

# 信号处理
cleanup() {
    RUNNING=false
    echo ""
    echo "正在停止测试..."
    
    # 终止所有子进程
    pkill -P $$ 2>/dev/null
    sleep 1
    
    # 最终统计
    update_stats_file
    echo ""
    echo "测试已停止"
    echo "详细日志: $LOG_FILE"
    echo "统计报告: $STATS_FILE"
    
    # 显示最终统计
    local final_total=$(cat /tmp/extreme_total.tmp 2>/dev/null || echo "0")
    local final_success=$(cat /tmp/extreme_success.tmp 2>/dev/null || echo "0")
    local final_error=$(cat /tmp/extreme_error.tmp 2>/dev/null || echo "0")
    local elapsed=$(($(date +%s) - START_TIME))
    local avg_rps=0
    
    if [ $elapsed -gt 0 ]; then
        avg_rps=$((final_total / elapsed))
    fi
    
    echo ""
    echo "=========================================="
    echo "最终测试结果"
    echo "=========================================="
    echo "总请求数: $final_total"
    echo "成功请求: $final_success"
    echo "失败请求: $final_error"
    echo "测试时长: ${elapsed}秒"
    echo "平均RPS: $avg_rps"
    echo "=========================================="
    
    # 清理临时文件
    rm -f /tmp/extreme_*.tmp /tmp/extreme.lock 2>/dev/null
    
    exit 0
}

# 主函数
main() {
    # 检查参数
    if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
        show_usage
        exit 0
    fi
    
    # 验证并发数
    if ! [[ "$CONCURRENT_COUNT" =~ ^[0-9]+$ ]] || [ "$CONCURRENT_COUNT" -lt 1 ]; then
        echo "错误: 并发数必须是正整数"
        exit 1
    fi
    
    # 验证间隔时间
    if ! [[ "$INTERVAL" =~ ^[0-9]*\.?[0-9]+$ ]]; then
        echo "错误: 间隔时间格式不正确"
        exit 1
    fi
    
    # 检查系统限制
    local max_files=$(ulimit -n)
    if [ "$CONCURRENT_COUNT" -gt $((max_files / 2)) ]; then
        echo "警告: 并发数($CONCURRENT_COUNT)可能超过系统文件描述符限制($max_files)"
        echo "建议执行: ulimit -n $((CONCURRENT_COUNT * 2))"
        read -p "是否继续? (y/N): " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            exit 1
        fi
    fi
    
    # 设置信号处理
    trap cleanup SIGINT SIGTERM
    
    # 初始化
    generate_filenames
    echo "0" > /tmp/extreme_total.tmp
    echo "0" > /tmp/extreme_success.tmp
    echo "0" > /tmp/extreme_error.tmp
    
    # 显示配置
    echo "=========================================="
    echo "极限压力测试启动"
    echo "=========================================="
    echo "目标URL: $PROBE_URL"
    echo "并发配置: ${CONCURRENT_COUNT}次/${INTERVAL}秒"
    echo "测试时长: ${DURATION}秒"
    echo "日志文件: $LOG_FILE"
    echo "统计文件: $STATS_FILE"
    echo "启动时间: $(date +"%Y/%m/%d %H:%M:%S")"
    
    # 计算理论RPS
    local theoretical_rps=$(echo "scale=2; $CONCURRENT_COUNT / $INTERVAL" | bc -l)
    echo "理论RPS: $theoretical_rps"
    echo "=========================================="
    
    # 记录开始
    echo "[$(date +"%Y/%m/%d/%H/%M/%S")] 极限压力测试开始" > "$LOG_FILE"
    
    # 主测试循环
    local end_time=$((START_TIME + DURATION))
    
    while [ $(date +%s) -lt $end_time ] && [ "$RUNNING" = true ]; do
        # 执行批量并发请求
        batch_concurrent_requests $CONCURRENT_COUNT
        
        # 显示实时统计
        show_realtime_stats
        
        # 更新统计文件（每10次循环更新一次）
        if [ $(($(date +%s) % 10)) -eq 0 ]; then
            update_stats_file
        fi
        
        # 等待下一个周期
        if [ "$RUNNING" = true ]; then
            sleep "$INTERVAL"
        fi
    done
    
    # 正常结束
    if [ "$RUNNING" = true ]; then
        echo ""
        echo "测试时间到达，正在结束..."
        cleanup
    fi
}

# 运行主函数
main "$@"
