pub struct Node { /* private fields */ }Expand description
IPFRS unified node combining all layers
Implementations§
Source§impl Node
impl Node
Sourcepub fn new(config: NodeConfig) -> Result<Self>
pub fn new(config: NodeConfig) -> Result<Self>
Create a new IPFRS node
Sourcepub fn warmup(&self) -> Result<()>
pub fn warmup(&self) -> Result<()>
Pre-initialize lazy components for faster first access
By default, semantic router and TensorLogic store are initialized lazily on first use. This method forces their initialization upfront, which can be useful for:
- Warmup scenarios where you want predictable latency
- Load testing where you want to measure steady-state performance
- Detecting configuration errors early at startup
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Pre-initialize all components for faster first access
node.warmup()?;
// Now semantic and tensorlogic calls will be instantSourcepub fn status(&self) -> NodeStatus
pub fn status(&self) -> NodeStatus
Get node status
Sourcepub async fn diagnostics(&self) -> Result<NodeDiagnostics>
pub async fn diagnostics(&self) -> Result<NodeDiagnostics>
Get comprehensive node diagnostics
Collects detailed diagnostic information about node health, resource usage, and performance. This is useful for monitoring, troubleshooting, and optimization.
§Example
use ipfrs::{Node, NodeConfig, DiagnosticAnalyzer};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Get diagnostics
let diagnostics = node.diagnostics().await?;
// Analyze and get recommendations
let recommendations = DiagnosticAnalyzer::analyze(&diagnostics);
for rec in recommendations {
println!("{:?}: {}", rec.severity, rec.message);
}
// Or get a human-readable report
let report = DiagnosticAnalyzer::health_report(&diagnostics);
println!("{}", report);Sourcepub fn is_semantic_enabled(&self) -> bool
pub fn is_semantic_enabled(&self) -> bool
Check if semantic routing is enabled
Returns true if the semantic router is configured to be enabled. Note: The router will be lazily initialized on first use.
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
if node.is_semantic_enabled() {
println!("Semantic search is available");
}Sourcepub fn is_tensorlogic_enabled(&self) -> bool
pub fn is_tensorlogic_enabled(&self) -> bool
Check if TensorLogic is enabled
Returns true if the TensorLogic store is configured to be enabled. Note: The store will be lazily initialized on first use.
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
if node.is_tensorlogic_enabled() {
println!("Logic programming is available");
}Sourcepub fn is_running(&self) -> bool
pub fn is_running(&self) -> bool
Check if the node is running
Returns true if the node has been started and the network component is active.
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
assert!(!node.is_running());
node.start().await?;
assert!(node.is_running());Sourcepub fn is_semantic_initialized(&self) -> bool
pub fn is_semantic_initialized(&self) -> bool
Check if semantic router has been initialized
Returns true if the semantic router has been lazily initialized.
This is different from is_semantic_enabled() which checks if it’s configured.
Sourcepub fn is_tensorlogic_initialized(&self) -> bool
pub fn is_tensorlogic_initialized(&self) -> bool
Check if TensorLogic store has been initialized
Returns true if the TensorLogic store has been lazily initialized.
This is different from is_tensorlogic_enabled() which checks if it’s configured.
Sourcepub fn auth_manager(&self) -> Result<Arc<AuthManager>>
pub fn auth_manager(&self) -> Result<Arc<AuthManager>>
Get the authentication manager if enabled
Sourcepub fn is_auth_enabled(&self) -> bool
pub fn is_auth_enabled(&self) -> bool
Check if authentication is enabled
Sourcepub fn create_user(
&self,
username: String,
email: Option<String>,
roles: HashSet<Role>,
) -> Result<User>
pub fn create_user( &self, username: String, email: Option<String>, roles: HashSet<Role>, ) -> Result<User>
Create a new user (requires auth enabled)
Sourcepub fn verify_token(&self, token: &str) -> Result<AuthToken>
pub fn verify_token(&self, token: &str) -> Result<AuthToken>
Verify an authentication token
Sourcepub fn check_permission(
&self,
token: &AuthToken,
permission: Permission,
) -> Result<()>
pub fn check_permission( &self, token: &AuthToken, permission: Permission, ) -> Result<()>
Check if a token has a specific permission
Sourcepub fn tls_manager(&self) -> Result<Arc<TlsManager>>
pub fn tls_manager(&self) -> Result<Arc<TlsManager>>
Get the TLS manager if enabled
Sourcepub fn is_tls_enabled(&self) -> bool
pub fn is_tls_enabled(&self) -> bool
Check if TLS is enabled
Sourcepub async fn add_file(&self, path: impl AsRef<Path>) -> Result<Cid>
pub async fn add_file(&self, path: impl AsRef<Path>) -> Result<Cid>
Add a file from the filesystem
Sourcepub async fn add_bytes(&self, data: impl Into<Bytes>) -> Result<Cid>
pub async fn add_bytes(&self, data: impl Into<Bytes>) -> Result<Cid>
Add bytes directly to storage
Sourcepub async fn add_reader<R>(&self, reader: R) -> Result<Cid>
pub async fn add_reader<R>(&self, reader: R) -> Result<Cid>
Add content from an async reader
Reads all data from the provided reader, stores it as a block, and returns the CID. This is useful for streaming data from files, network streams, or other async sources.
§Example
use ipfrs::{Node, NodeConfig};
use tokio::fs::File;
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
let file = File::open("data.bin").await?;
let cid = node.add_reader(file).await?;
println!("Stored with CID: {}", cid);Sourcepub async fn get_range(
&self,
cid: &Cid,
offset: usize,
length: Option<usize>,
) -> Result<Option<Bytes>>
pub async fn get_range( &self, cid: &Cid, offset: usize, length: Option<usize>, ) -> Result<Option<Bytes>>
Get a byte range from content
Retrieves a specific byte range from a block, similar to HTTP 206 Partial Content. This is useful for streaming large files or implementing range requests.
§Parameters
cid: The content identifieroffset: Starting byte position (0-indexed)length: Number of bytes to read (None for all remaining bytes)
§Returns
Ok(Some(bytes))- The requested byte rangeOk(None)- Block not foundErr(_)- Invalid range or other error
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Get bytes 100-199 (100 bytes starting at offset 100)
if let Some(data) = node.get_range(&cid, 100, Some(100)).await? {
println!("Retrieved {} bytes", data.len());
}Sourcepub async fn get_to_file(&self, cid: &Cid, path: impl AsRef<Path>) -> Result<()>
pub async fn get_to_file(&self, cid: &Cid, path: impl AsRef<Path>) -> Result<()>
Get content and write to file
Sourcepub async fn add_directory(&self, dir_path: impl AsRef<Path>) -> Result<Cid>
pub async fn add_directory(&self, dir_path: impl AsRef<Path>) -> Result<Cid>
Add a directory recursively
Traverses a directory tree, stores all files as blocks, and creates a directory structure using IPLD. Returns the root CID.
§Directory Structure
Directories are stored as IPLD maps where:
- Keys are file/directory names
- Values are either:
- Links to file blocks (for files)
- Nested maps (for subdirectories)
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
let root_cid = node.add_directory("/path/to/directory").await?;
println!("Directory stored with root CID: {}", root_cid);Sourcepub async fn get_directory(
&self,
cid: &Cid,
output_path: impl AsRef<Path>,
) -> Result<()>
pub async fn get_directory( &self, cid: &Cid, output_path: impl AsRef<Path>, ) -> Result<()>
Get a directory and write all files to the filesystem
Retrieves a directory DAG from storage and recreates the directory structure on the filesystem.
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
node.get_directory(&dir_cid, "/path/to/output").await?;Sourcepub async fn dag_put(&self, data: Ipld) -> Result<Cid>
pub async fn dag_put(&self, data: Ipld) -> Result<Cid>
Store an IPLD DAG node
Serializes the IPLD data structure, stores it as a block, and returns the CID. This is useful for storing structured data with links to other blocks.
§Example
use ipfrs::{Node, NodeConfig};
use ipfrs_core::Ipld;
use std::collections::BTreeMap;
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
let mut map = BTreeMap::new();
map.insert("name".to_string(), Ipld::String("Alice".to_string()));
map.insert("age".to_string(), Ipld::Integer(30));
let cid = node.dag_put(Ipld::Map(map)).await?;Sourcepub async fn dag_get(&self, cid: &Cid) -> Result<Option<Ipld>>
pub async fn dag_get(&self, cid: &Cid) -> Result<Option<Ipld>>
Retrieve an IPLD DAG node
Fetches a block by CID and deserializes it as IPLD.
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
if let Some(data) = node.dag_get(&cid).await? {
println!("Retrieved DAG node: {:?}", data);
}Sourcepub async fn dag_resolve(&self, root: &Cid, path: &str) -> Result<Option<Cid>>
pub async fn dag_resolve(&self, root: &Cid, path: &str) -> Result<Option<Cid>>
Resolve an IPLD path
Navigates through IPLD structures following a path like “/key1/key2/0”. Returns the CID if the path leads to a link.
§Path Format
- Map keys: “/key”
- List indices: “/0”, “/1”, etc.
- Nested: “/map_key/0/nested_key”
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Resolve path: /users/0/profile
if let Some(cid) = node.dag_resolve(&root_cid, "/users/0/profile").await? {
println!("Resolved to CID: {}", cid);
}Sourcepub async fn dag_traverse(
&self,
root: &Cid,
max_depth: Option<usize>,
) -> Result<Vec<Cid>>
pub async fn dag_traverse( &self, root: &Cid, max_depth: Option<usize>, ) -> Result<Vec<Cid>>
Traverse a DAG and collect all reachable CIDs
Performs a breadth-first traversal starting from the root CID, following all links and collecting all reachable CIDs.
§Parameters
root: The starting CIDmax_depth: Maximum depth to traverse (None for unlimited)
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Traverse up to depth 10
let cids = node.dag_traverse(&root_cid, Some(10)).await?;
println!("Found {} reachable blocks", cids.len());Sourcepub async fn put_blocks(&self, blocks: &[Block]) -> Result<()>
pub async fn put_blocks(&self, blocks: &[Block]) -> Result<()>
Store multiple blocks atomically
Sourcepub async fn get_blocks(&self, cids: &[Cid]) -> Result<Vec<Option<Block>>>
pub async fn get_blocks(&self, cids: &[Cid]) -> Result<Vec<Option<Block>>>
Retrieve multiple blocks
Sourcepub async fn has_blocks(&self, cids: &[Cid]) -> Result<Vec<bool>>
pub async fn has_blocks(&self, cids: &[Cid]) -> Result<Vec<bool>>
Check if multiple blocks exist
Sourcepub async fn delete_block(&self, cid: &Cid) -> Result<()>
pub async fn delete_block(&self, cid: &Cid) -> Result<()>
Delete a block
Sourcepub async fn delete_blocks(&self, cids: &[Cid]) -> Result<()>
pub async fn delete_blocks(&self, cids: &[Cid]) -> Result<()>
Delete multiple blocks
Sourcepub async fn block_stat(&self, cid: &Cid) -> Result<Option<BlockStat>>
pub async fn block_stat(&self, cid: &Cid) -> Result<Option<BlockStat>>
Get detailed statistics about a block
Returns comprehensive information about a block including its size, CID details, and storage metadata.
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
if let Some(stat) = node.block_stat(&cid).await? {
println!("Block size: {} bytes", stat.size);
println!("CID: {}", stat.cid);
}Sourcepub async fn block_rm(&self, cid: &Cid) -> Result<()>
pub async fn block_rm(&self, cid: &Cid) -> Result<()>
Remove a block from storage
Removes a block if it’s safe to do so. This method checks pinning status and refuses to remove pinned blocks to prevent accidental data loss.
§Safety
This operation is irreversible. The block will be permanently deleted from storage. Pinned blocks are protected and cannot be removed until unpinned.
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
node.block_rm(&cid).await?;
println!("Block removed");Sourcepub fn list_blocks(&self) -> Result<Vec<Cid>>
pub fn list_blocks(&self) -> Result<Vec<Cid>>
List all CIDs in storage
Sourcepub fn storage_stats(&self) -> Result<StorageStats>
pub fn storage_stats(&self) -> Result<StorageStats>
Get storage statistics
Sourcepub fn semantic_stats(&self) -> Result<SemanticStats>
pub fn semantic_stats(&self) -> Result<SemanticStats>
Get semantic router statistics
Returns comprehensive statistics about the semantic index including vector count, dimension, distance metric, and cache performance.
§Returns
Statistics about the semantic router
§Errors
Returns error if semantic routing is not enabled
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
let stats = node.semantic_stats()?;
println!("Indexed vectors: {}", stats.num_vectors);
println!("Vector dimension: {}", stats.dimension);
println!("Cache size: {}/{}", stats.cache_size, stats.cache_capacity);Sourcepub fn tensorlogic_stats(&self) -> Result<TensorLogicStats>
pub fn tensorlogic_stats(&self) -> Result<TensorLogicStats>
Get TensorLogic statistics
Returns information about the TensorLogic store including counts of stored terms, predicates, and rules.
§Returns
Statistics about TensorLogic storage
§Errors
Returns error if TensorLogic is not enabled
§Note
Currently returns basic statistics. Future versions will include knowledge base statistics, inference metrics, and proof counts.
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
let stats = node.tensorlogic_stats()?;
println!("TensorLogic enabled: {}", stats.enabled);Sourcepub async fn index_content(&self, cid: &Cid, embedding: &[f32]) -> Result<()>
pub async fn index_content(&self, cid: &Cid, embedding: &[f32]) -> Result<()>
Index content with its semantic embedding
Adds content to the semantic index for similarity search. The embedding should be a vector representation of the content (e.g., from a sentence transformer model).
§Arguments
cid- Content identifier to indexembedding- Vector embedding of the content
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Index content with 768-dimensional embedding (e.g., from BERT)
let embedding = vec![0.5; 768];
node.index_content(&cid, &embedding).await?;Sourcepub async fn search_similar(
&self,
query_embedding: &[f32],
k: usize,
) -> Result<Vec<SearchResult>>
pub async fn search_similar( &self, query_embedding: &[f32], k: usize, ) -> Result<Vec<SearchResult>>
Search for similar content by semantic similarity
Performs k-nearest neighbor search over indexed content using vector similarity. Returns the top k most similar items.
§Arguments
query_embedding- Query vector to search fork- Number of results to return
§Returns
Vector of search results ordered by similarity (highest first)
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Search for top 10 similar documents
let query_embedding = vec![0.3; 768];
let results = node.search_similar(&query_embedding, 10).await?;
for result in results {
println!("CID: {}, Score: {}", result.cid, result.score);
}Sourcepub async fn search_hybrid(
&self,
query_embedding: &[f32],
k: usize,
filter: QueryFilter,
) -> Result<Vec<SearchResult>>
pub async fn search_hybrid( &self, query_embedding: &[f32], k: usize, filter: QueryFilter, ) -> Result<Vec<SearchResult>>
Search with advanced filtering options
Performs semantic search with additional filters like minimum score threshold, CID prefix matching, and result limits.
§Arguments
query_embedding- Query vector to search fork- Number of results to returnfilter- Query filter options
§Returns
Vector of filtered search results ordered by similarity
§Example
use ipfrs::{Node, NodeConfig, QueryFilter};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Search with filters
let query_embedding = vec![0.3; 768];
let filter = QueryFilter {
min_score: Some(0.8), // Only results with score >= 0.8
max_score: None, // No max score filter
max_results: Some(5), // Limit to 5 results
cid_prefix: None, // No CID filtering
};
let results = node.search_hybrid(&query_embedding, 20, filter).await?;
for result in results {
println!("High-confidence match: {} ({})", result.cid, result.score);
}Sourcepub async fn put_term(&self, term: &Term) -> Result<Cid>
pub async fn put_term(&self, term: &Term) -> Result<Cid>
Store a logical term
Serializes and stores a TensorLogic term as a content-addressed block. Terms can be constants, variables, functions, or references to other CIDs.
§Arguments
term- The logical term to store
§Returns
CID of the stored term
§Example
use ipfrs::{Node, NodeConfig, Term, Constant};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Store a constant term
let term = Term::Const(Constant::String("Alice".to_string()));
let cid = node.put_term(&term).await?;
println!("Stored term with CID: {}", cid);Sourcepub async fn get_term(&self, cid: &Cid) -> Result<Option<Term>>
pub async fn get_term(&self, cid: &Cid) -> Result<Option<Term>>
Retrieve a logical term by CID
Fetches and deserializes a TensorLogic term from storage.
§Arguments
cid- Content identifier of the term
§Returns
The term if found, None otherwise
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
if let Some(term) = node.get_term(&cid).await? {
println!("Retrieved term: {}", term);
}Sourcepub async fn store_predicate(&self, predicate: &Predicate) -> Result<Cid>
pub async fn store_predicate(&self, predicate: &Predicate) -> Result<Cid>
Store a logical predicate
Stores a predicate (named relation with arguments) as a content-addressed block.
§Arguments
predicate- The predicate to store
§Returns
CID of the stored predicate
§Example
use ipfrs::{Node, NodeConfig, Predicate, Term, Constant};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Store a predicate: parent("Alice", "Bob")
let predicate = Predicate::new(
"parent".to_string(),
vec![
Term::Const(Constant::String("Alice".to_string())),
Term::Const(Constant::String("Bob".to_string())),
],
);
let cid = node.store_predicate(&predicate).await?;
println!("Stored predicate with CID: {}", cid);Sourcepub async fn get_predicate(&self, cid: &Cid) -> Result<Option<Predicate>>
pub async fn get_predicate(&self, cid: &Cid) -> Result<Option<Predicate>>
Retrieve a logical predicate by CID
Fetches and deserializes a predicate from storage.
§Arguments
cid- Content identifier of the predicate
§Returns
The predicate if found, None otherwise
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
if let Some(predicate) = node.get_predicate(&cid).await? {
println!("Retrieved predicate: {}", predicate);
}Sourcepub async fn store_rule(&self, rule: &Rule) -> Result<Cid>
pub async fn store_rule(&self, rule: &Rule) -> Result<Cid>
Store a logical rule
Stores a Horn clause (head :- body) as a content-addressed block.
§Arguments
rule- The rule to store
§Returns
CID of the stored rule
§Example
use ipfrs::{Node, NodeConfig, Rule, Predicate, Term, Constant};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Store a fact: parent("Alice", "Bob")
let fact = Rule::fact(Predicate::new(
"parent".to_string(),
vec![
Term::Const(Constant::String("Alice".to_string())),
Term::Const(Constant::String("Bob".to_string())),
],
));
let cid = node.store_rule(&fact).await?;
println!("Stored rule with CID: {}", cid);Sourcepub async fn get_rule(&self, cid: &Cid) -> Result<Option<Rule>>
pub async fn get_rule(&self, cid: &Cid) -> Result<Option<Rule>>
Retrieve a logical rule by CID
Fetches and deserializes a rule from storage.
§Arguments
cid- Content identifier of the rule
§Returns
The rule if found, None otherwise
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
if let Some(rule) = node.get_rule(&cid).await? {
println!("Retrieved rule: head={}, body_len={}", rule.head, rule.body.len());
}Sourcepub fn add_fact(&self, fact: Predicate) -> Result<()>
pub fn add_fact(&self, fact: Predicate) -> Result<()>
Add a fact to the knowledge base
Adds a logical fact (predicate with no body) to the in-memory knowledge base. Facts are used during inference queries.
§Arguments
fact- The predicate to add as a fact
§Example
use ipfrs::{Node, NodeConfig, Predicate, Term, Constant};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Add fact: parent("Alice", "Bob")
let fact = Predicate::new(
"parent".to_string(),
vec![
Term::Const(Constant::String("Alice".to_string())),
Term::Const(Constant::String("Bob".to_string())),
],
);
node.add_fact(fact)?;Sourcepub fn add_rule(&self, rule: Rule) -> Result<()>
pub fn add_rule(&self, rule: Rule) -> Result<()>
Add a rule to the knowledge base
Adds a logical rule (Horn clause) to the in-memory knowledge base. Rules are used during inference queries.
§Arguments
rule- The rule to add
§Example
use ipfrs::{Node, NodeConfig, Rule, Predicate, Term};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Add rule: grandparent(X, Z) :- parent(X, Y), parent(Y, Z)
let head = Predicate::new("grandparent".to_string(), vec![
Term::Var("X".to_string()),
Term::Var("Z".to_string()),
]);
let body = vec![
Predicate::new("parent".to_string(), vec![
Term::Var("X".to_string()),
Term::Var("Y".to_string()),
]),
Predicate::new("parent".to_string(), vec![
Term::Var("Y".to_string()),
Term::Var("Z".to_string()),
]),
];
node.add_rule(Rule::new(head, body))?;Sourcepub fn infer(&self, goal: &Predicate) -> Result<Vec<Substitution>>
pub fn infer(&self, goal: &Predicate) -> Result<Vec<Substitution>>
Run inference query
Executes a logical query using backward chaining inference. Returns all variable substitutions that satisfy the goal.
§Arguments
goal- The query predicate to prove
§Returns
Vector of variable substitutions (bindings) that satisfy the goal
§Example
use ipfrs::{Node, NodeConfig, Predicate, Term, Constant};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Add some facts
node.add_fact(Predicate::new("parent".to_string(), vec![
Term::Const(Constant::String("Alice".to_string())),
Term::Const(Constant::String("Bob".to_string())),
]))?;
// Query: parent("Alice", X)?
let goal = Predicate::new("parent".to_string(), vec![
Term::Const(Constant::String("Alice".to_string())),
Term::Var("X".to_string()),
]);
let solutions = node.infer(&goal)?;
for solution in solutions {
println!("Solution: {:?}", solution);
}Sourcepub fn prove(&self, goal: &Predicate) -> Result<Option<Proof>>
pub fn prove(&self, goal: &Predicate) -> Result<Option<Proof>>
Generate proof tree
Constructs a formal proof for a given goal predicate using backward chaining. Returns the proof if one can be found, None otherwise.
§Arguments
goal- The goal to prove
§Returns
Proof object if goal can be proven, None otherwise
§Example
use ipfrs::{Node, NodeConfig, Predicate, Term, Constant};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Add some facts
node.add_fact(Predicate::new("parent".to_string(), vec![
Term::Const(Constant::String("Alice".to_string())),
Term::Const(Constant::String("Bob".to_string())),
]))?;
// Generate proof
let goal = Predicate::new("parent".to_string(), vec![
Term::Const(Constant::String("Alice".to_string())),
Term::Const(Constant::String("Bob".to_string())),
]);
if let Some(proof) = node.prove(&goal)? {
println!("Proof found: {:?}", proof);
}Sourcepub async fn store_proof(&self, proof: &Proof) -> Result<Cid>
pub async fn store_proof(&self, proof: &Proof) -> Result<Cid>
Store a proof and return its CID
Serializes and stores a proof tree as a content-addressed block.
§Arguments
proof- The proof to store
§Returns
CID of the stored proof
§Example
use ipfrs::{Node, NodeConfig, Predicate, Term, Constant};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Add fact and generate proof
node.add_fact(Predicate::new("parent".to_string(), vec![
Term::Const(Constant::String("Alice".to_string())),
Term::Const(Constant::String("Bob".to_string())),
]))?;
let goal = Predicate::new("parent".to_string(), vec![
Term::Const(Constant::String("Alice".to_string())),
Term::Const(Constant::String("Bob".to_string())),
]);
if let Some(proof) = node.prove(&goal)? {
let cid = node.store_proof(&proof).await?;
println!("Proof stored with CID: {}", cid);
}Sourcepub async fn get_proof(&self, cid: &Cid) -> Result<Option<Proof>>
pub async fn get_proof(&self, cid: &Cid) -> Result<Option<Proof>>
Retrieve a proof by CID
Fetches and deserializes a proof from storage.
§Arguments
cid- Content identifier of the proof
§Returns
The proof if found, None otherwise
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
if let Some(proof) = node.get_proof(&cid).await? {
println!("Retrieved proof for goal: {}", proof.goal);
}Sourcepub fn verify_proof(&self, proof: &Proof) -> Result<bool>
pub fn verify_proof(&self, proof: &Proof) -> Result<bool>
Verify a proof against the current knowledge base
Checks if a proof tree is valid by verifying that:
- All facts exist in the knowledge base
- All rules exist and are correctly applied
- All subproofs are valid
§Arguments
proof- The proof to verify
§Returns
true if the proof is valid, false otherwise
§Example
use ipfrs::{Node, NodeConfig, Predicate, Term, Constant};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Add fact
node.add_fact(Predicate::new("parent".to_string(), vec![
Term::Const(Constant::String("Alice".to_string())),
Term::Const(Constant::String("Bob".to_string())),
]))?;
// Generate and verify proof
let goal = Predicate::new("parent".to_string(), vec![
Term::Const(Constant::String("Alice".to_string())),
Term::Const(Constant::String("Bob".to_string())),
]);
if let Some(proof) = node.prove(&goal)? {
let is_valid = node.verify_proof(&proof)?;
println!("Proof is valid: {}", is_valid);
}Sourcepub fn kb_stats(&self) -> Result<KnowledgeBaseStats>
pub fn kb_stats(&self) -> Result<KnowledgeBaseStats>
Get knowledge base statistics
Returns statistics about the in-memory knowledge base including counts of facts and rules.
§Returns
Knowledge base statistics
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
let stats = node.kb_stats()?;
println!("Facts: {}, Rules: {}", stats.num_facts, stats.num_rules);Sourcepub async fn save_semantic_index(&self, path: impl AsRef<Path>) -> Result<()>
pub async fn save_semantic_index(&self, path: impl AsRef<Path>) -> Result<()>
Save the semantic index to disk
Persists the entire HNSW index including all vectors and CID mappings to a file for later loading.
§Arguments
path- Path to save the index file
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Save the semantic index
node.save_semantic_index("semantic.index").await?;
println!("Semantic index saved");Sourcepub async fn load_semantic_index(&self, path: impl AsRef<Path>) -> Result<()>
pub async fn load_semantic_index(&self, path: impl AsRef<Path>) -> Result<()>
Load a semantic index from disk
Loads a previously saved HNSW index from disk, replacing the current index.
§Arguments
path- Path to the saved index file
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Load the semantic index
node.load_semantic_index("semantic.index").await?;
println!("Semantic index loaded");Sourcepub async fn save_knowledge_base(&self, path: impl AsRef<Path>) -> Result<()>
pub async fn save_knowledge_base(&self, path: impl AsRef<Path>) -> Result<()>
Save the knowledge base to disk
Persists the entire knowledge base (facts and rules) to a file for later loading.
§Arguments
path- Path to save the knowledge base file
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Save the knowledge base
node.save_knowledge_base("knowledge.kb").await?;
println!("Knowledge base saved");Sourcepub async fn load_knowledge_base(&self, path: impl AsRef<Path>) -> Result<()>
pub async fn load_knowledge_base(&self, path: impl AsRef<Path>) -> Result<()>
Load a knowledge base from disk
Loads a previously saved knowledge base from disk, replacing the current KB.
§Arguments
path- Path to the saved knowledge base file
§Example
use ipfrs::{Node, NodeConfig};
let mut node = Node::new(NodeConfig::default())?;
node.start().await?;
// Load the knowledge base
node.load_knowledge_base("knowledge.kb").await?;
println!("Knowledge base loaded");Sourcepub async fn disconnect(&mut self, peer_id: &str) -> Result<()>
pub async fn disconnect(&mut self, peer_id: &str) -> Result<()>
Disconnect from a peer
Sourcepub async fn find_providers(&mut self, cid: &Cid) -> Result<()>
pub async fn find_providers(&mut self, cid: &Cid) -> Result<()>
Find providers for content in DHT
Sourcepub fn network_stats(&self) -> Result<NetworkStats>
pub fn network_stats(&self) -> Result<NetworkStats>
Get network statistics
Sourcepub fn bitswap_stats(&self) -> Result<BitswapStats>
pub fn bitswap_stats(&self) -> Result<BitswapStats>
Get bitswap statistics
Sourcepub async fn ping(&mut self, _peer_id: &str) -> Result<()>
pub async fn ping(&mut self, _peer_id: &str) -> Result<()>
Ping a peer (placeholder implementation)
Sourcepub async fn find_peer(&mut self, peer_id: &str) -> Result<Vec<String>>
pub async fn find_peer(&mut self, peer_id: &str) -> Result<Vec<String>>
Find a peer’s addresses in the DHT (placeholder implementation)
Sourcepub fn bootstrap_peers(&self) -> Result<Vec<String>>
pub fn bootstrap_peers(&self) -> Result<Vec<String>>
Get bootstrap peers
Sourcepub async fn add_bootstrap_peer(&mut self, addr: &str) -> Result<()>
pub async fn add_bootstrap_peer(&mut self, addr: &str) -> Result<()>
Add a bootstrap peer
Sourcepub async fn remove_bootstrap_peer(&mut self, _addr: &str) -> Result<()>
pub async fn remove_bootstrap_peer(&mut self, _addr: &str) -> Result<()>
Remove a bootstrap peer
Sourcepub async fn dag_export(
&self,
root: &Cid,
path: impl AsRef<Path>,
) -> Result<DagExportStats>
pub async fn dag_export( &self, root: &Cid, path: impl AsRef<Path>, ) -> Result<DagExportStats>
Export a DAG to CAR (Content Addressable aRchive) format
Sourcepub async fn dag_import(&self, path: impl AsRef<Path>) -> Result<DagImportStats>
pub async fn dag_import(&self, path: impl AsRef<Path>) -> Result<DagImportStats>
Import blocks from a CAR file
Sourcepub async fn pin_add(
&self,
cid: &Cid,
recursive: bool,
name: Option<String>,
) -> Result<()>
pub async fn pin_add( &self, cid: &Cid, recursive: bool, name: Option<String>, ) -> Result<()>
Pin a block (prevent it from being garbage collected)
Sourcepub async fn repo_fsck(&self) -> Result<FsckResult>
pub async fn repo_fsck(&self) -> Result<FsckResult>
Verify repository integrity
Sourcepub async fn repo_fsck_quick(&self) -> Result<FsckResult>
pub async fn repo_fsck_quick(&self) -> Result<FsckResult>
Run quick filesystem check (only verify CIDs match content)
Sourcepub fn gc_stats(&self) -> Result<(usize, usize)>
pub fn gc_stats(&self) -> Result<(usize, usize)>
Get garbage collection statistics (without running GC)
Sourcepub async fn block_distribution(&self) -> Result<BlockDistribution>
pub async fn block_distribution(&self) -> Result<BlockDistribution>
Get block size distribution
Sourcepub async fn find_duplicates(&self) -> Result<Vec<Vec<Cid>>>
pub async fn find_duplicates(&self) -> Result<Vec<Vec<Cid>>>
Find duplicate blocks (same content, different CIDs)
Sourcepub async fn largest_blocks(&self, limit: usize) -> Result<Vec<(Cid, u64)>>
pub async fn largest_blocks(&self, limit: usize) -> Result<Vec<(Cid, u64)>>
Get largest blocks in the repository
Sourcepub async fn find_orphaned(&self) -> Result<Vec<Cid>>
pub async fn find_orphaned(&self) -> Result<Vec<Cid>>
Find orphaned blocks (not pinned and not referenced)
Auto Trait Implementations§
impl !Freeze for Node
impl !RefUnwindSafe for Node
impl Send for Node
impl !Sync for Node
impl Unpin for Node
impl !UnwindSafe for Node
Blanket Implementations§
Source§impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedExplicit<'a, E> for Twhere
T: 'a,
Source§impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
impl<'a, T, E> AsTaggedImplicit<'a, E> for Twhere
T: 'a,
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> FutureExt for T
impl<T> FutureExt for T
Source§fn with_context(self, otel_cx: Context) -> WithContext<Self>
fn with_context(self, otel_cx: Context) -> WithContext<Self>
Source§fn with_current_context(self) -> WithContext<Self>
fn with_current_context(self) -> WithContext<Self>
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§impl<T> Pointable for T
impl<T> Pointable for T
Source§impl<T> PolicyExt for Twhere
T: ?Sized,
impl<T> PolicyExt for Twhere
T: ?Sized,
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.