Update install_bot.sh

This commit is contained in:
Egor
2025-10-01 21:55:46 +03:00
committed by GitHub
parent 0d47acf044
commit 7684ed382e

View File

@@ -3,141 +3,86 @@ set -euo pipefail
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
STATE_FILE="$SCRIPT_DIR/.bot_install_state"
DEFAULT_INSTALL_PATH="$SCRIPT_DIR"
DEFAULT_ENV_FILE=".env"
BACKUP_DIR="$SCRIPT_DIR/backups"
# Util functions
log() {
printf '\n%s\n' "$1"
# Цвета для красивого вывода
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
PURPLE='\033[0;35m'
CYAN='\033[0;36m'
WHITE='\033[1;37m'
NC='\033[0m' # No Color
BOLD='\033[1m'
# Символы для UI
CHECK="✓"
CROSS="✗"
ARROW="➜"
STAR="★"
GEAR="⚙"
# Утилиты для вывода
print_header() {
echo -e "\n${CYAN}${BOLD}╔════════════════════════════════════════════════════════════╗${NC}"
echo -e "${CYAN}${BOLD}${NC} ${WHITE}${BOLD}$1${NC}${CYAN}${BOLD}${NC}"
echo -e "${CYAN}${BOLD}╚════════════════════════════════════════════════════════════╝${NC}\n"
}
error() {
printf 'Error: %s\n' "$1" >&2
print_section() {
echo -e "\n${BLUE}${BOLD}${ARROW} $1${NC}"
echo -e "${BLUE}─────────────────────────────────────────────────────${NC}"
}
ask_yes_no() {
local prompt="$1"
local default="$2"
local reply
while true; do
read -rp "$prompt" reply || reply=""
if [[ -z "$reply" ]]; then
reply="$default"
fi
case "${reply,,}" in
y|yes)
return 0
;;
n|no)
return 1
;;
*)
echo "Пожалуйста, ответьте 'y' или 'n'."
;;
esac
done
print_success() {
echo -e "${GREEN}${CHECK} $1${NC}"
}
prompt_value() {
local var_name="$1"
local prompt="$2"
local default_value="$3"
local reply
if [[ -n "$default_value" ]]; then
read -rp "$prompt [$default_value]: " reply || reply=""
print_error() {
echo -e "${RED}${CROSS} $1${NC}" >&2
}
print_warning() {
echo -e "${YELLOW}$1${NC}"
}
print_info() {
echo -e "${CYAN} $1${NC}"
}
print_status() {
local status=$1
local text=$2
if [[ "$status" == "running" ]]; then
echo -e "${GREEN}${text}${NC}"
elif [[ "$status" == "stopped" ]]; then
echo -e "${RED}${text}${NC}"
else
read -rp "$prompt: " reply || reply=""
fi
if [[ -z "$reply" ]]; then
printf '%s' "$default_value"
else
printf '%s' "$reply"
fi
}
escape_env_value() {
printf '%s' "$1" | sed 's/\\\\/\\\\\\\\/g; s/"/\\"/g'
}
write_env_file() {
local env_file="$1"
shift
local entries=("$@")
{
for entry in "${entries[@]}"; do
local key=${entry%%=*}
local value=${entry#*=}
printf '%s="%s"\n' "$key" "$(escape_env_value "$value")"
done
} >"$env_file"
}
get_env_value() {
local key="$1"
local env_file="$2"
if [[ -f "$env_file" ]]; then
local line
line=$(grep -E "^${key}=" "$env_file" | tail -n1 || true)
if [[ -n "$line" ]]; then
printf '%s' "${line#*=}" | sed 's/^"//; s/"$//'
return
fi
fi
printf ''
}
ensure_directory_structure() {
local path="$1"
mkdir -p "$path/logs" "$path/data" "$path/data/backups" "$path/data/referral_qr"
chmod -R 755 "$path/logs" "$path/data"
if command -v sudo >/dev/null 2>&1; then
sudo chown -R 1000:1000 "$path/logs" "$path/data" || true
else
chown -R 1000:1000 "$path/logs" "$path/data" 2>/dev/null || true
fi
}
sync_project_files() {
local destination="$1"
if [[ "$SCRIPT_DIR" == "$destination" ]]; then
return
fi
log "Синхронизируем файлы проекта в $destination"
local excludes=(--exclude '.git' --exclude '__pycache__' --exclude 'logs' --exclude 'data' --exclude '.bot_install_state' --exclude '.env')
if command -v rsync >/dev/null 2>&1; then
rsync -a --delete "${excludes[@]}" "$SCRIPT_DIR/" "$destination/"
else
(cd "$SCRIPT_DIR" && tar cf - --exclude='.git' --exclude='__pycache__' --exclude='logs' --exclude='data' --exclude='.bot_install_state' --exclude='.env' .) \
| (cd "$destination" && tar xf -)
echo -e "${YELLOW} ${text}${NC}"
fi
}
# Загрузка состояния
load_state() {
if [[ -f "$STATE_FILE" ]]; then
# shellcheck disable=SC1090
source "$STATE_FILE"
return 0
else
INSTALL_PATH="$DEFAULT_INSTALL_PATH"
ENV_FILE="$DEFAULT_ENV_FILE"
print_error "Установка бота не найдена. Запустите ./install.sh сначала."
exit 1
fi
}
save_state() {
cat >"$STATE_FILE" <<EOF_STATE
INSTALL_PATH="$INSTALL_PATH"
ENV_FILE="$ENV_FILE"
INSTALLED_AT="$(date --iso-8601=seconds)"
EOF_STATE
}
# Определение команды docker compose
resolve_compose_command() {
if docker compose version >/dev/null 2>&1; then
COMPOSE_BIN=(docker compose)
elif docker-compose version >/dev/null 2>&1; then
COMPOSE_BIN=(docker-compose)
else
error "Docker Compose не найден. Установите docker compose или docker-compose."
print_error "Docker Compose не найден."
exit 1
fi
}
@@ -146,117 +91,524 @@ run_compose() {
(cd "$INSTALL_PATH" && "${COMPOSE_BIN[@]}" "$@")
}
show_services_state() {
log "Текущее состояние сервисов:"
run_compose ps
# Получение статуса сервисов
get_service_status() {
local service=$1
local status
status=$(run_compose ps -q "$service" 2>/dev/null | xargs -r docker inspect -f '{{.State.Status}}' 2>/dev/null || echo "not_found")
echo "$status"
}
follow_logs() {
if ask_yes_no "Хотите посмотреть последние логи бота? [y/N]: " "n"; then
run_compose logs --tail=50 bot || true
fi
}
start_services() {
log "Запускаем сервисы бота..."
run_compose up -d
show_services_state
follow_logs
}
perform_installation() {
INSTALL_PATH=$(prompt_value "INSTALL_PATH" "Укажите путь установки бота" "$DEFAULT_INSTALL_PATH")
INSTALL_PATH=${INSTALL_PATH%/}
if [[ ! -d "$INSTALL_PATH" ]]; then
mkdir -p "$INSTALL_PATH"
log "Создана директория установки $INSTALL_PATH"
fi
sync_project_files "$INSTALL_PATH"
ENV_FILE="$INSTALL_PATH/$DEFAULT_ENV_FILE"
ensure_directory_structure "$INSTALL_PATH"
local existing_env
if [[ -f "$ENV_FILE" ]]; then
existing_env="true"
else
existing_env="false"
fi
log "Заполняем параметры окружения (.env)."
local bot_token admin_ids api_url api_key auth_type username password secret_key web_api_token
bot_token=$(prompt_value "BOT_TOKEN" "Введите BOT_TOKEN" "$(get_env_value BOT_TOKEN "$ENV_FILE")")
admin_ids=$(prompt_value "ADMIN_IDS" "Введите ADMIN_IDS (через запятую)" "$(get_env_value ADMIN_IDS "$ENV_FILE")")
printf '\nREMNAWAVE_API_URL должен быть в формате https://panel.example.com или http://remnawave:3000 при локальном запуске.\n'
api_url=$(prompt_value "REMNAWAVE_API_URL" "Введите REMNAWAVE_API_URL" "$(get_env_value REMNAWAVE_API_URL "$ENV_FILE")")
api_key=$(prompt_value "REMNAWAVE_API_KEY" "Введите REMNAWAVE_API_KEY" "$(get_env_value REMNAWAVE_API_KEY "$ENV_FILE")")
local default_auth
default_auth=$(get_env_value REMNAWAVE_AUTH_TYPE "$ENV_FILE")
auth_type=$(prompt_value "REMNAWAVE_AUTH_TYPE" "Введите тип авторизации REMNAWAVE (api_key/basic_auth)" "${default_auth:-api_key}")
username=""
password=""
if [[ "${auth_type}" == "basic_auth" ]]; then
username=$(prompt_value "REMNAWAVE_USERNAME" "Введите REMNAWAVE_USERNAME" "$(get_env_value REMNAWAVE_USERNAME "$ENV_FILE")")
password=$(prompt_value "REMNAWAVE_PASSWORD" "Введите REMNAWAVE_PASSWORD" "$(get_env_value REMNAWAVE_PASSWORD "$ENV_FILE")")
else
if ask_yes_no "Указать REMNAWAVE_USERNAME/REMNAWAVE_PASSWORD? [y/N]: " "n"; then
username=$(prompt_value "REMNAWAVE_USERNAME" "Введите REMNAWAVE_USERNAME" "$(get_env_value REMNAWAVE_USERNAME "$ENV_FILE")")
password=$(prompt_value "REMNAWAVE_PASSWORD" "Введите REMNAWAVE_PASSWORD" "$(get_env_value REMNAWAVE_PASSWORD "$ENV_FILE")")
# Мониторинг сервисов
show_monitoring() {
print_header "МОНИТОРИНГ СЕРВИСОВ БОТА"
print_section "Статус контейнеров"
local services=("bot" "postgres" "redis")
local all_running=true
for service in "${services[@]}"; do
local status
status=$(get_service_status "$service")
local uptime=""
if [[ "$status" == "running" ]]; then
uptime=$(run_compose ps "$service" 2>/dev/null | tail -n1 | awk '{for(i=1;i<=NF;i++){if($i~/Up/){print $(i+1), $(i+2); break}}}')
print_status "running" "$service: работает (uptime: $uptime)"
elif [[ "$status" == "exited" ]] || [[ "$status" == "stopped" ]]; then
print_status "stopped" "$service: остановлен"
all_running=false
else
print_status "unknown" "$service: не найден"
all_running=false
fi
done
# Статистика ресурсов
print_section "Использование ресурсов"
local stats
stats=$(docker stats --no-stream --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}" 2>/dev/null | grep -E "bot|postgres|redis" || echo "")
if [[ -n "$stats" ]]; then
echo -e "${WHITE}${BOLD}КОНТЕЙНЕР CPU ПАМЯТЬ${NC}"
echo "$stats" | tail -n+2 | while IFS=$'\t' read -r name cpu mem; do
echo -e "${CYAN}${name}${NC} ${YELLOW}${cpu}${NC} ${PURPLE}${mem}${NC}"
done
else
print_warning "Статистика недоступна"
fi
# Размер логов
print_section "Размер логов"
if [[ -d "$INSTALL_PATH/logs" ]]; then
local log_size
log_size=$(du -sh "$INSTALL_PATH/logs" 2>/dev/null | cut -f1)
echo -e "${CYAN}Логи: ${YELLOW}${log_size}${NC}"
fi
# Последние ошибки
print_section "Последние ошибки (если есть)"
local errors
errors=$(run_compose logs --tail=100 bot 2>/dev/null | grep -i "error\|exception\|critical" | tail -n 5 || echo "")
if [[ -n "$errors" ]]; then
echo "$errors" | while read -r line; do
print_error "$line"
done
else
print_success "Ошибок не обнаружено"
fi
echo ""
if $all_running; then
print_success "Все сервисы работают нормально!"
else
print_warning "Некоторые сервисы не запущены"
fi
secret_key=$(prompt_value "REMNAWAVE_SECRET_KEY" "Введите REMNAWAVE_SECRET_KEY (для установок eGames, формат XXXXXXX:DDDDDDDD, можно оставить пустым)" "$(get_env_value REMNAWAVE_SECRET_KEY "$ENV_FILE")")
web_api_token=$(prompt_value "WEB_API_DEFAULT_TOKEN" "Введите WEB_API_DEFAULT_TOKEN" "$(get_env_value WEB_API_DEFAULT_TOKEN "$ENV_FILE")")
local entries=()
entries+=("BOT_TOKEN=$bot_token")
entries+=("ADMIN_IDS=$admin_ids")
entries+=("REMNAWAVE_API_URL=$api_url")
entries+=("REMNAWAVE_API_KEY=$api_key")
entries+=("REMNAWAVE_AUTH_TYPE=$auth_type")
entries+=("REMNAWAVE_USERNAME=$username")
entries+=("REMNAWAVE_PASSWORD=$password")
entries+=("REMNAWAVE_SECRET_KEY=$secret_key")
entries+=("WEB_API_DEFAULT_TOKEN=$web_api_token")
write_env_file "$ENV_FILE" "${entries[@]}"
log "Файл окружения сохранен: $ENV_FILE"
save_state
log "Информация об установке сохранена ($STATE_FILE)."
resolve_compose_command
start_services
}
show_existing_installation() {
log "Найдена предыдущая установка бота."
log "Путь установки: $INSTALL_PATH"
log "Файл окружения: $ENV_FILE"
resolve_compose_command
show_services_state
if ask_yes_no "Перезапустить сервисы бота? [y/N]: " "n"; then
run_compose restart
show_services_state
# Обновление из Git
update_from_git() {
print_header "ОБНОВЛЕНИЕ ИЗ GIT РЕПОЗИТОРИЯ"
if [[ ! -d "$INSTALL_PATH/.git" ]]; then
print_error "Git репозиторий не найден в $INSTALL_PATH"
print_info "Инициализируем репозиторий..."
local repo_url
read -rp "Введите URL Git репозитория: " repo_url
if [[ -z "$repo_url" ]]; then
print_error "URL не указан"
return 1
fi
(cd "$INSTALL_PATH" && git init && git remote add origin "$repo_url")
fi
follow_logs
print_section "Проверка обновлений"
(cd "$INSTALL_PATH" && git fetch origin 2>&1)
local current_commit
local remote_commit
current_commit=$(cd "$INSTALL_PATH" && git rev-parse HEAD 2>/dev/null || echo "unknown")
remote_commit=$(cd "$INSTALL_PATH" && git rev-parse origin/main 2>/dev/null || git rev-parse origin/master 2>/dev/null || echo "unknown")
if [[ "$current_commit" == "$remote_commit" ]]; then
print_success "Бот уже имеет последнюю версию"
return 0
fi
print_info "Найдены обновления"
echo -e "${CYAN}Текущий коммит: ${YELLOW}${current_commit:0:8}${NC}"
echo -e "${CYAN}Новый коммит: ${YELLOW}${remote_commit:0:8}${NC}"
# Показываем изменения
print_section "Список изменений"
(cd "$INSTALL_PATH" && git log --oneline HEAD..origin/main 2>/dev/null || git log --oneline HEAD..origin/master 2>/dev/null || true)
echo ""
read -rp "$(echo -e ${YELLOW}Применить обновления? [y/N]: ${NC})" confirm
if [[ "${confirm,,}" != "y" ]]; then
print_warning "Обновление отменено"
return 1
fi
# Создаем резервную копию перед обновлением
print_info "Создаем резервную копию перед обновлением..."
create_backup "pre-update"
print_section "Применение обновлений"
# Останавливаем бота
print_info "Останавливаем сервисы..."
run_compose down
# Обновляем код
print_info "Обновляем код..."
(cd "$INSTALL_PATH" && git pull origin main 2>/dev/null || git pull origin master 2>/dev/null)
# Перезапускаем
print_info "Пересобираем и запускаем сервисы..."
run_compose up -d --build
print_success "Обновление завершено!"
# Показываем логи
echo ""
read -rp "$(echo -e ${YELLOW}Показать логи запуска? [y/N]: ${NC})" show_logs
if [[ "${show_logs,,}" == "y" ]]; then
run_compose logs --tail=50 -f bot
fi
}
# Создание резервной копии
create_backup() {
local backup_type=${1:-manual}
local timestamp
timestamp=$(date +%Y%m%d_%H%M%S)
local backup_name="backup_${backup_type}_${timestamp}"
local backup_path="$BACKUP_DIR/$backup_name"
print_header "СОЗДАНИЕ РЕЗЕРВНОЙ КОПИИ"
mkdir -p "$BACKUP_DIR"
mkdir -p "$backup_path"
print_section "Архивирование данных"
# Копируем конфигурацию
print_info "Сохраняем конфигурацию..."
cp "$INSTALL_PATH/.env" "$backup_path/" 2>/dev/null || true
cp "$INSTALL_PATH/docker-compose.yml" "$backup_path/" 2>/dev/null || true
# Экспортируем базу данных
if [[ $(get_service_status "postgres") == "running" ]]; then
print_info "Экспортируем базу данных PostgreSQL..."
run_compose exec -T postgres pg_dump -U postgres remnawave_bot > "$backup_path/database.sql" 2>/dev/null || {
print_warning "Не удалось экспортировать БД"
}
fi
# Копируем данные
if [[ -d "$INSTALL_PATH/data" ]]; then
print_info "Копируем пользовательские данные..."
cp -r "$INSTALL_PATH/data" "$backup_path/" 2>/dev/null || true
fi
# Создаем архив
print_info "Создаем архив..."
(cd "$BACKUP_DIR" && tar -czf "${backup_name}.tar.gz" "$backup_name" && rm -rf "$backup_name")
local backup_size
backup_size=$(du -h "$BACKUP_DIR/${backup_name}.tar.gz" | cut -f1)
print_success "Резервная копия создана: $BACKUP_DIR/${backup_name}.tar.gz"
echo -e "${CYAN}Размер: ${YELLOW}${backup_size}${NC}"
# Очистка старых бэкапов (оставляем последние 10)
print_info "Очистка старых бэкапов..."
(cd "$BACKUP_DIR" && ls -t backup_*.tar.gz 2>/dev/null | tail -n +11 | xargs -r rm -f)
local backup_count
backup_count=$(ls -1 "$BACKUP_DIR"/backup_*.tar.gz 2>/dev/null | wc -l)
print_info "Всего резервных копий: $backup_count"
}
# Восстановление из резервной копии
restore_backup() {
print_header "ВОССТАНОВЛЕНИЕ ИЗ РЕЗЕРВНОЙ КОПИИ"
if [[ ! -d "$BACKUP_DIR" ]] || [[ -z "$(ls -A "$BACKUP_DIR"/*.tar.gz 2>/dev/null)" ]]; then
print_error "Резервные копии не найдены"
return 1
fi
print_section "Доступные резервные копии"
local backups=()
local i=1
while IFS= read -r backup; do
local backup_name
local backup_size
local backup_date
backup_name=$(basename "$backup")
backup_size=$(du -h "$backup" | cut -f1)
backup_date=$(stat -c %y "$backup" 2>/dev/null | cut -d' ' -f1,2 | cut -d'.' -f1 || stat -f "%Sm" "$backup")
echo -e "${CYAN}[$i]${NC} ${WHITE}$backup_name${NC}"
echo -e " Размер: ${YELLOW}$backup_size${NC}, Дата: ${PURPLE}$backup_date${NC}"
backups+=("$backup")
((i++))
done < <(ls -t "$BACKUP_DIR"/*.tar.gz 2>/dev/null)
echo ""
read -rp "Выберите номер резервной копии для восстановления [1-$((i-1))]: " selection
if [[ ! "$selection" =~ ^[0-9]+$ ]] || [[ "$selection" -lt 1 ]] || [[ "$selection" -ge "$i" ]]; then
print_error "Неверный выбор"
return 1
fi
local selected_backup="${backups[$((selection-1))]}"
print_warning "ВНИМАНИЕ: Текущие данные будут перезаписаны!"
read -rp "$(echo -e ${RED}${BOLD}Продолжить восстановление? [y/N]: ${NC})" confirm
if [[ "${confirm,,}" != "y" ]]; then
print_warning "Восстановление отменено"
return 1
fi
# Создаем резервную копию перед восстановлением
print_info "Создаем резервную копию текущего состояния..."
create_backup "pre-restore"
print_section "Восстановление данных"
# Останавливаем сервисы
print_info "Останавливаем сервисы..."
run_compose down
# Распаковываем бэкап
print_info "Распаковываем резервную копию..."
local temp_dir
temp_dir=$(mktemp -d)
tar -xzf "$selected_backup" -C "$temp_dir"
local backup_folder
backup_folder=$(ls "$temp_dir")
# Восстанавливаем конфигурацию
if [[ -f "$temp_dir/$backup_folder/.env" ]]; then
print_info "Восстанавливаем конфигурацию..."
cp "$temp_dir/$backup_folder/.env" "$INSTALL_PATH/"
fi
# Восстанавливаем данные
if [[ -d "$temp_dir/$backup_folder/data" ]]; then
print_info "Восстанавливаем пользовательские данные..."
rm -rf "$INSTALL_PATH/data"
cp -r "$temp_dir/$backup_folder/data" "$INSTALL_PATH/"
fi
# Запускаем сервисы
print_info "Запускаем сервисы..."
run_compose up -d
# Восстанавливаем БД
if [[ -f "$temp_dir/$backup_folder/database.sql" ]]; then
print_info "Ожидаем запуска PostgreSQL..."
sleep 5
print_info "Восстанавливаем базу данных..."
run_compose exec -T postgres psql -U postgres remnawave_bot < "$temp_dir/$backup_folder/database.sql" 2>/dev/null || {
print_warning "Не удалось восстановить БД (возможно, структура уже актуальна)"
}
fi
# Очистка
rm -rf "$temp_dir"
print_success "Восстановление завершено!"
echo ""
show_monitoring
}
# Просмотр логов
view_logs() {
print_header "ПРОСМОТР ЛОГОВ"
echo -e "${CYAN}[1]${NC} Логи бота (последние 100 строк)"
echo -e "${CYAN}[2]${NC} Логи PostgreSQL (последние 100 строк)"
echo -e "${CYAN}[3]${NC} Логи Redis (последние 100 строк)"
echo -e "${CYAN}[4]${NC} Все логи (последние 100 строк)"
echo -e "${CYAN}[5]${NC} Следить за логами в реальном времени"
echo -e "${CYAN}[6]${NC} Поиск по логам"
echo ""
read -rp "Выберите опцию [1-6]: " choice
case $choice in
1)
run_compose logs --tail=100 bot
;;
2)
run_compose logs --tail=100 postgres
;;
3)
run_compose logs --tail=100 redis
;;
4)
run_compose logs --tail=100
;;
5)
print_info "Нажмите Ctrl+C для выхода"
run_compose logs -f
;;
6)
read -rp "Введите текст для поиска: " search_term
run_compose logs | grep -i "$search_term" --color=always | tail -n 50
;;
*)
print_error "Неверный выбор"
;;
esac
}
# Управление сервисами
manage_services() {
print_header "УПРАВЛЕНИЕ СЕРВИСАМИ"
echo -e "${CYAN}[1]${NC} Запустить все сервисы"
echo -e "${CYAN}[2]${NC} Остановить все сервисы"
echo -e "${CYAN}[3]${NC} Перезапустить все сервисы"
echo -e "${CYAN}[4]${NC} Пересобрать и запустить"
echo -e "${CYAN}[5]${NC} Остановить и удалить контейнеры"
echo ""
read -rp "Выберите опцию [1-5]: " choice
case $choice in
1)
print_info "Запускаем сервисы..."
run_compose up -d
print_success "Сервисы запущены"
show_monitoring
;;
2)
print_info "Останавливаем сервисы..."
run_compose stop
print_success "Сервисы остановлены"
;;
3)
print_info "Перезапускаем сервисы..."
run_compose restart
print_success "Сервисы перезапущены"
show_monitoring
;;
4)
print_info "Пересобираем и запускаем..."
run_compose up -d --build
print_success "Сервисы пересобраны и запущены"
show_monitoring
;;
5)
print_warning "Контейнеры будут удалены (данные сохранятся в volumes)"
read -rp "$(echo -e ${YELLOW}Продолжить? [y/N]: ${NC})" confirm
if [[ "${confirm,,}" == "y" ]]; then
run_compose down
print_success "Контейнеры остановлены и удалены"
fi
;;
*)
print_error "Неверный выбор"
;;
esac
}
# Очистка системы
cleanup_system() {
print_header "ОЧИСТКА СИСТЕМЫ"
echo -e "${CYAN}[1]${NC} Очистить старые логи (старше 7 дней)"
echo -e "${CYAN}[2]${NC} Очистить старые резервные копии (оставить 5 последних)"
echo -e "${CYAN}[3]${NC} Очистить неиспользуемые Docker образы"
echo -e "${CYAN}[4]${NC} Полная очистка (всё вышеперечисленное)"
echo ""
read -rp "Выберите опцию [1-4]: " choice
case $choice in
1)
print_info "Очищаем старые логи..."
find "$INSTALL_PATH/logs" -type f -mtime +7 -delete 2>/dev/null || true
print_success "Старые логи удалены"
;;
2)
print_info "Очищаем старые бэкапы..."
(cd "$BACKUP_DIR" && ls -t backup_*.tar.gz 2>/dev/null | tail -n +6 | xargs -r rm -f)
print_success "Старые бэкапы удалены"
;;
3)
print_info "Очищаем неиспользуемые Docker образы..."
docker image prune -f
print_success "Неиспользуемые образы удалены"
;;
4)
print_info "Выполняем полную очистку..."
find "$INSTALL_PATH/logs" -type f -mtime +7 -delete 2>/dev/null || true
(cd "$BACKUP_DIR" && ls -t backup_*.tar.gz 2>/dev/null | tail -n +6 | xargs -r rm -f)
docker image prune -f
docker volume prune -f
print_success "Полная очистка завершена"
;;
*)
print_error "Неверный выбор"
;;
esac
}
# Главное меню
show_menu() {
clear
echo -e "${PURPLE}${BOLD}"
cat << "EOF"
╔════════════════════════════════════════════════════════════╗
║ ║
║ ██████╗ ██████╗ ████████╗ ███╗ ███╗ ██████╗ ██████╗
║ ██╔══██╗██╔═══██╗╚══██╔══╝ ████╗ ████║██╔════╝ ██╔══██╗
║ ██████╔╝██║ ██║ ██║ ██╔████╔██║██║ ███╗██████╔╝
║ ██╔══██╗██║ ██║ ██║ ██║╚██╔╝██║██║ ██║██╔══██╗
║ ██████╔╝╚██████╔╝ ██║ ██║ ╚═╝ ██║╚██████╔╝██║ ██║
║ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝
║ ║
║ Система управления Telegram ботом ║
╚════════════════════════════════════════════════════════════╝
EOF
echo -e "${NC}"
echo -e "${WHITE}${BOLD}Путь установки:${NC} ${CYAN}$INSTALL_PATH${NC}"
echo ""
echo -e "${GREEN}${BOLD}[1]${NC} ${STAR} Мониторинг и статус сервисов"
echo -e "${BLUE}${BOLD}[2]${NC} ${GEAR} Управление сервисами"
echo -e "${YELLOW}${BOLD}[3]${NC} 📋 Просмотр логов"
echo -e "${PURPLE}${BOLD}[4]${NC} 🔄 Обновление из Git"
echo -e "${CYAN}${BOLD}[5]${NC} 💾 Создать резервную копию"
echo -e "${YELLOW}${BOLD}[6]${NC} 📦 Восстановить из резервной копии"
echo -e "${RED}${BOLD}[7]${NC} 🧹 Очистка системы"
echo -e "${WHITE}${BOLD}[0]${NC} 🚪 Выход"
echo ""
}
main() {
load_state
if [[ -f "$STATE_FILE" ]]; then
if ask_yes_no "Обнаружена существующая установка. Переустановить? [y/N]: " "n"; then
perform_installation
else
show_existing_installation
fi
else
perform_installation
fi
resolve_compose_command
while true; do
show_menu
read -rp "$(echo -e ${WHITE}${BOLD}Выберите опцию: ${NC})" choice
case $choice in
1)
show_monitoring
;;
2)
manage_services
;;
3)
view_logs
;;
4)
update_from_git
;;
5)
create_backup "manual"
;;
6)
restore_backup
;;
7)
cleanup_system
;;
0)
print_success "До свидания!"
exit 0
;;
*)
print_error "Неверный выбор. Попробуйте снова."
;;
esac
echo ""
read -rp "$(echo -e ${CYAN}Нажмите Enter для продолжения...${NC})"
done
}
main "$@"