helia_interface/lib.rs
1//! # Helia Interface
2//!
3//! The API defined by a Helia node
4//!
5//! This crate provides the core interfaces and traits that define the Helia IPFS implementation.
6//!
7//! ## Example
8//!
9//! ```rust
10//! use helia_interface::Helia;
11//!
12//! async fn do_something<H: Helia>(helia: H) {
13//! // use helia node functions here
14//! }
15//! ```
16
17pub mod blocks;
18pub mod errors;
19pub mod pins;
20pub mod routing;
21
22use std::collections::HashMap;
23use std::future::Future;
24use std::pin::Pin;
25use std::sync::Arc;
26
27use async_trait::async_trait;
28use bytes::Bytes;
29use cid::Cid;
30use futures::Stream;
31use libp2p::Swarm;
32use serde::{Deserialize, Serialize};
33use tokio::sync::{broadcast, Mutex};
34use trust_dns_resolver::TokioAsyncResolver;
35
36pub use blocks::*;
37pub use errors::*;
38pub use pins::*;
39pub use routing::*;
40
41/// Type alias for async iterables/streams
42pub type AwaitIterable<T> = Pin<Box<dyn Stream<Item = T> + Send>>;
43
44/// Type alias for awaitable results
45pub type Await<T> = Pin<Box<dyn Future<Output = T> + Send>>;
46
47/// Options that include an abort signal for canceling operations
48#[derive(Debug, Default)]
49pub struct AbortOptions {
50 // For now, we'll use a simpler approach without tokio channels
51 // pub signal: Option<mpsc::Receiver<()>>,
52}
53
54impl Clone for AbortOptions {
55 fn clone(&self) -> Self {
56 // AbortOptions can't be cloned due to the receiver, so we create a new default one
57 Self::default()
58 }
59}
60
61/// Progress event for tracking operation status
62#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct ProgressEvent<T> {
64 pub event_type: String,
65 pub detail: T,
66}
67
68/// Options for operations that support progress tracking
69pub struct ProgressOptions<T> {
70 /// Optional progress event handler
71 pub on_progress: Option<Box<dyn Fn(ProgressEvent<T>) + Send + Sync>>,
72}
73
74impl<T> std::fmt::Debug for ProgressOptions<T> {
75 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
76 f.debug_struct("ProgressOptions")
77 .field(
78 "on_progress",
79 &self.on_progress.as_ref().map(|_| "Some(closure)"),
80 )
81 .finish()
82 }
83}
84
85impl<T> Default for ProgressOptions<T> {
86 fn default() -> Self {
87 Self { on_progress: None }
88 }
89}
90
91impl<T> Clone for ProgressOptions<T> {
92 fn clone(&self) -> Self {
93 // Progress handlers can't be cloned, so we create a new default one
94 Self::default()
95 }
96}
97
98/// Codec loader for loading IPLD codecs
99#[async_trait]
100pub trait CodecLoader: Send + Sync {
101 /// Load a codec by its code
102 async fn load_codec(&self, code: u64) -> Result<Box<dyn Codec>, HeliaError>;
103}
104
105/// Hasher loader for loading multihash hashers
106#[async_trait]
107pub trait HasherLoader: Send + Sync {
108 /// Load a hasher by its code
109 async fn load_hasher(&self, code: u64) -> Result<Box<dyn Hasher>, HeliaError>;
110}
111
112/// IPLD codec trait
113#[async_trait]
114pub trait Codec: Send + Sync {
115 /// Encode data using this codec
116 async fn encode(&self, data: &[u8]) -> Result<Bytes, HeliaError>;
117
118 /// Decode data using this codec
119 async fn decode(&self, data: &[u8]) -> Result<Bytes, HeliaError>;
120
121 /// Get the codec code
122 fn code(&self) -> u64;
123}
124
125/// Multihash hasher trait
126#[async_trait]
127pub trait Hasher: Send + Sync {
128 /// Hash data using this hasher
129 async fn hash(&self, data: &[u8]) -> Result<multihash::Multihash<64>, HeliaError>;
130
131 /// Get the hasher code
132 fn code(&self) -> u64;
133}
134
135/// Events emitted by a Helia node
136#[derive(Debug, Clone)]
137pub enum HeliaEvent {
138 /// Node has started
139 Start,
140 /// Node has stopped
141 Stop,
142 /// Garbage collection started
143 GcStarted,
144 /// Garbage collection completed
145 GcCompleted,
146}
147
148/// Type alias for event receiver
149pub type HeliaEventReceiver = broadcast::Receiver<HeliaEvent>;
150
151/// Garbage collection options
152#[derive(Debug)]
153pub struct GcOptions {
154 /// Abort options
155 pub abort: AbortOptions,
156 /// Progress options for GC events
157 pub progress: ProgressOptions<GcEvent>,
158}
159
160impl Default for GcOptions {
161 fn default() -> Self {
162 Self {
163 abort: AbortOptions::default(),
164 progress: ProgressOptions::default(),
165 }
166 }
167}
168
169impl Clone for GcOptions {
170 fn clone(&self) -> Self {
171 Self {
172 abort: self.abort.clone(),
173 progress: self.progress.clone(),
174 }
175 }
176}
177
178/// Events emitted during garbage collection
179#[derive(Debug, Clone, Serialize, Deserialize)]
180pub enum GcEvent {
181 /// A CID was deleted
182 Deleted(Cid),
183 /// An error occurred during GC
184 Error(String),
185}
186
187/// Component logger for structured logging
188pub trait ComponentLogger: Send + Sync {
189 /// Log a debug message
190 fn debug(&self, message: &str);
191 /// Log an info message
192 fn info(&self, message: &str);
193 /// Log a warning message
194 fn warn(&self, message: &str);
195 /// Log an error message
196 fn error(&self, message: &str);
197}
198
199/// Metrics collection interface
200#[async_trait]
201pub trait Metrics: Send + Sync {
202 /// Record a counter metric
203 async fn record_counter(&self, name: &str, value: u64, labels: HashMap<String, String>);
204
205 /// Record a gauge metric
206 async fn record_gauge(&self, name: &str, value: f64, labels: HashMap<String, String>);
207
208 /// Record a histogram metric
209 async fn record_histogram(&self, name: &str, value: f64, labels: HashMap<String, String>);
210}
211
212/// Non-generic Helia trait for backward compatibility and trait objects
213#[async_trait]
214pub trait Helia: Send + Sync {
215 /// The blockstore for storing blocks
216 fn blockstore(&self) -> &dyn Blocks;
217
218 /// The datastore for key-value storage
219 fn datastore(&self) -> &dyn Datastore;
220
221 /// Pinning operations
222 fn pins(&self) -> &dyn Pins;
223
224 /// The logger component
225 fn logger(&self) -> &dyn ComponentLogger;
226
227 /// The routing component
228 fn routing(&self) -> &dyn Routing;
229
230 /// DNS resolver
231 fn dns(&self) -> &TokioAsyncResolver;
232
233 /// Optional metrics collector
234 fn metrics(&self) -> Option<&dyn Metrics>;
235
236 /// Subscribe to events emitted by this Helia node
237 ///
238 /// Returns a receiver that will receive all events emitted by the node.
239 /// Multiple subscribers can listen to events simultaneously.
240 ///
241 /// # Example
242 ///
243 /// ```rust,ignore
244 /// use helia_interface::{Helia, HeliaEvent};
245 ///
246 /// let mut events_rx = helia.subscribe_events();
247 ///
248 /// tokio::spawn(async move {
249 /// while let Ok(event) = events_rx.recv().await {
250 /// match event {
251 /// HeliaEvent::Start => println!("Helia started"),
252 /// HeliaEvent::Stop => println!("Helia stopped"),
253 /// HeliaEvent::GcStarted => println!("GC started"),
254 /// HeliaEvent::GcCompleted => println!("GC completed"),
255 /// }
256 /// }
257 /// });
258 /// ```
259 fn subscribe_events(&self) -> HeliaEventReceiver;
260
261 /// Start the Helia node
262 async fn start(&self) -> Result<(), HeliaError>;
263
264 /// Stop the Helia node
265 async fn stop(&self) -> Result<(), HeliaError>;
266
267 /// Perform garbage collection
268 async fn gc(&self, options: Option<GcOptions>) -> Result<(), HeliaError>;
269
270 /// Load an IPLD codec
271 async fn get_codec(&self, code: u64) -> Result<Box<dyn Codec>, HeliaError>;
272
273 /// Load a hasher
274 async fn get_hasher(&self, code: u64) -> Result<Box<dyn Hasher>, HeliaError>;
275}
276
277/// Generic Helia trait with libp2p type parameter for concrete implementations
278#[async_trait]
279pub trait HeliaWithLibp2p<T>: Helia
280where
281 T: libp2p::swarm::NetworkBehaviour + Send + 'static,
282{
283 /// The libp2p swarm instance (wrapped in Arc<Mutex<>> for thread safety)
284 fn libp2p(&self) -> Arc<Mutex<Swarm<T>>>;
285}
286
287/// Trait for NetworkBehaviours that include Bitswap
288///
289/// This trait allows Helia to work with any custom `NetworkBehaviour` that includes
290/// a `BitswapBehaviour` field. By implementing this trait, applications can share
291/// their custom swarm with Helia instead of running separate connections.
292///
293/// # Example
294///
295/// ```rust,ignore
296/// use libp2p::swarm::NetworkBehaviour;
297/// use helia_bitswap::BitswapBehaviour;
298/// use helia_interface::WithBitswap;
299///
300/// #[derive(NetworkBehaviour)]
301/// pub struct MyBehaviour {
302/// pub gossipsub: gossipsub::Behaviour,
303/// pub bitswap: BitswapBehaviour,
304/// }
305///
306/// impl WithBitswap for MyBehaviour {
307/// fn bitswap_mut(&mut self) -> &mut BitswapBehaviour {
308/// &mut self.bitswap
309/// }
310///
311/// fn bitswap(&self) -> &BitswapBehaviour {
312/// &self.bitswap
313/// }
314/// }
315/// ```
316pub trait WithBitswap {
317 /// Get a mutable reference to the BitswapBehaviour
318 fn bitswap_mut(&mut self) -> &mut dyn std::any::Any;
319
320 /// Get an immutable reference to the BitswapBehaviour
321 fn bitswap(&self) -> &dyn std::any::Any;
322}
323
324/// Key-value datastore interface
325#[async_trait]
326pub trait Datastore: Send + Sync {
327 /// Get a value by key
328 async fn get(&self, key: &[u8]) -> Result<Option<Bytes>, HeliaError>;
329
330 /// Put a key-value pair
331 async fn put(&self, key: &[u8], value: Bytes) -> Result<(), HeliaError>;
332
333 /// Delete a key
334 async fn delete(&self, key: &[u8]) -> Result<(), HeliaError>;
335
336 /// Check if a key exists
337 async fn has(&self, key: &[u8]) -> Result<bool, HeliaError>;
338
339 /// Query for keys with optional filters
340 async fn query(&self, prefix: Option<&[u8]>) -> Result<AwaitIterable<Bytes>, HeliaError>;
341}