rfcp 0.1.0

Replacement for cp
Documentation
use std::{sync::{Arc, Mutex}, path::PathBuf, fs::{Metadata, self, ReadDir}, ops::ControlFlow, fmt::Write};


use console::{style, Emoji};
use indicatif::{ProgressBar, MultiProgress, ProgressStyle, ProgressState};
use io::{FileWriter, FileReader};

pub mod io;
pub mod cmd;

pub static DEFAULT_BUF_SIZE: u32 = 10240;
pub static DEFAULT_THREAD_COUNT:i8 = 3;
static LOOKING_GLASS: Emoji<'_, '_> = Emoji("🔍  ", "");

pub struct Data {
    pub data: Vec<u8>,
    pub offset: u64,
}


#[derive(Clone)]
pub struct SourceFile {
    pub file_path: PathBuf,
    pub size: u64,
}



pub fn walk_dir(mut entries: fs::ReadDir, file_data: Arc<Mutex<Vec<SourceFile>>>, progress_bar: Arc<ProgressBar>){
    while let  Some(Ok(dir_entry)) = entries.next() {
        let path = dir_entry.path();
        
        if let Some(metadata) = folder_metadata(&path) {
            extract_detail_and_walk(metadata, path, file_data.clone(),progress_bar.clone());
        }
    }
}

pub fn folder_metadata(path: &PathBuf) -> Option<Metadata> {
    match fs::metadata(path) {
        Err(err) => {
            eprintln!("Error reading metadata {:?} error {:?}", path, err);
            return Option::None;
        }
        Ok(metadata) => Option::Some(metadata),
    }
}


fn extract_detail_and_walk(
    metadata: Metadata,
    path: PathBuf,
    file_data: Arc<Mutex<Vec<SourceFile>>>,progress_bar: Arc<ProgressBar>
)   {
    let progress_bar = progress_bar.clone();
   
        if metadata.is_file() {
            let mut data = (*file_data).lock().unwrap();
            data.push(SourceFile { file_path: path, size: metadata.len() });
            return;
        }
    
        if metadata.is_dir() {
            progress_bar.set_message(format!("Looking files in: {:?}",path));
            match fs::read_dir(&path) {
                Err(er) => {
                    eprintln!("Error reading directory {:?} error {:?}", path, er);
                }
                Ok(entries) => {
                    walk(entries, file_data,progress_bar.clone());
                }
            }
        }
   
    
}

fn walk(entries: ReadDir, file_data: Arc<Mutex<Vec<SourceFile>>>,progress_bar: Arc<ProgressBar>) {
    let file_data = file_data.clone();
    walk_dir(entries, file_data,progress_bar);
}

pub fn get_reative_path(file: &SourceFile, source: &String) -> String {
    let file_path  = file.file_path.clone();
    let source = PathBuf::from(source.clone());
    let relative_path = file_path.strip_prefix(source).unwrap();
    let relative_path = format!("{:?}",relative_path);
    let relative_path  = relative_path.replace("\"", "");
    relative_path
}

pub fn create_file_writer(relative_path: String, name: String, destination: String, size: u64) -> FileWriter {
    let parent_folder = relative_path.strip_suffix(&name).unwrap();
    let destination = PathBuf::from(destination).join(parent_folder);
    let file_writer = FileWriter::new(destination, name.clone(), size).unwrap();
    file_writer
}

pub fn copy_data(reader: &mut FileReader, offset: &mut u64, buf: &mut Vec<u8>, file_writer: &mut FileWriter, total_size_pb: &Arc<ProgressBar>, total_size_tmp: &Arc<Mutex<usize>>, buffer_size: u32) -> ControlFlow<()> {
    let dat_red = reader.read_random(*offset, buf).unwrap();
    if dat_red == 0 {
        return ControlFlow::Break(());
    }
    file_writer.write_random(*offset, &*buf).unwrap();
    total_size_pb.inc(dat_red as u64);
    let mut total_size = total_size_tmp.lock().unwrap();
    *total_size = *total_size + dat_red;
    *offset = *offset + buffer_size as u64;
    *buf = vec![0; buffer_size as usize];
                        
    ControlFlow::Continue(())
}

pub fn create_progress_bars(multi_progress: &Arc<MultiProgress>, total_size_pb: &Arc<ProgressBar>) -> (Arc<ProgressBar>, Arc<ProgressBar>) {
    let multi_progress = multi_progress.clone();
    let total_size_pb = total_size_pb.clone();
    let current_file = Arc::new(multi_progress.add(ProgressBar::new_spinner()));
    (total_size_pb, current_file)
}

pub fn read_file_metadata(file_reader: FileReader, source: String, file_data_arch: &Arc<Mutex<Vec<SourceFile>>>, progress_bar: &Arc<ProgressBar>, spinner_style: ProgressStyle) -> ControlFlow<()> {
    if file_reader.is_folder() {
        println!("{} {}Searching files...",style("[1/2]").bold().dim(),LOOKING_GLASS);
        let path = PathBuf::from(source);
        let reads = fs::read_dir(path);
        match reads {
            Err(er) => {
                eprintln!("Error reading folder  path {}",er);
                return ControlFlow::Break(());
            }
            Ok(entries) => {
                let file_data_arch = Arc::clone(file_data_arch);
                progress_bar.set_style(spinner_style.clone());
                walk_dir(entries, file_data_arch,progress_bar.clone());
            }
        }
    } else {
        let path_buff = PathBuf::new().join(source);
        let metadata = folder_metadata(&path_buff).unwrap();
        file_data_arch.lock().unwrap().push(SourceFile { file_path: path_buff,size: metadata.len() });
    }
    ControlFlow::Continue(())
}

pub fn create_total_progressbar(multi_progress: &Arc<MultiProgress>, total_size: u64) -> ProgressBar {
    let total_size_pb = multi_progress.add(ProgressBar::new(total_size));
    let sty = ProgressStyle::with_template(
        "[{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({elapsed_precise})",
    )
    .unwrap()
    .with_key("eta", |state: &ProgressState, w: &mut dyn Write| write!(w, "{:.1}s", state.eta().as_secs_f64()).unwrap())
    .progress_chars("#>-");
    total_size_pb.set_style(sty);
    total_size_pb
}