Skip to main content

nuwax_cli/
app.rs

1use anyhow::Result;
2use client_core::{
3    api::ApiClient, authenticated_client::AuthenticatedClient, backup::BackupManager,
4    config::AppConfig, constants::config, container::DockerManager, database::Database,
5    upgrade::UpgradeManager,
6};
7use rust_i18n::t;
8use std::path::{Path, PathBuf};
9use std::sync::Arc;
10
11use crate::cli::Commands;
12use crate::commands;
13use tracing::debug;
14
15#[derive(Clone)]
16pub struct CliApp {
17    pub config_path: PathBuf,
18    pub config: Arc<AppConfig>,
19    pub database: Arc<Database>,
20    pub api_client: Arc<ApiClient>,
21    pub authenticated_client: Arc<AuthenticatedClient>,
22    pub docker_manager: Arc<DockerManager>,
23    pub backup_manager: Arc<BackupManager>,
24    pub upgrade_manager: Arc<UpgradeManager>,
25}
26
27impl CliApp {
28    /// 使用智能配置查找初始化CLI应用
29    pub async fn new_with_auto_config() -> Result<Self> {
30        let config = Arc::new(AppConfig::find_and_load_config()?);
31
32        Self::new_with_config(config, PathBuf::from("config.toml")).await
33    }
34
35    /// 使用指定配置文件路径初始化CLI应用
36    pub async fn new_with_config_path<P: AsRef<Path>>(config_path: P) -> Result<Self> {
37        let config_path = config_path.as_ref();
38        let config = if config_path.exists() {
39            Arc::new(AppConfig::load_from_file(config_path)?)
40        } else {
41            // 如果指定的配置文件不存在,尝试智能查找
42            Arc::new(AppConfig::find_and_load_config()?)
43        };
44
45        Self::new_with_config(config, config_path.to_path_buf()).await
46    }
47
48    /// 使用配置初始化CLI应用
49    async fn new_with_config(config: Arc<AppConfig>, config_path: PathBuf) -> Result<Self> {
50        // 确保缓存目录存在
51        config.ensure_cache_dirs()?;
52
53        // 初始化数据库
54        let db_path = config::get_database_path();
55        let database = Arc::new(Database::connect(&db_path).await?);
56        debug!("Database connected: {}", db_path.display());
57
58        // 检查数据库是否已经初始化
59        if !database.is_database_initialized().await? {
60            return Err(anyhow::anyhow!(
61                t!("app.database_not_initialized").to_string(),
62            ));
63        }
64
65        // 创建认证客户端(自动处理注册和认证)
66        let server_base_url = client_core::constants::api::get_base_url();
67        let authenticated_client =
68            Arc::new(AuthenticatedClient::new(database.clone(), server_base_url).await?);
69
70        // 获取用于API请求的客户端ID(只使用服务端返回的client_id)
71        let client_id = database.get_api_client_id().await?;
72        let api_client = Arc::new(ApiClient::new(
73            client_id.clone(),
74            Some(authenticated_client.clone()),
75        ));
76
77        // 创建其他管理器
78        let docker_manager = Arc::new(DockerManager::with_project(
79            PathBuf::from(&config.docker.compose_file),
80            PathBuf::from(&config.docker.env_file),
81            None,
82        )?);
83
84        let backup_manager = Arc::new(BackupManager::new(
85            PathBuf::from(&config.backup.storage_dir),
86            database.clone(),
87            docker_manager.clone(),
88        )?);
89        let upgrade_manager = Arc::new(UpgradeManager::new(
90            config.clone(),
91            config_path.clone(),
92            api_client.clone(),
93            database.clone(),
94        ));
95
96        Ok(Self {
97            config_path,
98            config,
99            database,
100            api_client,
101            authenticated_client,
102            docker_manager,
103            backup_manager,
104            upgrade_manager,
105        })
106    }
107
108    /// 运行应用命令
109    pub async fn run_command(&mut self, command: Commands) -> Result<()> {
110        match command {
111            Commands::Status => commands::run_status(self).await,
112            Commands::ApiInfo => commands::run_api_info(self).await,
113            Commands::Init { .. } => unreachable!(), // 已经在 main.rs 中处理
114            Commands::CheckUpdate(check_update_cmd) => {
115                commands::handle_check_update_command(check_update_cmd)
116                    .await
117                    .map_err(|e| {
118                        anyhow::anyhow!(
119                            t!("app.check_update_failed", error = e.to_string()).to_string()
120                        )
121                    })
122            }
123            Commands::Upgrade { subcommand, args } => {
124                match subcommand {
125                    Some(crate::cli::UpgradeSubcommand::Download { full: _ }) => {
126                        commands::run_download_with_config(&self.config)
127                            .await
128                            .map_err(|e| {
129                                client_core::DuckError::custom(
130                                    t!("app.upgrade_failed", error = e.to_string()).to_string(),
131                                )
132                            })?;
133                    }
134                    Some(crate::cli::UpgradeSubcommand::Check { force }) => {
135                        let args = crate::cli::UpgradeArgs { force, check: true };
136                        commands::run_upgrade(self, args).await.map_err(|e| {
137                            client_core::DuckError::custom(
138                                t!("app.upgrade_failed", error = e.to_string()).to_string(),
139                            )
140                        })?;
141                    }
142                    None => {
143                        commands::run_upgrade(self, args).await.map_err(|e| {
144                            client_core::DuckError::custom(
145                                t!("app.upgrade_failed", error = e.to_string()).to_string(),
146                            )
147                        })?;
148                    }
149                }
150                Ok(())
151            }
152            Commands::ListBackups => commands::run_list_backups(self).await,
153            Commands::Rollback {
154                backup_id,
155                force,
156                list_json,
157                rollback_data,
158            } => {
159                commands::backup::run_rollback(
160                    self,
161                    backup_id,
162                    force,
163                    list_json,
164                    true,
165                    rollback_data,
166                )
167                .await
168            }
169            Commands::DockerService(docker_cmd) => {
170                commands::run_docker_service_command(self, docker_cmd).await
171            }
172            Commands::Ducker { args } => commands::run_ducker(args).await,
173            Commands::AutoBackup(auto_backup_cmd) => {
174                commands::handle_auto_backup(self, &auto_backup_cmd).await
175            }
176            Commands::AutoUpgradeDeploy(auto_upgrade_deploy_cmd) => {
177                commands::handle_auto_upgrade_deploy_command(self, auto_upgrade_deploy_cmd).await
178            }
179            Commands::Cache(cache_cmd) => commands::handle_cache_command(self, cache_cmd).await,
180            Commands::DiffSql {
181                old_sql,
182                new_sql,
183                old_version,
184                new_version,
185                output,
186            } => commands::run_diff_sql(old_sql, new_sql, old_version, new_version, output).await,
187        }
188    }
189}