1use serde::{Deserialize, Serialize};
2use std::fs;
3use std::path::PathBuf;
4
5#[derive(Debug, Serialize, Deserialize, Clone)]
7pub struct CairnConfig {
8 #[serde(default = "default_chain")]
9 pub chain: String,
10 #[serde(default = "default_network")]
11 pub network: String,
12 #[serde(default = "default_tier")]
13 pub tier: String,
14 pub default_confirmations: Option<u32>,
15 pub default_rebroadcast_max: Option<u32>,
16 pub default_valid_for: Option<u64>,
17 pub key_file: Option<String>,
18 pub credentials_path: Option<String>,
19 #[serde(default = "default_output")]
20 pub output: String,
21 pub api_url: Option<String>,
22}
23
24fn default_chain() -> String { "ethereum".to_string() }
25fn default_network() -> String { "mainnet".to_string() }
26fn default_tier() -> String { "standard".to_string() }
27fn default_output() -> String { "json".to_string() }
28
29impl Default for CairnConfig {
30 fn default() -> Self {
31 Self {
32 chain: default_chain(),
33 network: default_network(),
34 tier: default_tier(),
35 default_confirmations: Some(24),
36 default_rebroadcast_max: Some(3),
37 default_valid_for: Some(600),
38 key_file: None,
39 credentials_path: None,
40 output: default_output(),
41 api_url: None,
42 }
43 }
44}
45
46#[derive(Debug, Serialize, Deserialize, Clone)]
48pub struct Credentials {
49 pub jwt: String,
50 pub agent_id: Option<String>,
51 pub wallet: Option<String>,
52 pub expires_at: Option<String>,
53}
54
55impl CairnConfig {
56 pub fn config_dir() -> PathBuf {
57 dirs::home_dir()
58 .unwrap_or_else(|| PathBuf::from("."))
59 .join(".backpac")
60 }
61
62 pub fn config_path() -> PathBuf {
63 Self::config_dir().join("config.json")
64 }
65
66 pub fn credentials_path() -> PathBuf {
67 Self::config_dir().join("credentials.json")
68 }
69
70 pub fn load() -> Self {
71 let path = Self::config_path();
72 if path.exists() {
73 let data = fs::read_to_string(&path).unwrap_or_default();
74 serde_json::from_str(&data).unwrap_or_default()
75 } else {
76 Self::default()
77 }
78 }
79
80 pub fn save(&self) -> Result<(), std::io::Error> {
81 let dir = Self::config_dir();
82 fs::create_dir_all(&dir)?;
83 let data = serde_json::to_string_pretty(self)?;
84 fs::write(Self::config_path(), data)
85 }
86}
87
88impl Credentials {
89 pub fn load() -> Option<Self> {
90 let path = CairnConfig::credentials_path();
91 if path.exists() {
92 let data = fs::read_to_string(&path).ok()?;
93 serde_json::from_str(&data).ok()
94 } else {
95 None
96 }
97 }
98
99 pub fn save(&self) -> Result<(), std::io::Error> {
100 let dir = CairnConfig::config_dir();
101 fs::create_dir_all(&dir)?;
102 let data = serde_json::to_string_pretty(self)?;
103 fs::write(CairnConfig::credentials_path(), data)
104 }
105}