UI: спиннер, прогресс-бар и галочки на каждом шаге установки

Made-with: Cursor
This commit is contained in:
anten-ka
2026-03-06 18:54:05 +03:00
parent 8320d4dd06
commit 11d9cf6772

View File

@@ -12,6 +12,53 @@ BLUE='\033[0;34m'
WHITE='\033[1;37m'
NC='\033[0m'
# ── Спиннер и прогресс-бар ────────────────────────────────────────────────────
spin_pid=""
spinner_start() {
local msg="${1:-Подождите...}"
(
local frames=('⠋' '⠙' '⠹' '⠸' '⠼' '⠴' '⠦' '⠧' '⠇' '⠏')
local i=0
while true; do
printf "\r ${CYAN}${frames[$i]}${NC} ${msg}" >&2
i=$(( (i+1) % ${#frames[@]} ))
sleep 0.12
done
) &
spin_pid=$!
}
spinner_stop() {
[ -n "$spin_pid" ] && kill "$spin_pid" 2>/dev/null && wait "$spin_pid" 2>/dev/null
spin_pid=""
printf "\r\033[K" >&2
}
progress_bar() {
local current="$1" total="$2" label="${3:-}"
local pct=$(( current * 100 / total ))
local filled=$(( pct / 2 ))
local empty=$(( 50 - filled ))
local bar=""
for ((i=0; i<filled; i++)); do bar+="█"; done
for ((i=0; i<empty; i++)); do bar+="░"; done
printf "\r ${GREEN}[${bar}]${NC} ${pct}%% ${label}" >&2
[ "$current" -eq "$total" ] && echo "" >&2
}
run_with_progress() {
local label="$1"; shift
spinner_start "$label"
"$@" >/dev/null 2>&1
local rc=$?
spinner_stop
if [ $rc -eq 0 ]; then
echo -e " ${GREEN}${NC} $label"
else
echo -e " ${RED}${NC} $label ${RED}(ошибка)${NC}"
fi
return $rc
}
# ── Конфиг ───────────────────────────────────────────────────────────────────
CONTAINER_NAME="mtproto-proxy"
BOT_DIR="/opt/gotelegram-bot"
@@ -37,24 +84,34 @@ install_pkg() {
}
install_base_deps() {
for cmd in curl docker; do
if ! command -v $cmd &>/dev/null; then
echo -e "${YELLOW}[*] Установка $cmd...${NC}"
if [ "$cmd" = "docker" ]; then
curl -fsSL https://get.docker.com | sh
systemctl enable --now docker
else
install_pkg $cmd
local steps=0 total=4 # curl, docker, qrencode, docker-start
progress_bar $steps $total "Проверка зависимостей..."
if ! command -v curl &>/dev/null; then
run_with_progress "Установка curl" install_pkg curl
fi
steps=$((steps+1)); progress_bar $steps $total "curl"
if ! command -v docker &>/dev/null; then
spinner_start "Установка Docker (это может занять 1-2 минуты)..."
curl -fsSL https://get.docker.com | sh >/dev/null 2>&1
systemctl enable --now docker >/dev/null 2>&1
spinner_stop
echo -e " ${GREEN}${NC} Docker установлен"
fi
done
steps=$((steps+1)); progress_bar $steps $total "docker"
if ! command -v qrencode &>/dev/null; then
install_pkg qrencode 2>/dev/null || true
run_with_progress "Установка qrencode" install_pkg qrencode
fi
steps=$((steps+1)); progress_bar $steps $total "qrencode"
if ! docker info &>/dev/null 2>&1; then
systemctl start docker 2>/dev/null || true
sleep 2
fi
steps=$((steps+1)); progress_bar $steps $total "Готово"
echo ""
}
# ── Утилиты ──────────────────────────────────────────────────────────────────
@@ -225,6 +282,7 @@ menu_install() {
echo ""
echo -e "${YELLOW}[*] Настройка прокси (домен: $DOMAIN, порт: $PORT)...${NC}"
echo ""
# Docker проверка
if ! docker info &>/dev/null 2>&1; then
@@ -233,43 +291,65 @@ menu_install() {
return
fi
# Генерация secret
echo -e "${GREEN}[*] Генерация secret...${NC}"
local SECRET
local SECRET install_steps=5 install_cur=0
# Шаг 1: pull образа (если нет)
install_cur=$((install_cur+1)); progress_bar $install_cur $install_steps "Загрузка образа mtg..."
if ! docker images --format '{{.Repository}}:{{.Tag}}' | grep -q "nineseconds/mtg:2"; then
spinner_start "Загрузка Docker-образа mtg (первый раз — до 1 мин)..."
docker pull nineseconds/mtg:2 >/dev/null 2>&1
spinner_stop
fi
echo -e " ${GREEN}${NC} Образ mtg готов"
# Шаг 2: генерация secret
install_cur=$((install_cur+1)); progress_bar $install_cur $install_steps "Генерация secret..."
spinner_start "Генерация secret для $DOMAIN..."
SECRET=$(docker run --rm nineseconds/mtg:2 generate-secret --hex "$DOMAIN" 2>/dev/null)
spinner_stop
if [ -z "$SECRET" ]; then
echo -e "${RED}Ошибка генерации secret.${NC}"
echo -e " ${RED}${NC} Ошибка генерации secret."
read -p "Нажмите Enter..."
return
fi
echo -e " ${GREEN}${NC} Secret сгенерирован"
# Остановка старого
# Шаг 3: остановка старого
install_cur=$((install_cur+1)); progress_bar $install_cur $install_steps "Очистка..."
docker stop "$CONTAINER_NAME" &>/dev/null
docker rm "$CONTAINER_NAME" &>/dev/null
echo -e " ${GREEN}${NC} Старый контейнер удалён"
# Запуск с TCP + UDP (UDP для звонков)
echo -e "${GREEN}[*] Запуск контейнера (TCP + UDP)...${NC}"
# Шаг 4: запуск нового
install_cur=$((install_cur+1)); progress_bar $install_cur $install_steps "Запуск контейнера..."
spinner_start "Запуск MTProxy (TCP + UDP)..."
docker run -d --name "$CONTAINER_NAME" --restart always \
-p "$PORT":"$PORT"/tcp \
-p "$PORT":"$PORT"/udp \
nineseconds/mtg:2 simple-run \
-n 1.1.1.1 -i prefer-ipv4 \
0.0.0.0:"$PORT" "$SECRET" > /dev/null 2>&1
sleep 2
spinner_stop
if ! proxy_is_running; then
echo -e "${RED}Контейнер не запустился. Проверьте: docker logs $CONTAINER_NAME${NC}"
echo -e " ${RED}${NC} Контейнер не запустился. Проверьте: docker logs $CONTAINER_NAME"
read -p "Нажмите Enter..."
return
fi
echo -e " ${GREEN}${NC} Контейнер запущен"
# Сохраняем конфиг
# Шаг 5: сохранение
install_cur=$((install_cur+1)); progress_bar $install_cur $install_steps "Готово!"
mkdir -p "$BOT_DIR"
cat > "$BOT_DIR/proxy.json" << CFGEOF
{"domain": "$DOMAIN", "port": "$PORT", "secret": "$SECRET"}
CFGEOF
clear
echo -e "${GREEN}Прокси установлен! (TCP + UDP, звонки поддержаны)${NC}"
echo ""
echo -e "${GREEN}══════════════════════════════════════════════════${NC}"
echo -e "${GREEN} Прокси установлен! (TCP + UDP, звонки поддержаны)${NC}"
echo -e "${GREEN}══════════════════════════════════════════════════${NC}"
show_config
read -p "Нажмите Enter для возврата в меню..."
}
@@ -817,13 +897,36 @@ BOTEOF
}
install_bot_deps() {
echo -e "${GREEN}[*] Настройка Python venv...${NC}"
local bot_steps=3 bot_cur=0
bot_cur=$((bot_cur+1)); progress_bar $bot_cur $bot_steps "Создание venv..."
if [ ! -d "$BOT_DIR/venv" ]; then
python3 -m venv "$BOT_DIR/venv" || { echo -e "${RED}Ошибка создания venv.${NC}"; return 1; }
spinner_start "Создание Python venv..."
python3 -m venv "$BOT_DIR/venv" 2>/dev/null
spinner_stop
if [ ! -d "$BOT_DIR/venv" ]; then
echo -e " ${RED}${NC} Ошибка создания venv."
return 1
fi
echo -e "${GREEN}[*] Установка зависимостей (pip)...${NC}"
"$BOT_DIR/venv/bin/pip" install --upgrade pip -q 2>/dev/null || true
"$BOT_DIR/venv/bin/pip" install -r "$BOT_DIR/requirements.txt" -q || { echo -e "${RED}pip install не удался.${NC}"; return 1; }
fi
echo -e " ${GREEN}${NC} Python venv готов"
bot_cur=$((bot_cur+1)); progress_bar $bot_cur $bot_steps "Обновление pip..."
spinner_start "Обновление pip..."
"$BOT_DIR/venv/bin/pip" install --upgrade pip -q 2>/dev/null
spinner_stop
echo -e " ${GREEN}${NC} pip обновлён"
bot_cur=$((bot_cur+1)); progress_bar $bot_cur $bot_steps "Установка зависимостей..."
spinner_start "Установка python-telegram-bot (до 1 мин)..."
"$BOT_DIR/venv/bin/pip" install -r "$BOT_DIR/requirements.txt" -q 2>/dev/null
local rc=$?
spinner_stop
if [ $rc -ne 0 ]; then
echo -e " ${RED}${NC} pip install не удался."
return 1
fi
echo -e " ${GREEN}${NC} Зависимости установлены"
}
# ── Выход ────────────────────────────────────────────────────────────────────