use std::path::PathBuf;
use crate::app::CliApp;
use crate::cli::AutoBackupCommand;
use crate::commands::{backup, docker_service};
use crate::docker_service::health_check::HealthChecker;
use crate::docker_utils;
use anyhow::Result;
use client_core::constants::timeout;
use rust_i18n::t;
use tracing::{debug, error, info, warn};
pub async fn handle_auto_backup(app: &mut CliApp, command: &AutoBackupCommand) -> Result<()> {
match command {
AutoBackupCommand::Run => {
info!("Executing auto backup");
run_auto_backup(app).await
}
AutoBackupCommand::Status => show_status(app).await,
}
}
pub async fn run_auto_backup(app: &mut CliApp) -> Result<()> {
info!("Starting auto backup process");
let backup_start_time = chrono::Utc::now();
let mut backup_success = false;
let compose_file = Some(PathBuf::from(&app.config.docker.compose_file));
let project_name: Option<String> = None;
let service_running = {
let health_checker = HealthChecker::new(app.docker_manager.clone());
let report = health_checker.health_check().await?;
report.get_running_count() > 0
};
if service_running {
docker_service::stop_docker_services_and_wait(
app,
compose_file.clone(),
project_name.clone(),
)
.await?;
} else {
info!("Docker services not running, proceeding with backup directly");
}
info!("Starting backup operation");
let mut backup_error_message: String = String::new();
match backup::run_backup(app).await {
Ok(_) => {
backup_success = true;
info!("Backup completed successfully");
}
Err(e) => {
error!(error = %e, "Backup operation failed");
backup_error_message = format!("{e}");
}
}
if let Err(e) = update_last_backup_time(app, backup_start_time, backup_success).await {
warn!(error = %e, "Failed to record backup time");
}
if service_running {
info!("Restarting Docker services");
docker_service::start_docker_services(app, compose_file.clone(), project_name.clone())
.await?;
info!("Waiting for Docker services to fully start");
let compose_path = compose_file.as_ref().unwrap().as_path();
if docker_utils::wait_for_compose_services_started(
compose_path,
timeout::SERVICE_START_TIMEOUT,
)
.await?
{
if backup_success {
info!("Auto backup process complete, services restarted");
} else {
warn!("Auto backup process complete (backup failed), services restarted");
}
} else {
warn!("Service startup timeout, please check service status manually");
match check_docker_service_status(app).await {
Ok(true) => {
debug!("Final check: Services started normally");
}
Ok(false) => {
debug!("Final check: Services not started");
}
Err(e) => {
error!(error = %e, "Final check failed");
}
}
}
} else if backup_success {
info!("Auto backup process complete");
} else {
warn!("Auto backup process complete (backup failed)");
}
if !backup_success {
return Err(anyhow::anyhow!(
"{}",
t!("auto_backup.execution_failed", error = backup_error_message)
));
}
Ok(())
}
pub async fn show_status(app: &mut CliApp) -> Result<()> {
debug!("Displaying backup status and history");
info!("📦 Backup Management");
info!("============");
backup::run_list_backups(app).await?;
info!("");
info!("🔧 Quick Actions:");
info!(" - Run backup now: nuwax-cli auto-backup run");
Ok(())
}
pub async fn update_last_backup_time(
app: &CliApp,
backup_time: chrono::DateTime<chrono::Utc>,
success: bool,
) -> Result<()> {
app.database
.set_config("auto_backup_last_time", &backup_time.to_rfc3339())
.await?;
let status = if success { "success" } else { "failed" };
app.database
.set_config("auto_backup_last_status", status)
.await?;
Ok(())
}
async fn check_docker_service_status(app: &mut CliApp) -> Result<bool> {
let health_checker = HealthChecker::new(app.docker_manager.clone());
let report = health_checker.health_check().await?;
let running_count = report.get_running_count();
if running_count > 0 {
info!("🔍 Found {count} running services", count = running_count);
Ok(true)
} else {
info!("🔍 No running services found");
Ok(false)
}
}