diff --git a/client/src/file.rs b/client/src/file.rs index 149d309..14e80ce 100644 --- a/client/src/file.rs +++ b/client/src/file.rs @@ -1,11 +1,12 @@ use tokio::{ - fs::{read_dir, remove_file, DirBuilder, File, OpenOptions}, + fs::{remove_file, DirBuilder, File, OpenOptions}, io::{AsyncReadExt, AsyncWriteExt}, }; use sha3::{Digest, Sha3_512}; const PACKAGE_PATH: &str = "./packages/"; +const METADATA_FILE_NAME: &str = "metadata.txt"; pub async fn save_package(package_name: String, package_data: &[u8]) -> Result<(), std::io::Error> { let file_location = format!("{}{}", PACKAGE_PATH, package_name); @@ -22,23 +23,25 @@ pub async fn delete_package(package_name: String) -> Result<(), std::io::Error> delete_metadata(package_name).await } -pub async fn list_packages() -> Option> { - let mut folder_elements = read_dir(PACKAGE_PATH).await.ok()?; - let mut packages = vec![]; - loop { - match folder_elements.next_entry().await.ok()? { - Some(file_entry) => packages.push(file_entry.file_name().into_string().ok()?), - None => break, +pub async fn list_installed_packages() -> Result, std::io::Error> { + let metadata_file_location = format!("{}{}", PACKAGE_PATH, METADATA_FILE_NAME); + let mut metadata_file = match File::open(&metadata_file_location).await { + Ok(metadata_file) => metadata_file, + Err(_) => { + File::create_new(&metadata_file_location).await?; + return Ok(vec![]); } + }; + let mut metadata = String::default(); + metadata_file.read_to_string(&mut metadata).await?; + let mut package_names = vec![]; + for line in metadata.lines() { + package_names.push(line.trim_end().to_string()); } - - if packages.is_empty() { - return None; - } - Some(packages) + Ok(package_names) } -async fn calculate_hash(package_name: String) -> Result>, std::io::Error> { +pub async fn calculate_hash(package_name: String) -> Result>, std::io::Error> { if let Some(_) = search_metadata(package_name.to_owned()).await? { let file_location = format!("{}{}", PACKAGE_PATH, package_name); let mut target_file = File::open(file_location).await?; @@ -53,7 +56,7 @@ async fn calculate_hash(package_name: String) -> Result>, std::io } async fn search_metadata(package_name: String) -> Result, std::io::Error> { - let file_location = format!("{}{}", PACKAGE_PATH, "metadata.txt"); + let file_location = format!("{}{}", PACKAGE_PATH, METADATA_FILE_NAME); let mut file = match File::open(file_location.clone()).await { Ok(file) => file, Err(_) => { @@ -75,7 +78,7 @@ async fn search_metadata(package_name: String) -> Result, std::io: async fn search_and_retrieve_metadata( package_name: String, ) -> Result<(Option, Vec), std::io::Error> { - let file_location = format!("{}{}", PACKAGE_PATH, "metadata.txt"); + let file_location = format!("{}{}", PACKAGE_PATH, METADATA_FILE_NAME); let mut file = match File::open(file_location.clone()).await { Ok(file) => file, Err(_) => { @@ -98,7 +101,7 @@ async fn search_and_retrieve_metadata( async fn save_metadata(package_name: String) -> Result<(), std::io::Error> { let searched = search_metadata(package_name.to_owned()).await?; if searched.is_none() { - let file_location = format!("{}{}", PACKAGE_PATH, "metadata.txt"); + let file_location = format!("{}{}", PACKAGE_PATH, METADATA_FILE_NAME); let mut file = OpenOptions::new() .append(true) .create(true) @@ -118,7 +121,7 @@ async fn delete_metadata(package_name: String) -> Result<(), std::io::Error> { None => return Err(std::io::ErrorKind::NotFound.into()), }; - let file_location = format!("{}{}", PACKAGE_PATH, "metadata.txt"); + let file_location = format!("{}{}", PACKAGE_PATH, METADATA_FILE_NAME); let mut file = OpenOptions::new() .append(false) .create(false) diff --git a/client/src/package.rs b/client/src/package.rs index 7b3f5c9..0e437a0 100644 --- a/client/src/package.rs +++ b/client/src/package.rs @@ -18,6 +18,9 @@ impl Package { pub fn get_name(&self) -> String { self.name.clone() } + pub fn get_hash(&self) -> Vec { + self.hash.to_vec() + } } impl Default for Package { diff --git a/client/src/user.rs b/client/src/user.rs index d55bc39..f472fb0 100644 --- a/client/src/user.rs +++ b/client/src/user.rs @@ -1,5 +1,7 @@ use std::env; +use crate::file::calculate_hash; + fn env_collector() -> Vec { let mut env_values = env::args().collect::>(); env_values.remove(0); @@ -47,6 +49,25 @@ pub async fn user_interaction() { delete_package(package_name).await; return; } + "list_installed_packages" => { + list_installed_packages().await; + return; + } + "update_package" => { + let package_name = match env_values.get(i + 1) { + Some(package_name) => package_name, + None => { + eprintln!("Length is not enough"); + return; + } + }; + update_package(package_name).await; + return; + } + "update_all_packages" => { + update_all_packages().await; + return; + } _ => { eprintln!("Need an Argument"); return; @@ -92,3 +113,65 @@ async fn delete_package(package_name: &String) { Err(err_val) => eprintln!("Error: Delete Package | {}", err_val), } } + +async fn list_installed_packages() { + match crate::file::list_installed_packages().await { + Ok(package_names) => { + if package_names.is_empty() { + println!("There is no installed package"); + return; + } + for package_name in package_names { + println!("{}", package_name); + } + } + Err(err_val) => eprintln!("Error: List Installed Packages | {}", err_val), + } +} + +async fn update_package(package_name: &String) { + let target_package_local_hash = match calculate_hash(package_name.to_owned()).await { + Ok(target_package_local_hash) => match target_package_local_hash { + Some(target_package_local_hash) => target_package_local_hash, + None => { + eprintln!( + "Error: No Metadata Found for Local Hash Calculation | {}", + package_name + ); + return; + } + }, + Err(err_val) => { + eprintln!( + "Error: Local Hash Calculation | {} | {}", + package_name, err_val + ); + return; + } + }; + match crate::request::read_package(package_name.to_owned()).await { + Some(package) => match package.get_hash().eq(&target_package_local_hash) { + true => println!("Package is Already Up to Date"), + false => { + println!("New Version is Found, Installing"); + install_package(package_name).await; + } + }, + None => eprintln!("Error: Update Package | {}", package_name), + } +} + +async fn update_all_packages() { + match crate::file::list_installed_packages().await { + Ok(package_names) => { + if package_names.is_empty() { + println!("There is no installed package"); + return; + } + for package_name in package_names { + update_package(&package_name).await; + } + } + Err(err_val) => eprintln!("Error: List Installed Packages | {}", err_val), + } +}