#!/usr/bin/env bash
# speedtest.sh — pangolin 隧道速度/质量验证工具
#
# 在【pangolin 已连接】状态下运行(全局隧道,本机流量经节点出网),测:
#   1. 出口确认   — 出口 IP 是否=节点(确认走的是 pangolin 而非别的代理)
#   2. 链路质量   — 绑 en0 直测客户端→节点真实路径 RTT/丢包(绕开隧道)
#   3. 代理延迟   — 经隧道访问几个站点的首字节时间(TTFB)
#   4. 下行带宽   — 经隧道从 Cloudflare 下载,算 Mbps
#   5. 上行带宽   — 经隧道上传到 Cloudflare,算 Mbps
#
# 用法:
#   bash scripts/speedtest.sh                # 默认下/上行各 50MB / 10MB
#   bash scripts/speedtest.sh --node         # 额外 ssh 节点测其自身出口带宽(理论上限对照)
#   DL_MB=100 UL_MB=20 bash scripts/speedtest.sh
#
# 环境变量:
#   NODE_IP   节点公网 IP(默认 107.172.55.251)
#   NODE_SSH  节点 ssh 别名(默认 racknerd,仅 --node 用)
#   DL_MB     下行测试大小 MB(默认 50)
#   UL_MB     上行测试大小 MB(默认 10)
set -uo pipefail

NODE_IP="${NODE_IP:-107.172.55.251}"
NODE_SSH="${NODE_SSH:-racknerd}"
DL_MB="${DL_MB:-50}"
UL_MB="${UL_MB:-10}"
WITH_NODE=0
[ "${1:-}" = "--node" ] && WITH_NODE=1

command -v curl >/dev/null 2>&1 || { echo "✗ 需要 curl"; exit 1; }

# bytes/sec → 人类可读 Mbps(*8/1e6),保留 1 位小数
mbps() { awk -v b="$1" 'BEGIN{ printf "%.1f Mbps", b*8/1000000 }'; }
hr_bytes() { awk -v b="$1" 'BEGIN{ split("B KB MB GB",u); i=1; while(b>=1024&&i<4){b/=1024;i++} printf "%.1f%s", b, u[i] }'; }

echo "════════════════════════════════════════════════════"
echo " pangolin 测速  节点=$NODE_IP  下行=${DL_MB}MB 上行=${UL_MB}MB"
echo "════════════════════════════════════════════════════"

# ── 1. 出口确认 ──────────────────────────────────────────────────────────────
echo
echo "==> [1/5] 出口 IP 确认"
EGRESS_JSON="$(curl -fsS --max-time 15 https://ipinfo.io/json 2>/dev/null)"
EGRESS_IP="$(printf '%s' "$EGRESS_JSON" | awk -F'"' '/"ip"/{print $4; exit}')"
EGRESS_CITY="$(printf '%s' "$EGRESS_JSON" | awk -F'"' '/"city"/{print $4; exit}')"
if [ -z "$EGRESS_IP" ]; then
  echo "    ✗ 取不到出口 IP(隧道未连?网络异常?)——后续测试可能无意义"
elif [ "$EGRESS_IP" = "$NODE_IP" ]; then
  echo "    ✅ 出口 = $EGRESS_IP ($EGRESS_CITY) —— 确认走 pangolin 节点"
else
  echo "    ⚠ 出口 = $EGRESS_IP ($EGRESS_CITY) ≠ 节点 $NODE_IP"
  echo "      你可能没连 pangolin,或还开着别的代理(Shadowrocket/Tailscale)。测的不是 pangolin!"
fi

# ── 2. 真实链路质量(绕隧道,绑 en0 直测客户端→节点)────────────────────────
echo
echo "==> [2/5] 客户端→节点 真实路径(绑 en0 绕隧道,30 包)"
IF="$(route -n get default 2>/dev/null | awk '/interface:/{print $2; exit}')"
IF="${IF:-en0}"
PING_OUT="$(ping -b "$IF" -c 30 -i 0.2 "$NODE_IP" 2>/dev/null | tail -2)"
if [ -n "$PING_OUT" ]; then
  printf '%s\n' "$PING_OUT" | sed 's/^/    /'
else
  echo "    (ping 失败:ICMP 可能被拦,或 -b $IF 不支持)"
fi

# ── 3. 经隧道代理延迟(TTFB)──────────────────────────────────────────────────
echo
echo "==> [3/5] 经隧道访问延迟(首字节 TTFB)"
for url in https://www.gstatic.com/generate_204 https://cp.cloudflare.com/generate_204 https://www.youtube.com; do
  R="$(curl -o /dev/null -s --max-time 20 \
        -w '连接=%{time_connect}s  TTFB=%{time_starttransfer}s  http=%{http_code}' "$url" 2>/dev/null)"
  printf '    %-40s %s\n' "${url#https://}" "${R:-✗ 超时/失败}"
done

# ── 4. 下行带宽 ──────────────────────────────────────────────────────────────
echo
echo "==> [4/5] 下行带宽(从 Cloudflare 下载 ${DL_MB}MB)"
DL_BYTES=$((DL_MB * 1024 * 1024))
DL="$(curl -o /dev/null -s --max-time 120 \
      -w '%{speed_download} %{time_total} %{size_download}' \
      "https://speed.cloudflare.com/__down?bytes=$DL_BYTES" 2>/dev/null)"
if [ -n "$DL" ]; then
  read -r dl_speed dl_time dl_size <<<"$DL"
  echo "    下行 $(mbps "$dl_speed")   (传输 $(hr_bytes "$dl_size") 用时 ${dl_time}s)"
else
  echo "    ✗ 下行测试失败/超时"
fi

# ── 5. 上行带宽 ──────────────────────────────────────────────────────────────
echo
echo "==> [5/5] 上行带宽(上传 ${UL_MB}MB 到 Cloudflare)"
UL_BYTES=$((UL_MB * 1024 * 1024))
UL="$(head -c "$UL_BYTES" /dev/zero | curl -o /dev/null -s --max-time 120 \
      -X POST --data-binary @- \
      -w '%{speed_upload} %{time_total} %{size_upload}' \
      "https://speed.cloudflare.com/__up" 2>/dev/null)"
if [ -n "$UL" ]; then
  read -r ul_speed ul_time ul_size <<<"$UL"
  echo "    上行 $(mbps "$ul_speed")   (传输 $(hr_bytes "$ul_size") 用时 ${ul_time}s)"
else
  echo "    ✗ 上行测试失败/超时"
fi

# ── 可选:节点自身出口带宽(理论上限对照)──────────────────────────────────
if [ "$WITH_NODE" = "1" ]; then
  echo
  echo "==> [+] 节点自身出口带宽(ssh $NODE_SSH,理论上限对照)"
  ssh -o ConnectTimeout=10 "$NODE_SSH" "curl -o /dev/null -s --max-time 60 \
      -w '节点下行 %{speed_download} B/s  用时 %{time_total}s\n' \
      'https://speed.cloudflare.com/__down?bytes=$DL_BYTES'" 2>/dev/null \
    | awk '{b=$2; printf "    节点下行 %.1f Mbps  用时 %ss\n", b*8/1000000, $4}' \
    || echo "    (ssh $NODE_SSH 失败,跳过)"
fi

echo
echo "════════════════════════════════════════════════════"
echo " 说明:节点是 RackNerd 512MB/1核,REALITY 加解密吃 CPU,"
echo "       几十~一两百 Mbps 属正常;跨境晚高峰会波动。"
echo "       对照:退出 pangolin 后再跑一次 = 你的本地直连基线。"
echo "════════════════════════════════════════════════════"
