#!/bin/bash GIT_BRANCH="main" AUTO_AGENT_URL="" AUTO_NODE_TOKEN="" AUTO_MODE=false MIGRATE_ARGS="" for arg in "$@"; do case $arg in --agent=*) AUTO_AGENT_URL="${arg#*=}"; AUTO_MODE=true ;; --token=*) AUTO_NODE_TOKEN="${arg#*=}"; AUTO_MODE=true ;; --branch=*) GIT_BRANCH="${arg#*=}" ;; main|develop) GIT_BRANCH="$arg" ;; esac done export DEBIAN_FRONTEND=noninteractive BOT_INSTALL_PATH="/opt/tg-bot" SERVICE_NAME="tg-bot" WATCHDOG_SERVICE_NAME="tg-watchdog" NODE_SERVICE_NAME="tg-node" SERVICE_USER="tgbot" PYTHON_BIN="/usr/bin/python3" VENV_PATH="${BOT_INSTALL_PATH}/venv" README_FILE="${BOT_INSTALL_PATH}/README.md" DOCKER_COMPOSE_FILE="${BOT_INSTALL_PATH}/docker-compose.yml" ENV_FILE="${BOT_INSTALL_PATH}/.env" GITHUB_REPO="jatixs/tgbotvpscp" GITHUB_REPO_URL="https://github.com/${GITHUB_REPO}.git" C_RESET='\033[0m'; C_RED='\033[0;31m'; C_GREEN='\033[0;32m'; C_YELLOW='\033[0;33m'; C_BLUE='\033[0;34m'; C_CYAN='\033[0;36m'; C_BOLD='\033[1m' msg_info() { echo -e "${C_CYAN}🔵 $1${C_RESET}"; }; msg_success() { echo -e "${C_GREEN}✅ $1${C_RESET}"; }; msg_warning() { echo -e "${C_YELLOW}⚠️ $1${C_RESET}"; }; msg_error() { echo -e "${C_RED}❌ $1${C_RESET}"; }; msg_question() { local prompt="$1" local var_name="$2" if [ -z "${!var_name}" ]; then read -p "$(echo -e "${C_YELLOW}❓ $prompt${C_RESET}")" $var_name fi } spinner() { local pid=$1 local msg=$2 local spin='|/-\' local i=0 while kill -0 $pid 2>/dev/null; do i=$(( (i+1) % 4 )) printf "\r${C_BLUE}⏳ ${spin:$i:1} ${msg}...${C_RESET}" sleep .1 done printf "\r" } run_with_spinner() { local msg=$1 shift ( "$@" >> /tmp/${SERVICE_NAME}_install.log 2>&1 ) & local pid=$! spinner "$pid" "$msg" wait $pid local exit_code=$? echo -ne "\033[2K\r" if [ $exit_code -ne 0 ]; then msg_error "Ошибка во время '$msg'. Код: $exit_code" msg_error "Подробности в логе: /tmp/${SERVICE_NAME}_install.log" echo -e "${C_YELLOW}Последние строки лога (/tmp/${SERVICE_NAME}_install.log):${C_RESET}" tail -n 10 /tmp/${SERVICE_NAME}_install.log fi return $exit_code } get_local_version() { if [ -f "${ENV_FILE}" ]; then local ver_env=$(grep '^INSTALLED_VERSION=' "${ENV_FILE}" | cut -d'=' -f2 | tr -d '"') if [ -n "$ver_env" ]; then echo "$ver_env" return fi fi if [ -f "$README_FILE" ]; then grep -oP 'img\.shields\.io/badge/version-v\K[\d\.]+' "$README_FILE" || echo "Не найдена" else echo "Не установлен" fi } INSTALL_TYPE="НЕТ"; STATUS_MESSAGE="Проверка не проводилась." INTEGRITY_STATUS="" check_integrity() { INTEGRITY_STATUS="" if [ ! -d "${BOT_INSTALL_PATH}" ] || [ ! -f "${ENV_FILE}" ]; then INSTALL_TYPE="НЕТ"; STATUS_MESSAGE="Бот не установлен."; return; fi DEPLOY_MODE_FROM_ENV=$(grep '^DEPLOY_MODE=' "${ENV_FILE}" | cut -d'=' -f2 | tr -d '"' || echo "systemd") IS_NODE=$(grep -q "MODE=node" "${ENV_FILE}" && echo "yes" || echo "no") if [ "$IS_NODE" == "yes" ]; then INTEGRITY_STATUS="${C_GREEN}🛡️ Режим НОДЫ (Git не требуется)${C_RESET}" elif [ -d "${BOT_INSTALL_PATH}/.git" ]; then cd "${BOT_INSTALL_PATH}" || return git fetch origin "$GIT_BRANCH" >/dev/null 2>&1 local FILES_TO_CHECK="core modules bot.py watchdog.py migrate.py manage.py" local DIFF=$(git diff --name-only "origin/$GIT_BRANCH" -- $FILES_TO_CHECK 2>/dev/null) if [ -n "$DIFF" ]; then INTEGRITY_STATUS="${C_RED}⚠️ ЦЕЛОСТНОСТЬ НАРУШЕНА (Файлы отличаются от origin/${GIT_BRANCH})${C_RESET}" else INTEGRITY_STATUS="${C_GREEN}🛡️ Код подтвержден${C_RESET}" fi cd - >/dev/null else INTEGRITY_STATUS="${C_YELLOW}⚠️ Git не найден${C_RESET}" fi if [ "$IS_NODE" == "yes" ]; then INSTALL_TYPE="НОДА (Клиент)" if systemctl is-active --quiet ${NODE_SERVICE_NAME}.service; then STATUS_MESSAGE="${C_GREEN}Активен${C_RESET}"; else STATUS_MESSAGE="${C_RED}Неактивен${C_RESET}"; fi return fi if [ "$DEPLOY_MODE_FROM_ENV" == "docker" ]; then INSTALL_TYPE="АГЕНТ (Docker)" if command -v docker &> /dev/null && docker ps | grep -q "tg-bot"; then STATUS_MESSAGE="${C_GREEN}Docker OK${C_RESET}"; else STATUS_MESSAGE="${C_RED}Docker Stop${C_RESET}"; fi else INSTALL_TYPE="АГЕНТ (Systemd)" if systemctl is-active --quiet ${SERVICE_NAME}.service; then STATUS_MESSAGE="${C_GREEN}Systemd OK${C_RESET}"; else STATUS_MESSAGE="${C_RED}Systemd Stop${C_RESET}"; fi fi } setup_nginx_proxy() { echo -e "\n${C_CYAN}🔒 Настройка HTTPS (Nginx + Certbot)${C_RESET}" run_with_spinner "Установка Nginx и Certbot" sudo apt-get install -y -q nginx certbot python3-certbot-nginx psmisc if command -v lsof &> /dev/null && lsof -Pi :80 -sTCP:LISTEN -t >/dev/null ; then sudo fuser -k 80/tcp 2>/dev/null sudo systemctl stop nginx 2>/dev/null elif command -v fuser &> /dev/null && sudo fuser 80/tcp >/dev/null; then sudo fuser -k 80/tcp sudo systemctl stop nginx 2>/dev/null fi if sudo certbot certonly --standalone --non-interactive --agree-tos --email "${HTTPS_EMAIL}" -d "${HTTPS_DOMAIN}"; then msg_success "Сертификат получен!" else msg_error "Ошибка получения сертификата." sudo systemctl start nginx return 1 fi NGINX_CONF="/etc/nginx/sites-available/${HTTPS_DOMAIN}" NGINX_LINK="/etc/nginx/sites-enabled/${HTTPS_DOMAIN}" if [ -f "/etc/nginx/sites-enabled/default" ]; then sudo rm -f "/etc/nginx/sites-enabled/default"; fi sudo bash -c "cat > ${NGINX_CONF}" < /dev/null; then sudo ufw allow ${HTTPS_PORT}/tcp >/dev/null; fi echo -e "Веб-панель доступна: https://${HTTPS_DOMAIN}:${HTTPS_PORT}/" else msg_error "Ошибка в конфиге Nginx." fi } common_install_steps() { echo "" > /tmp/${SERVICE_NAME}_install.log msg_info "1. Обновление системы..." run_with_spinner "Apt update" sudo apt-get update -y -q run_with_spinner "Установка пакетов" sudo apt-get install -y -q -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" python3 python3-pip python3-venv git curl wget sudo python3-yaml } setup_repo_and_dirs() { local owner_user=$1; if [ -z "$owner_user" ]; then owner_user="root"; fi cd / msg_info "Подготовка файлов (Ветка: ${GIT_BRANCH})..." if [ -f "${ENV_FILE}" ]; then cp "${ENV_FILE}" /tmp/tgbot_env.bak; fi if [ -d "${BOT_INSTALL_PATH}" ]; then run_with_spinner "Удаление старых файлов" sudo rm -rf "${BOT_INSTALL_PATH}"; fi sudo mkdir -p ${BOT_INSTALL_PATH} run_with_spinner "Клонирование репозитория" sudo git clone --branch "${GIT_BRANCH}" "${GITHUB_REPO_URL}" "${BOT_INSTALL_PATH}" || exit 1 if [ -f "/tmp/tgbot_env.bak" ]; then sudo mv /tmp/tgbot_env.bak "${ENV_FILE}"; fi sudo mkdir -p "${BOT_INSTALL_PATH}/logs/bot" "${BOT_INSTALL_PATH}/logs/watchdog" "${BOT_INSTALL_PATH}/logs/node" "${BOT_INSTALL_PATH}/config" sudo chown -R ${owner_user}:${owner_user} ${BOT_INSTALL_PATH} } load_cached_env() { local env_file="${ENV_FILE}" if [ ! -f "$env_file" ] && [ -f "/tmp/tgbot_env.bak" ]; then env_file="/tmp/tgbot_env.bak"; fi if [ -f "$env_file" ]; then echo -e "${C_YELLOW}⚠️ Обнаружена сохраненная конфигурация.${C_RESET}" read -p "$(echo -e "${C_CYAN}❓ Восстановить настройки? (y/n) [y]: ${C_RESET}")" RESTORE_CHOICE RESTORE_CHOICE=${RESTORE_CHOICE:-y} if [[ "$RESTORE_CHOICE" =~ ^[Yy]$ ]]; then msg_info "Загружаю сохраненные данные..." get_env_val() { grep "^$1=" "$env_file" | cut -d'=' -f2- | sed 's/^"//;s/"$//' | sed "s/^'//;s/'$//"; } [ -z "$T" ] && T=$(get_env_val "TG_BOT_TOKEN") [ -z "$A" ] && A=$(get_env_val "TG_ADMIN_ID") [ -z "$U" ] && U=$(get_env_val "TG_ADMIN_USERNAME") [ -z "$N" ] && N=$(get_env_val "TG_BOT_NAME") [ -z "$P" ] && P=$(get_env_val "WEB_SERVER_PORT") [ -z "$SENTRY_DSN" ] && SENTRY_DSN=$(get_env_val "SENTRY_DSN") if [ -z "$W" ]; then local val=$(get_env_val "ENABLE_WEB_UI") if [[ "$val" == "false" ]]; then W="n"; else W="y"; fi fi [ -z "$AGENT_URL" ] && AGENT_URL=$(get_env_val "AGENT_BASE_URL") [ -z "$NODE_TOKEN" ] && NODE_TOKEN=$(get_env_val "AGENT_TOKEN") else msg_info "Восстановление пропущено." fi fi } cleanup_common_trash() { if [ -d "$BOT_INSTALL_PATH/.github" ]; then sudo rm -rf "$BOT_INSTALL_PATH/.github"; fi if [ -d "$BOT_INSTALL_PATH/assets" ]; then sudo rm -rf "$BOT_INSTALL_PATH/assets"; fi sudo find "$BOT_INSTALL_PATH" -maxdepth 1 -type f \( -name "*.txt" -o -name "*.md" -o -name "*.ini" -o -name "*.sh" -o -name ".gitignore" -o -name "LICENSE" \) -delete sudo find "$BOT_INSTALL_PATH" -type d -name "__pycache__" -exec rm -rf {} + 2>/dev/null } cleanup_for_systemd() { local action_name=$1 msg_info "Завершение ${action_name}..." cleanup_common_trash sudo rm -rf "${BOT_INSTALL_PATH}/node" sudo rm -f "${BOT_INSTALL_PATH}/Dockerfile" "${BOT_INSTALL_PATH}/docker-compose.yml" } cleanup_for_docker() { local action_name=$1 msg_info "Завершение ${action_name}..." cleanup_common_trash cd "${BOT_INSTALL_PATH}" sudo rm -rf node sudo rm -rf core modules bot.py watchdog.py manage.py migrate.py aerich.ini sudo rm -f Dockerfile } cleanup_for_node() { local action_name=$1 msg_info "Завершение ${action_name}..." cleanup_common_trash cd ${BOT_INSTALL_PATH} sudo rm -rf core modules bot.py watchdog.py Dockerfile docker-compose.yml .git config/users.json config/alerts_config.json } install_extras() { if ! command -v fail2ban-client &> /dev/null; then msg_question "Fail2Ban не найден. Установить? (y/n): " I; if [[ "$I" =~ ^[Yy]$ ]]; then run_with_spinner "Установка Fail2ban" sudo apt-get install -y -q fail2ban; fi fi if ! command -v iperf3 &> /dev/null; then msg_question "iperf3 не найден. Установить? (y/n): " I; if [[ "$I" =~ ^[Yy]$ ]]; then run_with_spinner "Установка iperf3" sudo apt-get install -y -q iperf3; fi fi } ask_env_details() { msg_info "Ввод данных .env..." msg_question "Токен Ботa: " T; msg_question "ID Админа: " A; msg_question "Username (opt): " U; msg_question "Bot Name (opt): " N msg_question "Внутренний Web Port [8080]: " P; if [ -z "$P" ]; then WEB_PORT="8080"; else WEB_PORT="$P"; fi msg_question "Sentry DSN (opt): " SENTRY_DSN msg_question "Включить Web-UI? (y/n) [y]: " W if [[ "$W" =~ ^[Nn]$ ]]; then ENABLE_WEB="false" SETUP_HTTPS="false" else ENABLE_WEB="true" GEN_PASS=$(tr -dc A-Za-z0-9 ${ENV_FILE}" < /dev/null; then curl -sSL https://get.docker.com -o /tmp/get-docker.sh; run_with_spinner "Установка Docker" sudo sh /tmp/get-docker.sh; fi if command -v docker-compose &> /dev/null; then sudo rm -f $(which docker-compose); fi } create_dockerfile() { sudo tee "${BOT_INSTALL_PATH}/Dockerfile" > /dev/null <<'EOF' FROM python:3.10-slim-bookworm RUN apt-get update && apt-get install -y python3-yaml iperf3 git curl wget sudo procps iputils-ping net-tools gnupg docker.io coreutils && rm -rf /var/lib/apt/lists/* RUN pip install --no-cache-dir docker aiohttp aiosqlite argon2-cffi sentry-sdk tortoise-orm aerich cryptography tomlkit RUN groupadd -g 1001 tgbot && useradd -u 1001 -g 1001 -m -s /bin/bash tgbot && echo "tgbot ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers WORKDIR /opt/tg-bot COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . RUN mkdir -p /opt/tg-bot/config /opt/tg-bot/logs/bot /opt/tg-bot/logs/watchdog && chown -R tgbot:tgbot /opt/tg-bot USER tgbot CMD ["python", "bot.py"] EOF } create_docker_compose_yml() { sudo tee "${BOT_INSTALL_PATH}/docker-compose.yml" > /dev/null < /dev/null < /dev/null; sudo systemctl restart ${svc} } run_db_migrations() { local exec_user=$1 msg_info "Миграция базы данных и настроек..." cd "${BOT_INSTALL_PATH}" || return 1 if [ -f "${ENV_FILE}" ]; then set -a; source "${ENV_FILE}"; set +a; fi local cmd_prefix=""; if [ -n "$exec_user" ]; then cmd_prefix="sudo -E -u ${SERVICE_USER}"; fi if [ ! -f "${BOT_INSTALL_PATH}/aerich.ini" ]; then $cmd_prefix ${VENV_PATH}/bin/aerich init -t core.config.TORTOISE_ORM >/dev/null 2>&1; fi if [ ! -d "${BOT_INSTALL_PATH}/migrations" ]; then if ! $cmd_prefix ${VENV_PATH}/bin/aerich init-db; then :; fi else $cmd_prefix ${VENV_PATH}/bin/aerich upgrade >/dev/null 2>&1 fi if [ -f "${BOT_INSTALL_PATH}/migrate.py" ]; then $cmd_prefix ${VENV_PATH}/bin/python "${BOT_INSTALL_PATH}/migrate.py" $MIGRATE_ARGS fi } install_systemd_logic() { local mode=$1 common_install_steps install_extras local exec_cmd="" if [ "$mode" == "secure" ]; then if ! id "${SERVICE_USER}" &>/dev/null; then sudo useradd -r -s /bin/false -d ${BOT_INSTALL_PATH} ${SERVICE_USER}; fi setup_repo_and_dirs "${SERVICE_USER}" sudo -u ${SERVICE_USER} ${PYTHON_BIN} -m venv "${VENV_PATH}" run_with_spinner "Обновление pip" sudo -u ${SERVICE_USER} "${VENV_PATH}/bin/pip" install --upgrade pip run_with_spinner "Установка зависимостей" sudo -u ${SERVICE_USER} "${VENV_PATH}/bin/pip" install -r "${BOT_INSTALL_PATH}/requirements.txt" run_with_spinner "Установка tomlkit" sudo -u ${SERVICE_USER} "${VENV_PATH}/bin/pip" install tomlkit exec_cmd="sudo -u ${SERVICE_USER}" else setup_repo_and_dirs "root" ${PYTHON_BIN} -m venv "${VENV_PATH}" run_with_spinner "Обновление pip" "${VENV_PATH}/bin/pip" install --upgrade pip run_with_spinner "Установка зависимостей" "${VENV_PATH}/bin/pip" install -r "${BOT_INSTALL_PATH}/requirements.txt" run_with_spinner "Установка tomlkit" "${VENV_PATH}/bin/pip" install tomlkit exec_cmd="" fi load_cached_env ask_env_details write_env_file "systemd" "$mode" "" run_db_migrations "$exec_cmd" cleanup_for_systemd "установки" create_and_start_service "${SERVICE_NAME}" "${BOT_INSTALL_PATH}/bot.py" "$mode" "Telegram Bot" create_and_start_service "${WATCHDOG_SERVICE_NAME}" "${BOT_INSTALL_PATH}/watchdog.py" "root" "Наблюдатель" msg_info "Создание команды 'tgcp-bot'..." sudo bash -c "cat > /usr/local/bin/tgcp-bot" </dev/null; then dc_cmd="docker compose"; else dc_cmd="docker-compose"; fi run_with_spinner "Сборка Docker" sudo $dc_cmd build run_with_spinner "Запуск Docker" sudo $dc_cmd --profile "${mode}" up -d --remove-orphans msg_info "Миграция в контейнере..." sudo $dc_cmd --profile "${mode}" exec -T ${container_name} aerich init -t core.config.TORTOISE_ORM >/dev/null 2>&1 sudo $dc_cmd --profile "${mode}" exec -T ${container_name} aerich init-db >/dev/null 2>&1 sudo $dc_cmd --profile "${mode}" exec -T ${container_name} aerich upgrade >/dev/null 2>&1 sudo $dc_cmd --profile "${mode}" exec -T ${container_name} python migrate.py $MIGRATE_ARGS >/dev/null 2>&1 cleanup_for_docker "установки" sudo bash -c "cat > /usr/local/bin/tgcp-bot" < ${ENV_FILE}" < /dev/null < /dev/null sudo systemctl disable ${SERVICE_NAME} ${WATCHDOG_SERVICE_NAME} ${NODE_SERVICE_NAME} &> /dev/null sudo rm -f /etc/systemd/system/${SERVICE_NAME}.service /etc/systemd/system/${WATCHDOG_SERVICE_NAME}.service /etc/systemd/system/${NODE_SERVICE_NAME}.service sudo systemctl daemon-reload if [ -f "${DOCKER_COMPOSE_FILE}" ]; then cd ${BOT_INSTALL_PATH} && sudo docker-compose down -v --remove-orphans &> /dev/null; fi sudo rm -rf "${BOT_INSTALL_PATH}" sudo rm -f /usr/local/bin/tgcp-bot if id "${SERVICE_USER}" &>/dev/null; then sudo userdel -r "${SERVICE_USER}" &> /dev/null; fi msg_success "Удалено." } update_bot() { echo -e "\n${C_BOLD}=== Обновление ===${C_RESET}" if [ -f "${ENV_FILE}" ] && grep -q "MODE=node" "${ENV_FILE}"; then install_node_logic; return; fi if [ ! -d "${BOT_INSTALL_PATH}/.git" ]; then msg_error "Git не найден."; return 1; fi echo "" > /tmp/${SERVICE_NAME}_install.log local exec_cmd="" if [ -f "${ENV_FILE}" ] && grep -q "INSTALL_MODE=secure" "${ENV_FILE}"; then exec_cmd="sudo -u ${SERVICE_USER}"; fi cd "${BOT_INSTALL_PATH}" if ! run_with_spinner "Git fetch" $exec_cmd git fetch origin; then return 1; fi if ! run_with_spinner "Git reset" $exec_cmd git reset --hard "origin/${GIT_BRANCH}"; then return 1; fi if [ -f "$README_FILE" ]; then local new_ver=$(grep -oP 'img\.shields\.io/badge/version-v\K[\d\.]+' "$README_FILE") if [ -n "$new_ver" ] && [ -f "${ENV_FILE}" ]; then if grep -q "^INSTALLED_VERSION=" "${ENV_FILE}"; then sudo sed -i "s/^INSTALLED_VERSION=.*/INSTALLED_VERSION=${new_ver}/" "${ENV_FILE}" else sudo bash -c "echo 'INSTALLED_VERSION=${new_ver}' >> ${ENV_FILE}" fi fi fi local current_mode=$(grep '^DEPLOY_MODE=' "${ENV_FILE}" | cut -d'=' -f2 | tr -d '"') if [ "$current_mode" == "docker" ]; then if [ -f "docker-compose.yml" ]; then local dc_cmd=""; if sudo docker compose version &>/dev/null; then dc_cmd="docker compose"; else dc_cmd="docker-compose"; fi if ! run_with_spinner "Docker Up" sudo $dc_cmd up -d --build; then msg_error "Ошибка Docker."; return 1; fi sudo bash -c "cat > /usr/local/bin/tgcp-bot" < /usr/local/bin/tgcp-bot" </dev/null 2>&1 sudo $dc_cmd --profile "${mode}" exec -T ${cn} python migrate.py $MIGRATE_ARGS >/dev/null 2>&1 cleanup_for_docker "обновления" else run_db_migrations "$exec_cmd" cleanup_for_systemd "обновления" fi msg_success "Обновлено." } main_menu() { local local_version=$(get_local_version) while true; do clear echo -e "${C_BLUE}${C_BOLD}╔═══════════════════════════════════╗${C_RESET}" echo -e "${C_BLUE}${C_BOLD}║ Менеджер VPS Telegram Бот ║${C_RESET}" echo -e "${C_BLUE}${C_BOLD}╚═══════════════════════════════════╝${C_RESET}" check_integrity echo -e " Ветка: ${GIT_BRANCH} | Версия: ${local_version}" echo -e " Тип: ${INSTALL_TYPE} | Статус: ${STATUS_MESSAGE}" if [ -n "$INTEGRITY_STATUS" ]; then echo -e " Интегритет: ${INTEGRITY_STATUS}"; fi echo "--------------------------------------------------------" echo " 1) Обновить бота" echo " 2) Удалить бота" echo " 3) Переустановить (Systemd - Secure)" echo " 4) Переустановить (Systemd - Root)" echo " 5) Переустановить (Docker - Secure)" echo " 6) Переустановить (Docker - Root)" echo -e "${C_GREEN} 7) Установить НОДУ (Клиент)${C_RESET}" echo " 0) Выход" echo "--------------------------------------------------------" read -p "$(echo -e "${C_BOLD}Ваш выбор: ${C_RESET}")" choice case $choice in 1) update_bot; read -p "Нажмите Enter..." ;; 2) msg_question "Удалить? (y/n): " c; if [[ "$c" =~ ^[Yy]$ ]]; then uninstall_bot; return; fi ;; 3) uninstall_bot; install_systemd_logic "secure"; read -p "Нажмите Enter..." ;; 4) uninstall_bot; install_systemd_logic "root"; read -p "Нажмите Enter..." ;; 5) uninstall_bot; install_docker_logic "secure"; read -p "Нажмите Enter..." ;; 6) uninstall_bot; install_docker_logic "root"; read -p "Нажмите Enter..." ;; 7) uninstall_bot; install_node_logic; read -p "Нажмите Enter..." ;; 0) break ;; esac done } if [ "$(id -u)" -ne 0 ]; then msg_error "Нужен root."; exit 1; fi if [ "$AUTO_MODE" = true ] && [ -n "$AUTO_AGENT_URL" ] && [ -n "$AUTO_NODE_TOKEN" ]; then install_node_logic; exit 0; fi check_integrity if [ "$INSTALL_TYPE" == "НЕТ" ]; then clear echo -e "${C_BLUE}${C_BOLD}╔═══════════════════════════════════╗${C_RESET}" echo -e "${C_BLUE}${C_BOLD}║ Установка VPS Manager Bot ║${C_RESET}" echo -e "${C_BLUE}${C_BOLD}╚═══════════════════════════════════╝${C_RESET}" echo -e " Выберите режим установки:" echo "--------------------------------------------------------" echo " 1) АГЕНТ (Systemd - Secure) [Рекомендуется]" echo " 2) АГЕНТ (Systemd - Root) [Полный доступ]" echo " 3) АГЕНТ (Docker - Secure) [Изоляция]" echo " 4) АГЕНТ (Docker - Root) [Docker + Host]" echo -e "${C_GREEN} 7) НОДА (Клиент)${C_RESET}" echo " 0) Выход" echo "--------------------------------------------------------" read -p "$(echo -e "${C_BOLD}Ваш выбор: ${C_RESET}")" ch case $ch in 1) uninstall_bot; install_systemd_logic "secure"; read -p "Нажмите Enter..." ;; 2) uninstall_bot; install_systemd_logic "root"; read -p "Нажмите Enter..." ;; 3) uninstall_bot; install_docker_logic "secure"; read -p "Нажмите Enter..." ;; 4) uninstall_bot; install_docker_logic "root"; read -p "Нажмите Enter..." ;; 7) uninstall_bot; install_node_logic; read -p "Нажмите Enter..." ;; 0) exit 0 ;; *) msg_error "Неверный выбор."; sleep 2 ;; esac main_menu else main_menu fi