1
2use std::collections::HashMap;
3use std::fs::read_dir;
4use std::path::Path;
5use round::round;
6use serde::Serialize;
7
8#[derive(Debug,Serialize)]
9pub struct FileInfo {
10    pub path: String,
11    pub extension: String,
12    pub file_size_raw: u64,
13    pub file_size_label: String
14}
15
16#[derive(Debug,Serialize)]
17pub enum TreeType {
18    File(FileInfo),
19    Dir(HashMap<String,Vec<TreeType>>)
20}
21pub fn file_size_to_string(mut file_size: f64,file_size_round: i32) -> String {
29    let units: Vec<&str> = Vec::from(
30        ["b","kb","mb","gb","tb","pb"]
31    );
32    let mut selected_unit: &str = "b";
33
34    for unit in units {
35        if  file_size < 1024.00 {
36            selected_unit = unit;
37            break;
38        }
39        else {            
40            file_size = file_size / 1024.00;
41        }
42    }
43    format!("{}{}",round(file_size,file_size_round),selected_unit)
44}
45
46pub fn explore(base_path: &Path, data: &mut HashMap<String,Vec<TreeType>>,file_size_round: i32) {
58    match read_dir(base_path){
59        Ok(rd) => {
60            let mut inner_files: Vec<TreeType> = Vec::new();
61            for dir_entry in rd {
62                if let Ok(ref entry) = dir_entry {
63                    if entry.path().is_dir() {
64                        let mut inner_dirs: HashMap<String,Vec<TreeType>> = HashMap::new();
65                        explore(entry.path().as_path(), &mut inner_dirs,file_size_round);                        
66                        inner_files.push(
67                            TreeType::Dir( inner_dirs)
68                        );
69                    }
70                    else if entry.path().is_file() {                        
71                        let file_size_raw:u64 = entry.path().metadata().unwrap().len();
72                        inner_files.push(
73                            TreeType::File( 
74                                FileInfo{ 
75                                    path: entry.file_name().to_str().unwrap().to_string(),
76                                    extension: entry.path().extension().unwrap().to_str().unwrap().to_string(),
77                                    file_size_raw,
78                                    file_size_label: file_size_to_string(file_size_raw as f64,file_size_round)
79                                }
80                            ) 
81                        );
82                    }
83                }
84            }
85            if inner_files.len() > 0 {
86                data.insert(base_path.file_name().unwrap().to_str().unwrap().to_string(), inner_files );
87            }
88        }
89        Err(error) => {
90            panic!("{}",error);
91        }
92    }
93}
94
95pub fn to_json(data: HashMap<String,Vec<TreeType>>) -> String {
108    serde_json::to_string_pretty(&data).unwrap()
109}
110
111#[cfg(test)]
112mod test_fd_mapping {
113    use super::*;
114    
115    #[test]
116    fn test_explore(){
117        let base_path: String = String::from("storage/test-data");
118        let mut data: HashMap<String,Vec<TreeType>> = HashMap::new();
119        explore(Path::new(&base_path),&mut data,1);
120        let mapping:String = to_json(data);
121        println!("{}",mapping);
122    }
123    #[test]
124    fn test_file_size_converter(){
125
126        for t in vec![
127            (1024,"1kb"),
128            (1024,"1kb"),
129            (1048576,"1mb"),
130            (1073741824,"1gb"),
131            (1,"1b")
132        ] {
133            let result: String = file_size_to_string(f64::from(t.0),1);
134            println!("{:#?}",result);
135            assert_eq!(result,t.1);
136        }
137    }
138}