guardian_db/ipfs_core_api/backends/mod.rs
1/// Backend intercambiável para operações IPFS
2///
3/// Este módulo define a interface comum para diferentes implementações de IPFS,
4/// permitindo suporte nativo ao Iroh e implementações híbridas.
5use crate::error::{GuardianError, Result};
6use crate::ipfs_core_api::types::*;
7use async_trait::async_trait;
8use cid::Cid;
9use libp2p::PeerId;
10use std::pin::Pin;
11use tokio::io::AsyncRead;
12
13// Módulos principais
14pub mod hybrid;
15pub mod iroh;
16pub mod iroh_pubsub;
17pub mod key_synchronizer;
18pub mod networking_metrics;
19
20// Módulos de otimização
21pub mod batch_processor;
22pub mod connection_pool;
23pub mod optimized_cache;
24
25pub use hybrid::HybridBackend;
26pub use iroh::IrohBackend;
27pub use iroh_pubsub::IrohPubSub;
28
29/// Trait principal para backends IPFS intercambiáveis
30///
31/// Define a interface comum que todos os backends devem implementar,
32/// garantindo compatibilidade total independentemente da implementação subjacente.
33#[async_trait]
34pub trait IpfsBackend: Send + Sync + 'static {
35 // === OPERAÇÕES DE CONTEÚDO ===
36
37 /// Adiciona dados ao IPFS e retorna o CID resultante
38 ///
39 /// # Argumentos
40 /// * `data` - Stream de dados para adicionar
41 ///
42 /// # Retorna
43 /// Resposta contendo o CID e metadados do objeto adicionado
44 async fn add(&self, data: Pin<Box<dyn AsyncRead + Send>>) -> Result<AddResponse>;
45
46 /// Recupera dados do IPFS pelo CID
47 ///
48 /// # Argumentos
49 /// * `cid` - Content Identifier do objeto desejado
50 ///
51 /// # Retorna
52 /// Stream de dados do objeto
53 async fn cat(&self, cid: &str) -> Result<Pin<Box<dyn AsyncRead + Send>>>;
54
55 /// Fixa um objeto no storage local (evita garbage collection)
56 ///
57 /// # Argumentos
58 /// * `cid` - CID do objeto a ser fixado
59 async fn pin_add(&self, cid: &str) -> Result<()>;
60
61 /// Remove fixação de um objeto (permite garbage collection)
62 ///
63 /// # Argumentos
64 /// * `cid` - CID do objeto a ser desfixado
65 async fn pin_rm(&self, cid: &str) -> Result<()>;
66
67 /// Lista objetos fixados
68 ///
69 /// # Retorna
70 /// Lista de CIDs fixados com seus tipos
71 async fn pin_ls(&self) -> Result<Vec<PinInfo>>;
72
73 // === OPERAÇÕES DE REDE ===
74
75 /// Conecta explicitamente a um peer
76 ///
77 /// # Argumentos
78 /// * `peer` - ID do peer para conectar
79 async fn connect(&self, peer: &PeerId) -> Result<()>;
80
81 /// Lista peers atualmente conectados
82 ///
83 /// # Retorna
84 /// Lista de informações dos peers conectados
85 async fn peers(&self) -> Result<Vec<PeerInfo>>;
86
87 /// Obtém informações do nó local
88 ///
89 /// # Retorna
90 /// Informações do nó incluindo ID, chaves públicas, endereços
91 async fn id(&self) -> Result<NodeInfo>;
92
93 /// Resolve um peer ID para seus endereços conhecidos
94 ///
95 /// # Argumentos
96 /// * `peer` - PeerId a ser resolvido
97 ///
98 /// # Retorna
99 /// Lista de endereços multiaddr do peer
100 async fn dht_find_peer(&self, peer: &PeerId) -> Result<Vec<String>>;
101
102 // === OPERAÇÕES DO REPOSITÓRIO ===
103
104 /// Obtém estatísticas do repositório local
105 ///
106 /// # Retorna
107 /// Estatísticas incluindo tamanho, número de objetos, etc.
108 async fn repo_stat(&self) -> Result<RepoStats>;
109
110 /// Obtém versão e informações do nó IPFS
111 ///
112 /// # Retorna
113 /// Informações de versão do software IPFS
114 async fn version(&self) -> Result<VersionInfo>;
115
116 // === OPERAÇÕES DE BLOCOS (LOWER-LEVEL) ===
117
118 /// Obtém um bloco raw pelo seu CID
119 ///
120 /// # Argumentos
121 /// * `cid` - CID do bloco desejado
122 ///
123 /// # Retorna
124 /// Dados raw do bloco
125 async fn block_get(&self, cid: &Cid) -> Result<Vec<u8>>;
126
127 /// Armazena dados raw como bloco
128 ///
129 /// # Argumentos
130 /// * `data` - Dados raw para armazenar
131 ///
132 /// # Retorna
133 /// CID do bloco criado
134 async fn block_put(&self, data: Vec<u8>) -> Result<Cid>;
135
136 /// Verifica se um bloco existe localmente
137 ///
138 /// # Argumentos
139 /// * `cid` - CID do bloco a verificar
140 ///
141 /// # Retorna
142 /// true se o bloco existe localmente
143 async fn block_stat(&self, cid: &Cid) -> Result<BlockStats>;
144
145 // === METADADOS DO BACKEND ===
146
147 /// Retorna o tipo/nome do backend
148 fn backend_type(&self) -> BackendType;
149
150 /// Verifica se o backend está online e operacional
151 async fn is_online(&self) -> bool;
152
153 /// Obtém métricas de performance do backend
154 async fn metrics(&self) -> Result<BackendMetrics>;
155
156 /// Executa health check completo do backend
157 async fn health_check(&self) -> Result<HealthStatus>;
158}
159
160/// Tipo do backend IPFS
161#[derive(Debug, Clone, PartialEq, Eq)]
162pub enum BackendType {
163 /// Backend usando Iroh embarcado (padrão)
164 Iroh,
165 /// Backend híbrido (Iroh + LibP2P)
166 Hybrid,
167 /// Backend de teste/mock
168 Mock,
169}
170
171impl BackendType {
172 pub fn as_str(&self) -> &'static str {
173 match self {
174 BackendType::Iroh => "iroh",
175 BackendType::Hybrid => "hybrid",
176 BackendType::Mock => "mock",
177 }
178 }
179}
180
181/// Informações de um objeto fixado
182#[derive(Debug, Clone)]
183pub struct PinInfo {
184 pub cid: String,
185 pub pin_type: PinType,
186}
187
188/// Tipo de fixação (pin)
189#[derive(Debug, Clone, PartialEq, Eq)]
190pub enum PinType {
191 /// Fixação direta do objeto
192 Direct,
193 /// Fixação recursiva (inclui referencias)
194 Recursive,
195 /// Fixação indireta (referenciado por outro pin)
196 Indirect,
197}
198
199/// Estatísticas de um bloco
200#[derive(Debug, Clone)]
201pub struct BlockStats {
202 pub cid: Cid,
203 pub size: u64,
204 pub exists_locally: bool,
205}
206
207/// Estatísticas de garbage collection
208#[derive(Debug, Clone)]
209pub struct GcStats {
210 pub blocks_removed: u64,
211 pub bytes_freed: u64,
212 pub duration_ms: u64,
213}
214
215/// Métricas de performance do backend
216#[derive(Debug, Clone)]
217pub struct BackendMetrics {
218 /// Operações por segundo
219 pub ops_per_second: f64,
220 /// Latência média em ms
221 pub avg_latency_ms: f64,
222 /// Número de operações totais
223 pub total_operations: u64,
224 /// Número de erros
225 pub error_count: u64,
226 /// Uso de memória em bytes
227 pub memory_usage_bytes: u64,
228}
229
230/// Status de saúde do backend
231#[derive(Debug, Clone)]
232pub struct HealthStatus {
233 /// Backend está saudável
234 pub healthy: bool,
235 /// Mensagem descritiva
236 pub message: String,
237 /// Tempo de resposta em ms
238 pub response_time_ms: u64,
239 /// Componentes verificados
240 pub checks: Vec<HealthCheck>,
241}
242
243/// Verificação individual de saúde
244#[derive(Debug, Clone)]
245pub struct HealthCheck {
246 pub name: String,
247 pub passed: bool,
248 pub message: String,
249}
250
251/// Factory para criar backends baseado na configuração
252pub struct BackendFactory;
253
254impl BackendFactory {
255 /// Cria um backend baseado no tipo especificado
256 ///
257 /// # Argumentos
258 /// * `backend_type` - Tipo do backend desejado
259 /// * `config` - Configuração específica do backend
260 ///
261 /// # Retorna
262 /// Instância do backend configurado
263 pub async fn create_backend(
264 backend_type: BackendType,
265 config: &crate::ipfs_core_api::config::ClientConfig,
266 ) -> Result<Box<dyn IpfsBackend>> {
267 match backend_type {
268 BackendType::Iroh => {
269 let backend = iroh::IrohBackend::new(config).await?;
270 Ok(Box::new(backend))
271 }
272 BackendType::Hybrid => {
273 let backend = hybrid::HybridBackend::new(config).await?;
274 Ok(Box::new(backend))
275 }
276 BackendType::Mock => Err(GuardianError::Other(
277 "Mock backend não implementado ainda".to_string(),
278 )),
279 }
280 }
281
282 /// Auto-detecta o melhor backend baseado na configuração disponível
283 ///
284 /// # Argumentos
285 /// * `config` - Configuração do cliente
286 ///
287 /// # Retorna
288 /// Backend mais apropriado para a configuração
289 pub async fn auto_detect_backend(
290 config: &crate::ipfs_core_api::config::ClientConfig,
291 ) -> Result<Box<dyn IpfsBackend>> {
292 // Prioridade: Hybrid > Iroh (nativo)
293
294 // Tenta Hybrid primeiro (melhor desempenho + compatibilidade P2P)
295 if config.data_store_path.is_some()
296 && config.enable_pubsub
297 && let Ok(backend) = hybrid::HybridBackend::new(config).await
298 {
299 return Ok(Box::new(backend));
300 }
301
302 // Fallback para Iroh puro (sempre disponível)
303 if let Ok(backend) = iroh::IrohBackend::new(config).await {
304 return Ok(Box::new(backend));
305 }
306
307 Err(GuardianError::Other(
308 "Falha ao inicializar backend Iroh".to_string(),
309 ))
310 }
311}