use ipfs_api_backend_hyper::{IpfsApi, IpfsClient}; use std::fs::File; use std::path::Path; use tokio::runtime::Runtime; use crate::error::{Result, WebBuilderError}; /// Upload a file to IPFS /// /// # Arguments /// /// * `path` - Path to the file to upload /// /// # Returns /// /// The IPFS hash of the file or an error pub fn upload_file>(path: P) -> Result { let path = path.as_ref(); // Check if the file exists if !path.exists() { return Err(WebBuilderError::MissingFile(path.to_path_buf())); } // Create a tokio runtime let rt = Runtime::new() .map_err(|e| WebBuilderError::Other(format!("Failed to create tokio runtime: {}", e)))?; // Upload the file to IPFS let client = IpfsClient::default(); let ipfs_hash = rt.block_on(async { // Open the file directly - this implements Read trait let file = File::open(path).map_err(|e| WebBuilderError::IoError(e))?; client .add(file) .await .map_err(|e| WebBuilderError::IpfsError(format!("Failed to upload to IPFS: {}", e))) .map(|res| res.hash) })?; Ok(ipfs_hash) } /// Calculate the Blake3 hash of a file /// /// # Arguments /// /// * `path` - Path to the file to hash /// /// # Returns /// /// The Blake3 hash of the file or an error pub fn calculate_blake_hash>(path: P) -> Result { let path = path.as_ref(); // Check if the file exists if !path.exists() { return Err(WebBuilderError::MissingFile(path.to_path_buf())); } // Read the file let content = std::fs::read(path).map_err(|e| WebBuilderError::IoError(e))?; // Calculate the hash let hash = blake3::hash(&content); let hash_hex = hash.to_hex().to_string(); Ok(format!("blake3-{}", hash_hex)) }