Files
IP-Sentinel/install/ui_menu.sh

430 lines
23 KiB
Bash
Executable File
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/bin/bash
# ==========================================================
# 模块名称: ui_menu.sh
# 核心功能: 交互式状态机、LBS 地图解析、Telegram 控制中枢配置
# ==========================================================
do_fetch_map() {
echo -e "\n[2/7] 正在连线云端,拉取全球节点地图..."
curl -fsSL --connect-timeout 10 --retry 3 "${REPO_RAW_URL}/data/map.json" -o "${SECURE_TMP}/map.json"
if [ ! -s "${SECURE_TMP}/map.json" ]; then
echo -e "\033[31m❌ 拉取全球地图失败!请检查网络或 GitHub 仓库地址。\033[0m"
exit 1
fi
}
do_handle_menu() {
if [ "$SILENT_OTA" == "true" ]; then
echo -e "\n⏳ [OTA] 静默升级指令已确认,正在剥离控制台交互..."
ACTION_CHOICE=1
UPGRADE_MODE="true"
KEEP_LOGS="true"
source "$CONFIG_FILE"
else
echo -e "\n请选择操作:"
echo " 1) 🚀 部署边缘节点 (进入全球节点配置)"
echo " 2) 🗑️ 一键卸载 IP-Sentinel"
read -p "请输入选择 [1-2] (默认1): " ACTION_CHOICE
ACTION_CHOICE=${ACTION_CHOICE:-1}
if [ "$ACTION_CHOICE" == "2" ]; then
echo -e "\n⏳ 正在拉取卸载程序..."
curl -fsSL --connect-timeout 10 --retry 3 "${REPO_RAW_URL}/core/uninstall.sh" -o "${SECURE_TMP}/ip_uninstall.sh"
chmod +x "${SECURE_TMP}/ip_uninstall.sh"
bash "${SECURE_TMP}/ip_uninstall.sh"
rm -f "${SECURE_TMP}/ip_uninstall.sh"
exit 0
fi
UPGRADE_MODE="false"
KEEP_LOGS="true"
if [ "$ACTION_CHOICE" == "1" ] && [ -f "$CONFIG_FILE" ]; then
echo -e "\n\033[33m💡 哨兵雷达提示:检测到本机已部署过 IP-Sentinel。\033[0m"
read -p "👉 是否按原配置直接进行平滑升级?(y/n, 默认y): " UPGRADE_CHOICE
if [[ -z "$UPGRADE_CHOICE" || "$UPGRADE_CHOICE" =~ ^[Yy]$ ]]; then
UPGRADE_MODE="true"
read -p "👉 是否保留历史运行日志?(y/n, 默认y): " LOG_CHOICE
if [[ "$LOG_CHOICE" =~ ^[Nn]$ ]]; then
KEEP_LOGS="false"
fi
source "$CONFIG_FILE"
echo -e "\033[32m✅ 已激活 [平滑升级模式],即将跳过基础配置,直接更新核心装甲...\033[0m"
else
echo -e "\033[33m🔄 您选择了重新配置,旧的哨兵数据将被彻底抹除。\033[0m"
fi
fi
fi
}
do_interactive_setup() {
if [ "$UPGRADE_MODE" == "false" ]; then
# [v4.3.1 重构] 引入有限状态机 (State Machine) 与输入边界防御
local step=0
while [ $step -lt 4 ]; do
case $step in
0)
echo -e "\n\033[36m📍 【第零级】请选择目标战区 (Continent):\033[0m"
jq -r '.continents[] | "\(.id)|\(.name)"' "${SECURE_TMP}/map.json" > "${SECURE_TMP}/continents.txt"
i=1; CONT_MAP=()
while IFS="|" read -r cont_id cont_name; do
echo " $i) $cont_name"
CONT_MAP[$i]="$cont_id"
((i++))
done < "${SECURE_TMP}/continents.txt"
read -p "请输入选择 [1-$((i-1))] (默认1): " CONT_SEL
CONT_SEL=${CONT_SEL:-1}
if ! [[ "$CONT_SEL" =~ ^[0-9]+$ ]] || [ "$CONT_SEL" -lt 1 ] || [ "$CONT_SEL" -ge "$i" ]; then
echo -e "\033[31m❌ 输入非法,请输入列表中的正确数字。\033[0m"
continue
fi
CONT_ID="${CONT_MAP[$CONT_SEL]}"
step=1
;;
1)
echo -e "\n\033[36m📍 【第一级】正在检索 [$CONT_ID] 战区下的国家/地区...\033[0m"
jq -r ".continents[] | select(.id==\"$CONT_ID\") | .countries[] | \"\(.id)|\(.name)|\(.keyword_file)\"" "${SECURE_TMP}/map.json" > "${SECURE_TMP}/countries.txt"
i=1; COUNTRY_MAP=(); KEYWORD_MAP=()
echo " 0) 🔙 返回上一级 (重新选择战区)"
while IFS="|" read -r c_id c_name k_file; do
echo " $i) $c_name"
COUNTRY_MAP[$i]="$c_id"
KEYWORD_MAP[$i]="$k_file"
((i++))
done < "${SECURE_TMP}/countries.txt"
read -p "请输入选择 [0-$((i-1))] (默认1): " C_SEL
C_SEL=${C_SEL:-1}
if [ "$C_SEL" -eq 0 ]; then
step=0
continue
fi
if ! [[ "$C_SEL" =~ ^[0-9]+$ ]] || [ "$C_SEL" -lt 1 ] || [ "$C_SEL" -ge "$i" ]; then
echo -e "\033[31m❌ 输入非法,请输入列表中的正确数字。\033[0m"
continue
fi
COUNTRY_ID="${COUNTRY_MAP[$C_SEL]}"
KEYWORD_FILE="${KEYWORD_MAP[$C_SEL]}"
REGION_CODE="$COUNTRY_ID"
step=2
;;
2)
echo -e "\n\033[36m📍 【第二级】正在检索 [$COUNTRY_ID] 的行政区数据...\033[0m"
jq -r ".continents[] | select(.id==\"$CONT_ID\") | .countries[] | select(.id==\"$COUNTRY_ID\") | .states[] | \"\(.id)|\(.name)\"" "${SECURE_TMP}/map.json" > "${SECURE_TMP}/states.txt"
STATE_COUNT=$(wc -l < "${SECURE_TMP}/states.txt")
if [ "$STATE_COUNT" -eq 1 ]; then
IFS="|" read -r STATE_ID STATE_NAME < "${SECURE_TMP}/states.txt"
echo -e "\033[32m💡 该国家下仅有单一配置 [$STATE_NAME],已自动跃迁。\033[0m"
step=3
continue
else
i=1; STATE_MAP=()
echo " 0) 🔙 返回上一级 (重新选择国家)"
while IFS="|" read -r s_id s_name; do
echo " $i) $s_name"
STATE_MAP[$i]="$s_id"
((i++))
done < "${SECURE_TMP}/states.txt"
read -p "请输入选择 [0-$((i-1))] (默认1): " S_SEL
S_SEL=${S_SEL:-1}
if [ "$S_SEL" -eq 0 ]; then
step=1
continue
fi
if ! [[ "$S_SEL" =~ ^[0-9]+$ ]] || [ "$S_SEL" -lt 1 ] || [ "$S_SEL" -ge "$i" ]; then
echo -e "\033[31m❌ 输入非法,请输入列表中的正确数字。\033[0m"
continue
fi
STATE_ID="${STATE_MAP[$S_SEL]}"
step=3
fi
;;
3)
echo -e "\n\033[36m📍 【第三级】请锁定具体城市节点:\033[0m"
jq -r ".continents[] | select(.id==\"$CONT_ID\") | .countries[] | select(.id==\"$COUNTRY_ID\") | .states[] | select(.id==\"$STATE_ID\") | .cities[] | \"\(.id)|\(.name)\"" "${SECURE_TMP}/map.json" > "${SECURE_TMP}/cities.txt"
CITY_COUNT=$(wc -l < "${SECURE_TMP}/cities.txt")
if [ "$CITY_COUNT" -eq 1 ]; then
IFS="|" read -r CITY_ID CITY_NAME < "${SECURE_TMP}/cities.txt"
echo -e "\033[32m💡 该区域下仅有单一城市 [$CITY_NAME],已自动锁定。\033[0m"
step=4
continue
else
i=1; CITY_MAP=(); CITY_NAME_MAP=()
echo " 0) 🔙 返回上一级 (重新选择行政区)"
while IFS="|" read -r c_id c_name; do
echo " $i) $c_name"
CITY_MAP[$i]="$c_id"
CITY_NAME_MAP[$i]="$c_name"
((i++))
done < "${SECURE_TMP}/cities.txt"
read -p "请输入选择 [0-$((i-1))] (默认1): " CI_SEL
CI_SEL=${CI_SEL:-1}
if [ "$CI_SEL" -eq 0 ]; then
if [ "$STATE_COUNT" -eq 1 ]; then
step=1
else
step=2
fi
continue
fi
if ! [[ "$CI_SEL" =~ ^[0-9]+$ ]] || [ "$CI_SEL" -lt 1 ] || [ "$CI_SEL" -ge "$i" ]; then
echo -e "\033[31m❌ 输入非法,请输入列表中的正确数字。\033[0m"
continue
fi
CITY_ID="${CITY_MAP[$CI_SEL]}"
CITY_NAME="${CITY_NAME_MAP[$CI_SEL]}"
step=4
fi
;;
esac
done
rm -f "${SECURE_TMP}/map.json" "${SECURE_TMP}/continents.txt" "${SECURE_TMP}/countries.txt" "${SECURE_TMP}/states.txt" "${SECURE_TMP}/cities.txt"
mkdir -p "${INSTALL_DIR}/core"
mkdir -p "${INSTALL_DIR}/data/keywords"
mkdir -p "${INSTALL_DIR}/data/regions/${COUNTRY_ID}/${STATE_ID}"
mkdir -p "${INSTALL_DIR}/logs"
echo -e "\n[3/7] 正在初始化养护模块 (默认全量部署,支持 TG 远程动态启停)..."
ENABLE_GOOGLE="true"
ENABLE_TRUST="true"
echo -e "\n[4/7] 是否接入 Master 司令部进行远程联控? (y/n)"
read -p "请输入选择 [y/n] (默认y): " TG_CHOICE
TG_CHOICE=${TG_CHOICE:-y}
TG_TOKEN=""
CHAT_ID=""
AGENT_PORT="9527"
if [[ "$TG_CHOICE" =~ ^[Yy]$ ]]; then
echo -e "\n请选择中枢接入模式 (推荐私有部署,支持后续 OTA 远程静默升级):"
echo " 1) 🛡️ 私有独立中枢 (需提供自建 Bot Token推荐)"
echo " 2) ☁️ 官方公共网关 (@OmniBeacon_bot新手免配置)"
read -p "请输入选择 [1-2] (默认1): " MASTER_TYPE
MASTER_TYPE=${MASTER_TYPE:-1}
if [ "$MASTER_TYPE" == "2" ]; then
TG_TOKEN="OFFICIAL_GATEWAY_MODE"
TG_API_URL="https://omni-gateway.samanthaestime296.workers.dev"
ENABLE_OTA="false"
echo -e "\033[32m✅ 已自动连接官方安全网关 (@OmniBeacon_bot)。\033[0m"
echo -e "\033[33m👉 请确保您已在 TG 中关注官方机器人并发送过 /start否则将无法接收消息。\033[0m"
echo -e "\n\033[33m⚠ 【安全熔断提示】\033[0m"
echo -e "\033[33m由于您使用了官方公共网关为防止潜在的滥用或供应链风险本节点的 [OTA 远程升级] 权限已被系统底层强制禁用。\033[0m"
echo -e "\033[33m💡 若未来需要启用 OTA请自建私有中枢后重新部署本节点。\033[0m"
else
echo -e "\n\033[36m📘 私有 Bot 创建教程: \033[4m\033]8;;https://blog.iot-architect.com/engineering-practice/create-private-telegram-bot-via-botfather/\033\\👉 [点击此处直接在浏览器中打开]\033]8;;\033\\ 👈\033[0m"
echo -e "\033[90m (若您的终端较老不支持点击,请手动复制: https://blog.iot-architect.com/engineering-practice/create-private-telegram-bot-via-botfather/ )\033[0m"
read -p "请输入您的私有 Telegram Bot Token: " RAW_TOKEN
USER_TOKEN=$(echo "$RAW_TOKEN" | tr -cd 'a-zA-Z0-9_:-')
while [ -z "$USER_TOKEN" ]; do
read -p "⚠️ Token 不能为空或包含非法字符,请重新输入: " RAW_TOKEN
USER_TOKEN=$(echo "$RAW_TOKEN" | tr -cd 'a-zA-Z0-9_:-')
done
TG_TOKEN="$USER_TOKEN"
TG_API_URL="https://api.telegram.org/bot${TG_TOKEN}/sendMessage"
echo -e "\033[32m✅ 已记录您的私有机器人 Token。\033[0m"
echo -e "\n\033[36m[4.1/7] OTA 远程静默升级授权\033[0m"
echo -e "💡 开启后,您可以在 TG 面板一键将本节点热更新至最新版本。"
read -p "是否允许本节点接收 OTA 升级指令?(y/n, 默认y): " OTA_CHOICE
if [[ "$OTA_CHOICE" =~ ^[Nn]$ ]]; then
ENABLE_OTA="false"
echo -e "🛡️ \033[33m已关闭 OTA 权限,本节点未来将只能通过 SSH 手动升级。\033[0m"
else
ENABLE_OTA="true"
echo -e "✅ \033[32m已开启 OTA 权限,核按钮已挂载至您的私有中枢。\033[0m"
fi
fi
echo -e "\n\033[33m💡 提示:如果您不知道下方自己的 Chat ID 是什么,可以关注 @userinfobot 获取。\033[0m"
echo -e "\033[36m📘 查看图文教程: \033[4m\033]8;;https://blog.iot-architect.com/engineering-practice/get-telegram-personal-id-via-userinfobot/\033\\👉 [点击此处直接在浏览器中打开]\033]8;;\033\\ 👈\033[0m"
echo -e "\033[90m (若您的终端较老不支持点击,请手动复制: https://blog.iot-architect.com/engineering-practice/get-telegram-personal-id-via-userinfobot/ )\033[0m"
read -p "请输入你的 Chat ID (必须准确,否则无法联控): " RAW_CHAT_ID
CHAT_ID=$(echo "$RAW_CHAT_ID" | tr -cd '0-9-')
echo -e "\n\033[36m[4.2/7] 正在构建 Webhook 安全通信隧道...\033[0m"
echo -n "🎲 正在探测可用随机端口..."
while true; do
RANDOM_PORT=$((RANDOM % 55536 + 10000))
if ! (ss -tuln 2>/dev/null | grep -q ":$RANDOM_PORT " || netstat -tuln 2>/dev/null | grep -q ":$RANDOM_PORT "); then
break
fi
echo -n "."
done
echo -e " 完成!"
echo -e "💡 系统为您生成的推荐随机高位端口为: \033[32m$RANDOM_PORT\033[0m"
echo -e "\033[33m(该端口已通过本地占用校验,可直接使用)\033[0m"
while true; do
read -p "请输入 Webhook 监听端口 (回车采用推荐, 或手动输入): " INPUT_PORT
if [ -z "$INPUT_PORT" ]; then
AGENT_PORT="$RANDOM_PORT"
break
else
if [[ "$INPUT_PORT" =~ ^[0-9]+$ ]] && [ "$INPUT_PORT" -ge 1 ] && [ "$INPUT_PORT" -le 65535 ]; then
if (ss -tuln 2>/dev/null | grep -q ":$INPUT_PORT " || netstat -tuln 2>/dev/null | grep -q ":$INPUT_PORT "); then
echo -e "\033[31m❌ 端口 $INPUT_PORT 已被占用,请重新输入或使用推荐端口。\033[0m"
else
AGENT_PORT="$INPUT_PORT"
break
fi
else
echo -e "\033[31m❌ 输入非法!端口范围应为 1-65535。\033[0m"
fi
fi
done
echo -e "✅ 已锁定 Webhook 通讯端口: \033[32m$AGENT_PORT\033[0m"
fi
fi
}
do_final_report() {
if [[ -n "$TG_TOKEN" ]] && [[ -n "$CHAT_ID" ]]; then
# 注册报文中塞入多宿主弹匣 SAFE_COMM_IP
REG_MSG="#REGISTER#|${REGION_CODE}|${NODE_NAME}|${SAFE_COMM_IP}|${AGENT_PORT}|${NODE_ALIAS}|${ENABLE_OTA}"
if [ "$UPGRADE_MODE" == "true" ]; then
OLD_VERSION=$(grep "^AGENT_VERSION=" "$CONFIG_FILE" | cut -d'"' -f2)
[ -z "$OLD_VERSION" ] && OLD_VERSION="3.3.1"
if version_lt "$OLD_VERSION" "4.2.2"; then
echo -e "\n📡 [路由枢纽] 正在执行容灾架构重组 (v${OLD_VERSION} -> v${TARGET_VERSION})..."
TEXT_MSG="✨ *IP-Sentinel 容灾引擎热更新完成!*
📍 节点:\`${NODE_ALIAS}\`
🌐 养护 IP\`${SAFE_PUBLIC_IP}\`
📡 容灾弹匣:\`${SAFE_COMM_IP}\`
🚀 状态v${TARGET_VERSION} 全域双栈引擎已部署
⚠️ *通讯架构已升级为多宿主容灾模式!*
👉 **请务必点击下方指令并发送,将新版通讯弹匣同步至司令部:**
\`${REG_MSG}\`"
JSON_PAYLOAD=$(jq -n --arg cid "$CHAT_ID" --arg txt "$TEXT_MSG" --arg cb "manage:${NODE_NAME}" '{chat_id: $cid, text: $txt, parse_mode: "Markdown", reply_markup: {inline_keyboard: [[{text: "⚙️ 调出该节点控制台", callback_data: $cb}]]}}')
curl -s -X POST "${TG_API_URL}" -H "Content-Type: application/json" -d "$JSON_PAYLOAD" >/dev/null 2>&1
echo -e "\033[32m✅ 升级通知已推送!请前往 TG 点击注册指令完成身份同步!\033[0m"
else
echo -e "\n📡 [路由枢纽] 正在执行静默平滑升级 (v${OLD_VERSION} -> v${TARGET_VERSION})..."
TEXT_MSG="✨ *IP-Sentinel 引擎热更新完成!*
📍 节点:\`${NODE_ALIAS}\`
🌐 养护 IP\`${SAFE_PUBLIC_IP}\`
📡 容灾 IP\`${SAFE_COMM_IP}\`
🚀 状态v${TARGET_VERSION} OTA 动态活体引擎已部署"
JSON_PAYLOAD=$(jq -n --arg cid "$CHAT_ID" --arg txt "$TEXT_MSG" --arg cb "manage:${NODE_NAME}" '{chat_id: $cid, text: $txt, parse_mode: "Markdown", reply_markup: {inline_keyboard: [[{text: "⚙️ 调出该节点控制台", callback_data: $cb}]]}}')
curl -s -X POST "${TG_API_URL}" -H "Content-Type: application/json" -d "$JSON_PAYLOAD" >/dev/null 2>&1
echo -e "\033[32m✅ 升级成功通知已推送到您的 Telegram\033[0m"
fi
sed -i '/^NAME_HASHED=/d' "$CONFIG_FILE" 2>/dev/null
if grep -q "^AGENT_VERSION=" "$CONFIG_FILE"; then
sed -i "s/^AGENT_VERSION=.*/AGENT_VERSION=\"$TARGET_VERSION\"/" "$CONFIG_FILE"
else
echo "AGENT_VERSION=\"$TARGET_VERSION\"" >> "$CONFIG_FILE"
fi
else
echo -e "\n📡 正在向指挥部发送注册暗号..."
# [修补重点] 必须转义,否则含有下划线的 SAFE_COMM_IP_ESC 在 Telegram Markdown 中会引发 400 Bad Request
SAFE_COMM_IP_ESC=$(echo "$SAFE_COMM_IP" | sed 's/_/\\_/g')
TEXT_MSG="✨ *IP-Sentinel 部署成功!*
📍 区域:${REGION_NAME}
🌐 养护 IP\`${SAFE_PUBLIC_IP}\`
📡 容灾 IP\`${SAFE_COMM_IP_ESC}\`
🔌 端口:\`${AGENT_PORT}\`
🔑 *请点击下方指令复制并回复给机器人:*
\`${REG_MSG}\`"
JSON_PAYLOAD=$(jq -n --arg cid "$CHAT_ID" --arg txt "$TEXT_MSG" --arg cb "manage:${NODE_NAME}" '{chat_id: $cid, text: $txt, parse_mode: "Markdown", reply_markup: {inline_keyboard: [[{text: "⚙️ 调出该节点控制台", callback_data: $cb}]]}}')
PUSH_RESULT=$(curl -s -X POST "${TG_API_URL}" -H "Content-Type: application/json" -d "$JSON_PAYLOAD")
if echo "$PUSH_RESULT" | grep -q '"ok":true'; then
echo -e "\033[32m✅ 注册信息已推送到您的 Telegram请按指令完成最终激活\033[0m"
else
echo -e "\033[31m❌ 消息推送失败,请检查 Chat ID 是否正确或是否已关注机器人。\033[0m"
fi
fi
fi
}
do_show_summary() {
echo "========================================================"
if [ "$UPGRADE_MODE" == "true" ]; then
echo "🎉 边缘节点 (Agent) 平滑热更新已彻底完成!"
else
echo "🎉 边缘节点 (Agent) 部署流程彻底完成!"
fi
echo "📍 你的本地守护区域已锁定为: $REGION_NAME"
echo "⚙️ 哨兵现已开启 [每20分钟] 的高频高拟真养护循环。"
if [[ -n "$TG_TOKEN" ]]; then
echo "📡 Webhook 监听已启动 (端口: $AGENT_PORT) 并向中枢发送了注册请求。"
echo -e "\n🛡 \033[36m[🔥 防火墙自动化操纵] 正在检测本地防线并全开双栈对空通道...\033[0m"
if command -v ufw >/dev/null 2>&1 && ufw status | grep -qw active; then
ufw allow "$AGENT_PORT"/tcp >/dev/null 2>&1
echo -e " ✅ \033[32mUFW 防火墙检测到活跃态,规则注入成功 (IPv4 & IPv6 双栈已通)。\033[0m"
elif command -v firewall-cmd >/dev/null 2>&1 && systemctl is-active firewalld | grep -qw active; then
firewall-cmd --zone=public --add-port="$AGENT_PORT"/tcp --permanent >/dev/null 2>&1
firewall-cmd --reload >/dev/null 2>&1
echo -e " ✅ \033[32mFirewalld 防火墙检测到活跃态,持久化策略重载完成。\033[0m"
else
local fw_applied=false
if command -v iptables >/dev/null 2>&1; then
iptables -I INPUT -p tcp --dport "$AGENT_PORT" -j ACCEPT >/dev/null 2>&1
fw_applied=true
fi
if command -v ip6tables >/dev/null 2>&1; then
ip6tables -I INPUT -p tcp --dport "$AGENT_PORT" -j ACCEPT >/dev/null 2>&1
fw_applied=true
fi
if [ "$fw_applied" = true ]; then
echo -e " ✅ \033[32mRaw Netfilter 链条锁定,已通过 iptables/ip6tables 强行挂载入站例外。\033[0m"
else
echo -e " 💡 \033[33m未检测到本机活跃的常规 Linux 防火墙组件,维持全通态势。\033[0m"
fi
fi
echo -e "\n\033[31m⚠ 【高危警告】您的节点通讯寻址池已锁定为: $SAFE_COMM_IP\033[0m"
echo -e "\033[33m为确保 Master 司令部能够成功下发指令,您【必须】前往云服务商 (如 AWS/Oracle/阿里云 等) 的网页控制台中,将安全组 (Security Group) 防火墙的 TCP $AGENT_PORT 端口彻底放行!\033[0m"
echo -e "\033[31m⛔ 本系统已开启全域双栈监听,禁止尝试通过修改脚本强行绑定局域网 IP 来绕过通信阻断!\033[0m\n"
fi
echo "🗑️ 若未来需卸载,可重新运行本脚本选择[2]或执行: bash ${INSTALL_DIR}/core/uninstall.sh"
echo "========================================================"
if [ "$UPGRADE_MODE" == "false" ]; then
echo -e "\n📡 正在向开源社区汇报装机量 (完全匿名不收集IP)..."
AGENT_COUNT=$(curl -s -m 3 "https://ip-sentinel-count.samanthaestime296.workers.dev/ping/agent" || echo "")
if [ -n "$AGENT_COUNT" ] && [[ "$AGENT_COUNT" =~ ^[0-9]+$ ]]; then
echo -e "\033[32m✅ 感谢您成为全球第 ${AGENT_COUNT} 名 IP-Sentinel 节点维护者!\033[0m"
else
echo -e "\033[32m✅ 感谢您部署 IP-Sentinel\033[0m"
fi
fi
echo -e "\n========================================================"
echo -e "⭐ \033[33m开源不易如果 IP-Sentinel 提升了您的节点稳定性,请赐予我们一枚星标!\033[0m"
echo -e "💡 \033[32m您的每一颗 Star 都是我们持续对抗风控、维护更新指纹库的核心动力。\033[0m"
echo -e "👉 \033[36m\033[4m\033]8;;https://github.com/hotyue/IP-Sentinel\033\\点击此处直达 GitHub 仓库点亮 Star 🌟\033[0m\033]8;;\033\\"
echo -e "========================================================\n"
}