iris_hub/core/config.rs
1//! # Gerenciamento de Configurações
2//!
3//! Este módulo é responsável por carregar, salvar e gerenciar
4//! as configurações da aplicação Iris.
5//!
6//! ## Localização do Arquivo de Configuração
7//! As configurações são salvas em: `%APPDATA%\iris\config.json`
8
9use std::fs;
10use std::path::PathBuf;
11use super::models::AppState;
12
13/// Gerenciador de configurações da aplicação.
14///
15/// Responsável por:
16/// - Determinar o caminho do arquivo de configuração
17/// - Carregar configurações do disco
18/// - Salvar configurações em disco
19/// - Importar/Exportar configurações
20pub struct ConfigManager {
21 /// Caminho do arquivo de configuração
22 config_path: PathBuf,
23}
24
25impl ConfigManager {
26 /// Cria uma nova instância do gerenciador de configurações.
27 ///
28 /// Automaticamente determina o caminho correto baseado no sistema operacional.
29 pub fn new() -> Self {
30 let config_path = Self::get_config_path();
31 Self { config_path }
32 }
33
34 /// Retorna o caminho do arquivo de configuração.
35 ///
36 /// No Windows: `%APPDATA%\iris\config.json`
37 /// No Linux/macOS: `~/.config/iris/config.json`
38 pub fn get_config_path() -> PathBuf {
39 let mut path = dirs::config_dir().unwrap_or_else(|| PathBuf::from("."));
40 path.push("iris");
41 fs::create_dir_all(&path).ok();
42 path.push("config.json");
43 path
44 }
45
46 /// Retorna uma referência ao caminho do arquivo de configuração
47 pub fn path(&self) -> &PathBuf {
48 &self.config_path
49 }
50
51 /// Carrega o estado da aplicação do disco.
52 ///
53 /// Se o arquivo não existir ou for inválido, retorna um estado vazio.
54 ///
55 /// # Exemplo
56 /// ```rust
57 /// let manager = ConfigManager::new();
58 /// let state = manager.load();
59 /// println!("Aplicações carregadas: {}", state.apps.len());
60 /// ```
61 pub fn load(&self) -> AppState {
62 if self.config_path.exists() {
63 if let Ok(content) = fs::read_to_string(&self.config_path) {
64 if let Ok(state) = serde_json::from_str(&content) {
65 return state;
66 }
67 }
68 }
69 AppState::default()
70 }
71
72 /// Salva o estado da aplicação em disco.
73 ///
74 /// # Argumentos
75 /// * `state` - Estado a ser salvo
76 ///
77 /// # Retorno
78 /// Retorna `Ok(())` em caso de sucesso ou `Err` com a mensagem de erro.
79 pub fn save(&self, state: &AppState) -> Result<(), String> {
80 match serde_json::to_string_pretty(state) {
81 Ok(json) => {
82 fs::write(&self.config_path, json)
83 .map_err(|e| format!("Erro ao salvar configurações: {}", e))
84 }
85 Err(e) => Err(format!("Erro ao serializar configurações: {}", e)),
86 }
87 }
88
89 /// Exporta as configurações para um arquivo específico.
90 ///
91 /// # Argumentos
92 /// * `state` - Estado a ser exportado
93 /// * `path` - Caminho do arquivo de destino
94 pub fn export(&self, state: &AppState, path: &PathBuf) -> Result<(), String> {
95 match serde_json::to_string_pretty(state) {
96 Ok(json) => {
97 fs::write(path, json)
98 .map_err(|e| format!("Erro ao exportar configurações: {}", e))
99 }
100 Err(e) => Err(format!("Erro ao serializar configurações: {}", e)),
101 }
102 }
103
104 /// Importa configurações de um arquivo.
105 ///
106 /// As aplicações importadas recebem novos IDs para evitar conflitos.
107 ///
108 /// # Argumentos
109 /// * `path` - Caminho do arquivo a ser importado
110 ///
111 /// # Retorno
112 /// Retorna o estado importado ou uma mensagem de erro.
113 pub fn import(&self, path: &PathBuf) -> Result<AppState, String> {
114 let content = fs::read_to_string(path)
115 .map_err(|e| format!("Erro ao ler arquivo: {}", e))?;
116
117 let mut state: AppState = serde_json::from_str(&content)
118 .map_err(|e| format!("Erro ao processar JSON: {}", e))?;
119
120 // Gera novos IDs para evitar conflitos
121 for app in &mut state.apps {
122 app.id = crate::utils::uuid_simple();
123 }
124
125 Ok(state)
126 }
127}
128
129impl Default for ConfigManager {
130 fn default() -> Self {
131 Self::new()
132 }
133}
134
135#[cfg(test)]
136mod tests {
137 use super::*;
138
139 #[test]
140 fn test_config_path_exists() {
141 let path = ConfigManager::get_config_path();
142 assert!(path.to_string_lossy().contains("iris"));
143 }
144
145 #[test]
146 fn test_default_state_is_empty() {
147 let state = AppState::default();
148 assert!(state.apps.is_empty());
149 }
150}