caretta_sync_cli/cli/args/
config.rs1use std::path::PathBuf;
2
3use caretta_sync_core::{
4 config::{Config, PartialConfig, PartialIrohConfig},
5 utils::{emptiable::Emptiable, mergeable::Mergeable},
6};
7use clap::Args;
8
9use tokio::sync::OnceCell;
10
11#[derive(Args, Clone, Debug)]
12pub struct ConfigArgs {
13 #[arg(short = 'c', long = "config")]
14 pub file_path: Option<PathBuf>,
15 #[arg(skip)]
16 pub file_content: OnceCell<PartialConfig>,
17 #[command(flatten)]
18 pub args: PartialConfig,
19}
20
21impl ConfigArgs {
22 fn get_file_path_or_default(&self, app_name: &'static str) -> PathBuf {
23 self.file_path.clone().unwrap_or(
24 dirs::config_local_dir()
25 .expect("Config user directory should be set")
26 .join(app_name)
27 .join("config.toml"),
28 )
29 }
30 async fn get_or_read_file_content(&self, app_name: &'static str) -> PartialConfig {
31 self.file_content
32 .get_or_init(|| async {
33 PartialConfig::read_from(self.get_file_path_or_default(app_name))
34 .expect("Config file should be invalid!")
35 })
36 .await
37 .clone()
38 }
39 pub async fn to_partial_config_with_default(&self, app_name: &'static str) -> PartialConfig {
40 let mut default = PartialConfig::default(app_name);
41 default.merge(self.to_partial_config_without_default(app_name).await);
42 default
43 }
44 pub async fn to_partial_config_without_default(&self, app_name: &'static str) -> PartialConfig {
45 let mut file_content = self.get_or_read_file_content(app_name).await;
46 let args = self.args.clone();
47 file_content.merge(args);
48 file_content
49 }
50 async fn has_p2p_private_key(&self, app_name: &'static str) -> bool {
51 let merged = self.to_partial_config_with_default(app_name).await;
52 match merged.iroh {
53 Some(p2p) => p2p.secret_key.is_some(),
54 None => false,
55 }
56 }
57 pub async fn into_config(mut self, app_name: &'static str) -> Config {
58 if !self.has_p2p_private_key(app_name).await {
59 let path = self.get_file_path_or_default(app_name);
60 let content = self.file_content.get_mut().unwrap();
61 if let Some(p2p) = content.iroh.as_mut() {
62 p2p.renew_secret_key();
63 } else {
64 content
65 .iroh
66 .insert(PartialIrohConfig::empty().with_new_secret_key());
67 }
68 content
69 .write_to(path)
70 .expect("Config file should be writable first time to initialize secret");
71 }
72 self.to_partial_config_with_default(app_name)
73 .await
74 .try_into()
75 .expect("Some configurations are missing!")
76 }
77}