use anyhow::Result;
use client_core::{
api::ApiClient, authenticated_client::AuthenticatedClient, backup::BackupManager,
config::AppConfig, constants::config, container::DockerManager, database::Database,
upgrade::UpgradeManager,
};
use rust_i18n::t;
use std::path::{Path, PathBuf};
use std::sync::Arc;
use crate::cli::Commands;
use crate::commands;
use tracing::debug;
#[derive(Clone)]
pub struct CliApp {
pub config_path: PathBuf,
pub config: Arc<AppConfig>,
pub database: Arc<Database>,
pub api_client: Arc<ApiClient>,
pub authenticated_client: Arc<AuthenticatedClient>,
pub docker_manager: Arc<DockerManager>,
pub backup_manager: Arc<BackupManager>,
pub upgrade_manager: Arc<UpgradeManager>,
}
impl CliApp {
pub async fn new_with_auto_config() -> Result<Self> {
let config = Arc::new(AppConfig::find_and_load_config()?);
Self::new_with_config(config, PathBuf::from("config.toml")).await
}
pub async fn new_with_config_path<P: AsRef<Path>>(config_path: P) -> Result<Self> {
let config_path = config_path.as_ref();
let config = if config_path.exists() {
Arc::new(AppConfig::load_from_file(config_path)?)
} else {
Arc::new(AppConfig::find_and_load_config()?)
};
Self::new_with_config(config, config_path.to_path_buf()).await
}
async fn new_with_config(config: Arc<AppConfig>, config_path: PathBuf) -> Result<Self> {
config.ensure_cache_dirs()?;
let db_path = config::get_database_path();
let database = Arc::new(Database::connect(&db_path).await?);
debug!("Database connected: {}", db_path.display());
if !database.is_database_initialized().await? {
return Err(anyhow::anyhow!(
t!("app.database_not_initialized").to_string(),
));
}
let server_base_url = client_core::constants::api::get_base_url();
let authenticated_client =
Arc::new(AuthenticatedClient::new(database.clone(), server_base_url).await?);
let client_id = database.get_api_client_id().await?;
let api_client = Arc::new(ApiClient::new(
client_id.clone(),
Some(authenticated_client.clone()),
));
let docker_manager = Arc::new(DockerManager::with_project(
PathBuf::from(&config.docker.compose_file),
PathBuf::from(&config.docker.env_file),
None,
)?);
let backup_manager = Arc::new(BackupManager::new(
PathBuf::from(&config.backup.storage_dir),
database.clone(),
docker_manager.clone(),
)?);
let upgrade_manager = Arc::new(UpgradeManager::new(
config.clone(),
config_path.clone(),
api_client.clone(),
database.clone(),
));
Ok(Self {
config_path,
config,
database,
api_client,
authenticated_client,
docker_manager,
backup_manager,
upgrade_manager,
})
}
pub async fn run_command(&mut self, command: Commands) -> Result<()> {
match command {
Commands::Status => commands::run_status(self).await,
Commands::ApiInfo => commands::run_api_info(self).await,
Commands::Init { .. } => unreachable!(), Commands::CheckUpdate(check_update_cmd) => {
commands::handle_check_update_command(check_update_cmd)
.await
.map_err(|e| {
anyhow::anyhow!(
t!("app.check_update_failed", error = e.to_string()).to_string()
)
})
}
Commands::Upgrade { subcommand, args } => {
match subcommand {
Some(crate::cli::UpgradeSubcommand::Download { full: _ }) => {
commands::run_download_with_config(&self.config)
.await
.map_err(|e| {
client_core::DuckError::custom(
t!("app.upgrade_failed", error = e.to_string()).to_string(),
)
})?;
}
Some(crate::cli::UpgradeSubcommand::Check { force }) => {
let args = crate::cli::UpgradeArgs { force, check: true };
commands::run_upgrade(self, args).await.map_err(|e| {
client_core::DuckError::custom(
t!("app.upgrade_failed", error = e.to_string()).to_string(),
)
})?;
}
None => {
commands::run_upgrade(self, args).await.map_err(|e| {
client_core::DuckError::custom(
t!("app.upgrade_failed", error = e.to_string()).to_string(),
)
})?;
}
}
Ok(())
}
Commands::ListBackups => commands::run_list_backups(self).await,
Commands::Rollback {
backup_id,
force,
list_json,
rollback_data,
} => {
commands::backup::run_rollback(
self,
backup_id,
force,
list_json,
true,
rollback_data,
)
.await
}
Commands::DockerService(docker_cmd) => {
commands::run_docker_service_command(self, docker_cmd).await
}
Commands::Ducker { args } => commands::run_ducker(args).await,
Commands::AutoBackup(auto_backup_cmd) => {
commands::handle_auto_backup(self, &auto_backup_cmd).await
}
Commands::AutoUpgradeDeploy(auto_upgrade_deploy_cmd) => {
commands::handle_auto_upgrade_deploy_command(self, auto_upgrade_deploy_cmd).await
}
Commands::Cache(cache_cmd) => commands::handle_cache_command(self, cache_cmd).await,
Commands::DiffSql {
old_sql,
new_sql,
old_version,
new_version,
output,
} => commands::run_diff_sql(old_sql, new_sql, old_version, new_version, output).await,
}
}
}