guardian_db/ipfs_core_api/
config.rs

1// Configuração do cliente IPFS
2//
3// Centraliza todas as opções de configuração do cliente IPFS
4
5use libp2p::PeerId;
6use serde::{Deserialize, Serialize};
7use std::path::PathBuf;
8use std::time::Duration;
9
10/// Configuração completa do cliente IPFS
11#[derive(Debug, Clone, Serialize, Deserialize)]
12pub struct ClientConfig {
13    /// Habilita funcionalidades de PubSub
14    pub enable_pubsub: bool,
15
16    /// Habilita funcionalidades de Swarm/networking
17    pub enable_swarm: bool,
18
19    /// Caminho para armazenar dados do IPFS (opcional)
20    pub data_store_path: Option<PathBuf>,
21
22    /// Endereços de rede para escutar conexões
23    pub listening_addrs: Vec<String>,
24
25    /// Peers de bootstrap para conectar inicialmente
26    pub bootstrap_peers: Vec<PeerId>,
27
28    /// Habilita descoberta de peers via mDNS
29    pub enable_mdns: bool,
30
31    /// Habilita protocolo Kademlia DHT
32    pub enable_kad: bool,
33
34    /// Configurações de networking
35    pub network: NetworkConfig,
36
37    /// Configurações de armazenamento
38    pub storage: StorageConfig,
39
40    /// Configurações de PubSub
41    pub pubsub: PubsubConfig,
42}
43
44impl Default for ClientConfig {
45    fn default() -> Self {
46        Self {
47            enable_pubsub: true,
48            enable_swarm: true,
49            data_store_path: Some(PathBuf::from("./ipfs_data")),
50            listening_addrs: vec![
51                "/ip4/0.0.0.0/tcp/0".to_string(),
52                "/ip6/::/tcp/0".to_string(),
53            ],
54            bootstrap_peers: vec![],
55            enable_mdns: true,
56            enable_kad: true,
57            network: NetworkConfig::default(),
58            storage: StorageConfig::default(),
59            pubsub: PubsubConfig::default(),
60        }
61    }
62}
63
64impl ClientConfig {
65    /// Cria configuração mínima para desenvolvimento
66    pub fn development() -> Self {
67        Self {
68            enable_pubsub: true, // Habilitado para testes de desenvolvimento
69            enable_swarm: true,  // Necessário para pubsub funcionar
70            data_store_path: Some("./tmp/ipfs_dev".into()),
71            listening_addrs: vec!["/ip4/127.0.0.1/tcp/0".to_string()],
72            bootstrap_peers: vec![],
73            enable_mdns: false,
74            enable_kad: false,
75            network: NetworkConfig::development(),
76            storage: StorageConfig::development(),
77            pubsub: PubsubConfig::development(),
78        }
79    }
80
81    /// Cria configuração para produção
82    pub fn production() -> Self {
83        Self {
84            enable_pubsub: true,
85            enable_swarm: true,
86            data_store_path: Some("/var/lib/ipfs".into()),
87            listening_addrs: vec![
88                "/ip4/0.0.0.0/tcp/4001".to_string(),
89                "/ip6/::/tcp/4001".to_string(),
90                "/ip4/0.0.0.0/tcp/8081/ws".to_string(),
91            ],
92            bootstrap_peers: vec![], // Seria populado com peers reais
93            enable_mdns: true,
94            enable_kad: true,
95            network: NetworkConfig::production(),
96            storage: StorageConfig::production(),
97            pubsub: PubsubConfig::production(),
98        }
99    }
100
101    /// Configuração apenas para testes
102    pub fn testing() -> Self {
103        Self {
104            enable_pubsub: true,
105            enable_swarm: false,
106            data_store_path: None, // Em memória
107            listening_addrs: vec![],
108            bootstrap_peers: vec![],
109            enable_mdns: false,
110            enable_kad: false,
111            network: NetworkConfig::testing(),
112            storage: StorageConfig::testing(),
113            pubsub: PubsubConfig::testing(),
114        }
115    }
116
117    /// Habilita modo offline (sem networking)
118    pub fn offline() -> Self {
119        Self {
120            enable_pubsub: false,
121            enable_swarm: false,
122            enable_mdns: false,
123            enable_kad: false,
124            ..Self::development()
125        }
126    }
127
128    /// Adiciona um peer de bootstrap
129    pub fn add_bootstrap_peer(&mut self, peer: PeerId) {
130        if !self.bootstrap_peers.contains(&peer) {
131            self.bootstrap_peers.push(peer);
132        }
133    }
134
135    /// Adiciona um endereço de escuta
136    pub fn add_listening_addr(&mut self, addr: String) {
137        if !self.listening_addrs.contains(&addr) {
138            self.listening_addrs.push(addr);
139        }
140    }
141
142    /// Define o caminho de armazenamento
143    pub fn with_data_path<P: Into<PathBuf>>(mut self, path: P) -> Self {
144        self.data_store_path = Some(path.into());
145        self
146    }
147
148    /// Valida a configuração
149    pub fn validate(&self) -> Result<(), String> {
150        // Verifica consistência da configuração
151        if self.enable_pubsub && !self.enable_swarm {
152            return Err("PubSub requer Swarm habilitado".to_string());
153        }
154
155        if self.enable_kad && !self.enable_swarm {
156            return Err("Kademlia DHT requer Swarm habilitado".to_string());
157        }
158
159        if self.enable_swarm && self.listening_addrs.is_empty() {
160            return Err("Swarm requer pelo menos um endereço de escuta".to_string());
161        }
162
163        // Valida endereços
164        for addr in &self.listening_addrs {
165            if addr.is_empty() {
166                return Err("Endereço de escuta não pode estar vazio".to_string());
167            }
168        }
169
170        Ok(())
171    }
172
173    /// Cria configuração para backend híbrido (Iroh + LibP2P)
174    pub fn hybrid() -> Self {
175        Self {
176            enable_pubsub: true,                           // LibP2P PubSub
177            enable_swarm: true,                            // LibP2P Swarm
178            data_store_path: Some("./hybrid_data".into()), // Armazenamento local Iroh
179            listening_addrs: vec![
180                "/ip4/0.0.0.0/tcp/0".to_string(),
181                "/ip6/::/tcp/0".to_string(),
182            ],
183            bootstrap_peers: vec![],
184            enable_mdns: true,                    // Descoberta de peers local
185            enable_kad: true,                     // DHT distribuído
186            network: NetworkConfig::production(), // Configuração robusta de rede
187            storage: StorageConfig::production(), // Cache otimizado
188            pubsub: PubsubConfig::production(),   // PubSub otimizado
189        }
190    }
191
192    /// Determina se deve usar backend embarcado (Iroh ou Híbrido)
193    pub fn should_use_embedded(&self) -> bool {
194        self.data_store_path.is_some()
195    }
196}
197
198/// Configurações específicas de networking
199#[derive(Debug, Clone, Serialize, Deserialize)]
200pub struct NetworkConfig {
201    /// Timeout para conexões
202    pub connection_timeout: Duration,
203
204    /// Número máximo de conexões simultâneas
205    pub max_connections: usize,
206
207    /// Habilita relay de conexões
208    pub enable_relay: bool,
209
210    /// Configurações de transport
211    pub transport: TransportConfig,
212}
213
214impl Default for NetworkConfig {
215    fn default() -> Self {
216        Self {
217            connection_timeout: Duration::from_secs(30),
218            max_connections: 100,
219            enable_relay: false,
220            transport: TransportConfig::default(),
221        }
222    }
223}
224
225impl NetworkConfig {
226    pub fn development() -> Self {
227        Self {
228            connection_timeout: Duration::from_secs(10),
229            max_connections: 10,
230            enable_relay: false,
231            transport: TransportConfig::development(),
232        }
233    }
234
235    pub fn production() -> Self {
236        Self {
237            connection_timeout: Duration::from_secs(60),
238            max_connections: 1000,
239            enable_relay: true,
240            transport: TransportConfig::production(),
241        }
242    }
243
244    pub fn testing() -> Self {
245        Self {
246            connection_timeout: Duration::from_secs(5),
247            max_connections: 5,
248            enable_relay: false,
249            transport: TransportConfig::testing(),
250        }
251    }
252}
253
254/// Configurações de transport de rede
255#[derive(Debug, Clone, Serialize, Deserialize)]
256pub struct TransportConfig {
257    /// Habilita TCP
258    pub enable_tcp: bool,
259
260    /// Habilita QUIC
261    pub enable_quic: bool,
262
263    /// Habilita WebSocket
264    pub enable_websocket: bool,
265
266    /// Configurações de segurança
267    pub security: SecurityConfig,
268}
269
270impl Default for TransportConfig {
271    fn default() -> Self {
272        Self {
273            enable_tcp: true,
274            enable_quic: false,
275            enable_websocket: false,
276            security: SecurityConfig::default(),
277        }
278    }
279}
280
281impl TransportConfig {
282    pub fn development() -> Self {
283        Self {
284            enable_tcp: true,
285            enable_quic: false,
286            enable_websocket: false,
287            security: SecurityConfig::development(),
288        }
289    }
290
291    pub fn production() -> Self {
292        Self {
293            enable_tcp: true,
294            enable_quic: true,
295            enable_websocket: true,
296            security: SecurityConfig::production(),
297        }
298    }
299
300    pub fn testing() -> Self {
301        Self {
302            enable_tcp: true,
303            enable_quic: false,
304            enable_websocket: false,
305            security: SecurityConfig::testing(),
306        }
307    }
308}
309
310/// Configurações de segurança
311#[derive(Debug, Clone, Serialize, Deserialize)]
312pub struct SecurityConfig {
313    /// Habilita encriptação Noise
314    pub enable_noise: bool,
315
316    /// Força uso de TLS
317    pub require_tls: bool,
318}
319
320impl Default for SecurityConfig {
321    fn default() -> Self {
322        Self {
323            enable_noise: true,
324            require_tls: false,
325        }
326    }
327}
328
329impl SecurityConfig {
330    pub fn development() -> Self {
331        Self {
332            enable_noise: false, // Simplificado para desenvolvimento
333            require_tls: false,
334        }
335    }
336
337    pub fn production() -> Self {
338        Self {
339            enable_noise: true,
340            require_tls: true,
341        }
342    }
343
344    pub fn testing() -> Self {
345        Self {
346            enable_noise: false,
347            require_tls: false,
348        }
349    }
350}
351
352/// Configurações de armazenamento
353#[derive(Debug, Clone, Serialize, Deserialize)]
354pub struct StorageConfig {
355    /// Habilita cache em memória
356    pub enable_memory_cache: bool,
357
358    /// Tamanho máximo do cache (bytes)
359    pub max_cache_size: usize,
360
361    /// Habilita compressão de dados
362    pub enable_compression: bool,
363
364    /// Tipo de backend de armazenamento
365    pub backend: StorageBackend,
366}
367
368impl Default for StorageConfig {
369    fn default() -> Self {
370        Self {
371            enable_memory_cache: true,
372            max_cache_size: 100 * 1024 * 1024, // 100MB
373            enable_compression: false,
374            backend: StorageBackend::Memory,
375        }
376    }
377}
378
379impl StorageConfig {
380    pub fn development() -> Self {
381        Self {
382            enable_memory_cache: true,
383            max_cache_size: 10 * 1024 * 1024, // 10MB
384            enable_compression: false,
385            backend: StorageBackend::Memory,
386        }
387    }
388
389    pub fn production() -> Self {
390        Self {
391            enable_memory_cache: true,
392            max_cache_size: 1024 * 1024 * 1024, // 1GB
393            enable_compression: true,
394            backend: StorageBackend::Sled,
395        }
396    }
397
398    pub fn testing() -> Self {
399        Self {
400            enable_memory_cache: false,
401            max_cache_size: 1024 * 1024, // 1MB
402            enable_compression: false,
403            backend: StorageBackend::Memory,
404        }
405    }
406}
407
408/// Tipos de backend de armazenamento
409#[derive(Debug, Clone, Serialize, Deserialize)]
410pub enum StorageBackend {
411    /// Armazenamento apenas em memória
412    Memory,
413    /// Backend Sled (embedded database)
414    Sled,
415    /// Sistema de arquivos
416    FileSystem,
417}
418
419/// Configurações de PubSub
420#[derive(Debug, Clone, Serialize, Deserialize)]
421pub struct PubsubConfig {
422    /// Habilita validação de mensagens
423    pub enable_message_validation: bool,
424
425    /// Tamanho máximo de mensagem (bytes)
426    pub max_message_size: usize,
427
428    /// Buffer size para streams de mensagens
429    pub message_buffer_size: usize,
430
431    /// Timeout para operações de PubSub
432    pub operation_timeout: Duration,
433}
434
435impl Default for PubsubConfig {
436    fn default() -> Self {
437        Self {
438            enable_message_validation: true,
439            max_message_size: 1024 * 1024, // 1MB
440            message_buffer_size: 1000,
441            operation_timeout: Duration::from_secs(30),
442        }
443    }
444}
445
446impl PubsubConfig {
447    pub fn development() -> Self {
448        Self {
449            enable_message_validation: false,
450            max_message_size: 64 * 1024, // 64KB
451            message_buffer_size: 100,
452            operation_timeout: Duration::from_secs(10),
453        }
454    }
455
456    pub fn production() -> Self {
457        Self {
458            enable_message_validation: true,
459            max_message_size: 10 * 1024 * 1024, // 10MB
460            message_buffer_size: 10000,
461            operation_timeout: Duration::from_secs(60),
462        }
463    }
464
465    pub fn testing() -> Self {
466        Self {
467            enable_message_validation: false,
468            max_message_size: 1024, // 1KB
469            message_buffer_size: 10,
470            operation_timeout: Duration::from_secs(5),
471        }
472    }
473}
474
475#[cfg(test)]
476mod tests {
477    use super::*;
478
479    #[test]
480    fn test_default_config() {
481        let config = ClientConfig::default();
482        assert!(config.enable_pubsub);
483        assert!(config.enable_swarm);
484        assert!(config.validate().is_ok());
485    }
486
487    #[test]
488    fn test_development_config() {
489        let config = ClientConfig::development();
490        assert!(config.enable_pubsub);
491        assert!(config.enable_swarm);
492        assert_eq!(config.listening_addrs.len(), 1);
493    }
494
495    #[test]
496    fn test_production_config() {
497        let config = ClientConfig::production();
498        assert!(config.enable_pubsub);
499        assert!(config.enable_swarm);
500        assert!(config.listening_addrs.len() >= 2);
501    }
502
503    #[test]
504    fn test_testing_config() {
505        let config = ClientConfig::testing();
506        assert!(config.enable_pubsub);
507        assert!(!config.enable_swarm);
508        assert!(config.listening_addrs.is_empty());
509    }
510
511    #[test]
512    fn test_offline_config() {
513        let config = ClientConfig::offline();
514        assert!(!config.enable_pubsub);
515        assert!(!config.enable_swarm);
516        assert!(!config.enable_mdns);
517        assert!(!config.enable_kad);
518    }
519
520    #[test]
521    fn test_config_validation() {
522        let mut config = ClientConfig::default();
523
524        // Configuração válida
525        assert!(config.validate().is_ok());
526
527        // PubSub sem Swarm (inválido)
528        config.enable_pubsub = true;
529        config.enable_swarm = false;
530        assert!(config.validate().is_err());
531
532        // Swarm sem endereços de escuta (inválido)
533        config.enable_swarm = true;
534        config.listening_addrs.clear();
535        assert!(config.validate().is_err());
536    }
537
538    #[test]
539    fn test_add_bootstrap_peer() {
540        let mut config = ClientConfig::default();
541        let peer = PeerId::random();
542
543        config.add_bootstrap_peer(peer);
544        assert!(config.bootstrap_peers.contains(&peer));
545
546        // Não deve duplicar
547        config.add_bootstrap_peer(peer);
548        assert_eq!(config.bootstrap_peers.len(), 1);
549    }
550
551    #[test]
552    fn test_with_data_path() {
553        let config = ClientConfig::default().with_data_path("/custom/path");
554
555        assert_eq!(config.data_store_path, Some(PathBuf::from("/custom/path")));
556    }
557
558    #[test]
559    fn test_hybrid_configuration() {
560        let config = ClientConfig::hybrid();
561
562        assert!(config.should_use_embedded());
563        assert!(config.enable_pubsub);
564        assert!(config.enable_swarm);
565        assert!(config.enable_kad);
566    }
567
568    #[test]
569    fn test_backend_detection() {
570        // Configuração embarcada
571        let embedded_config = ClientConfig::development();
572        assert!(embedded_config.should_use_embedded());
573
574        // Configuração híbrida
575        let hybrid_config = ClientConfig::hybrid();
576        assert!(hybrid_config.should_use_embedded());
577    }
578}