From 709713c4dce4392c1d995b38938a3eba38daf4c0 Mon Sep 17 00:00:00 2001 From: David Irvine Date: Fri, 29 Nov 2024 11:22:41 +0000 Subject: [PATCH] feat: add command line arguments to parallel decryptor example Enhanced the parallel streaming decryptor example with proper CLI handling: - Added required command line arguments for: - Data map file path (-d, --data-map) - Chunks directory path (-c, --chunks-dir) - Output file path (-o, --output) - Added comprehensive path validation: - Checks data map file exists and is readable - Verifies chunks directory exists and is a directory - Validates output directory exists and is writable - Added clap dependency with derive features - Improved error messages and user feedback The example now provides a more robust CLI interface with proper validation before attempting decryption operations. --- Cargo.toml | 1 + examples/parallel_streaming_decryptor.rs | 82 ++++++++++++++++++++++-- 2 files changed, 78 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index c49ea3f17..7470b288e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,6 +57,7 @@ features = ["rt"] [dev-dependencies] criterion = "~0.3" docopt = "~0.9.0" +clap = { version = "4.4", features = ["derive"] } [dev-dependencies.tokio] version = "1.34.0" diff --git a/examples/parallel_streaming_decryptor.rs b/examples/parallel_streaming_decryptor.rs index 24751a36e..6881519c3 100644 --- a/examples/parallel_streaming_decryptor.rs +++ b/examples/parallel_streaming_decryptor.rs @@ -3,18 +3,88 @@ use rayon::prelude::*; use self_encryption::{deserialize, streaming_decrypt_from_storage, DataMap, Error, Result}; use std::{fs::File, io::Read, path::Path}; use xor_name::XorName; +use clap::{Parser, error::ErrorKind}; + +/// Parallel streaming decryptor for self-encrypted files +#[derive(Parser, Debug)] +#[command(author, version, about, long_about = None)] +struct Args { + /// Path to the data map file + #[arg(short, long, required = true)] + data_map: String, + + /// Directory containing the encrypted chunks + #[arg(short, long, required = true)] + chunks_dir: String, + + /// Path where the decrypted file should be written + #[arg(short, long, required = true)] + output: String, +} + +fn validate_paths(args: &Args) -> Result<()> { + // Check data map file exists and is readable + if !Path::new(&args.data_map).exists() { + return Err(Error::Generic(format!( + "Data map file does not exist: {}", + args.data_map + ))); + } + + // Check chunks directory exists and is readable + let chunks_dir = Path::new(&args.chunks_dir); + if !chunks_dir.exists() { + return Err(Error::Generic(format!( + "Chunks directory does not exist: {}", + args.chunks_dir + ))); + } + if !chunks_dir.is_dir() { + return Err(Error::Generic(format!( + "Chunks path is not a directory: {}", + args.chunks_dir + ))); + } + + // Check output parent directory exists and is writable + let output_path = Path::new(&args.output); + if let Some(parent) = output_path.parent() { + if !parent.exists() { + return Err(Error::Generic(format!( + "Output directory does not exist: {}", + parent.display() + ))); + } + // Try to verify write permissions + if !parent.metadata() + .map(|m| m.permissions().readonly()) + .unwrap_or(true) + { + return Err(Error::Generic(format!( + "Output directory is not writable: {}", + parent.display() + ))); + } + } + + Ok(()) +} fn main() -> Result<()> { - // Load the data map from file or another source - let data_map = load_data_map("path/to/data_map")?; + let args = Args::parse(); + + // Validate all paths before proceeding + validate_paths(&args)?; + + // Load the data map from file + let data_map = load_data_map(&args.data_map)?; // Implement the parallel chunk retrieval function let get_chunk_parallel = |hashes: &[XorName]| -> Result> { hashes .par_iter() .map(|hash| { - // Simulate network retrieval with local file read - let chunk_path = Path::new("chunks").join(hex::encode(hash)); + let chunk_path = Path::new(&args.chunks_dir).join(hex::encode(hash)); let mut chunk_data = Vec::new(); File::open(&chunk_path) .and_then(|mut file| file.read_to_end(&mut chunk_data)) @@ -25,7 +95,9 @@ fn main() -> Result<()> { }; // Use the streaming decryption function - streaming_decrypt_from_storage(&data_map, Path::new("output_file.dat"), get_chunk_parallel)?; + streaming_decrypt_from_storage(&data_map, Path::new(&args.output), get_chunk_parallel)?; + + println!("Successfully decrypted file to: {}", args.output); Ok(()) }