feat: list_installed_packages, update_package, update_all_packages for client

This commit is contained in:
Ahmet Kaan GÜMÜŞ 2024-11-24 20:46:16 +03:00
parent 0f0e05ef91
commit 4ba4e6fe30
3 changed files with 107 additions and 18 deletions

View file

@ -1,11 +1,12 @@
use tokio::{ use tokio::{
fs::{read_dir, remove_file, DirBuilder, File, OpenOptions}, fs::{remove_file, DirBuilder, File, OpenOptions},
io::{AsyncReadExt, AsyncWriteExt}, io::{AsyncReadExt, AsyncWriteExt},
}; };
use sha3::{Digest, Sha3_512}; use sha3::{Digest, Sha3_512};
const PACKAGE_PATH: &str = "./packages/"; 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> { pub async fn save_package(package_name: String, package_data: &[u8]) -> Result<(), std::io::Error> {
let file_location = format!("{}{}", PACKAGE_PATH, package_name); 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 delete_metadata(package_name).await
} }
pub async fn list_packages() -> Option<Vec<String>> { pub async fn list_installed_packages() -> Result<Vec<String>, std::io::Error> {
let mut folder_elements = read_dir(PACKAGE_PATH).await.ok()?; let metadata_file_location = format!("{}{}", PACKAGE_PATH, METADATA_FILE_NAME);
let mut packages = vec![]; let mut metadata_file = match File::open(&metadata_file_location).await {
loop { Ok(metadata_file) => metadata_file,
match folder_elements.next_entry().await.ok()? { Err(_) => {
Some(file_entry) => packages.push(file_entry.file_name().into_string().ok()?), File::create_new(&metadata_file_location).await?;
None => break, 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());
} }
Ok(package_names)
if packages.is_empty() {
return None;
}
Some(packages)
} }
async fn calculate_hash(package_name: String) -> Result<Option<Vec<u8>>, std::io::Error> { pub async fn calculate_hash(package_name: String) -> Result<Option<Vec<u8>>, std::io::Error> {
if let Some(_) = search_metadata(package_name.to_owned()).await? { if let Some(_) = search_metadata(package_name.to_owned()).await? {
let file_location = format!("{}{}", PACKAGE_PATH, package_name); let file_location = format!("{}{}", PACKAGE_PATH, package_name);
let mut target_file = File::open(file_location).await?; let mut target_file = File::open(file_location).await?;
@ -53,7 +56,7 @@ async fn calculate_hash(package_name: String) -> Result<Option<Vec<u8>>, std::io
} }
async fn search_metadata(package_name: String) -> Result<Option<usize>, std::io::Error> { async fn search_metadata(package_name: String) -> Result<Option<usize>, 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 { let mut file = match File::open(file_location.clone()).await {
Ok(file) => file, Ok(file) => file,
Err(_) => { Err(_) => {
@ -75,7 +78,7 @@ async fn search_metadata(package_name: String) -> Result<Option<usize>, std::io:
async fn search_and_retrieve_metadata( async fn search_and_retrieve_metadata(
package_name: String, package_name: String,
) -> Result<(Option<usize>, Vec<String>), std::io::Error> { ) -> Result<(Option<usize>, Vec<String>), 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 { let mut file = match File::open(file_location.clone()).await {
Ok(file) => file, Ok(file) => file,
Err(_) => { Err(_) => {
@ -98,7 +101,7 @@ async fn search_and_retrieve_metadata(
async fn save_metadata(package_name: String) -> Result<(), std::io::Error> { async fn save_metadata(package_name: String) -> Result<(), std::io::Error> {
let searched = search_metadata(package_name.to_owned()).await?; let searched = search_metadata(package_name.to_owned()).await?;
if searched.is_none() { 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() let mut file = OpenOptions::new()
.append(true) .append(true)
.create(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()), 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() let mut file = OpenOptions::new()
.append(false) .append(false)
.create(false) .create(false)

View file

@ -18,6 +18,9 @@ impl Package {
pub fn get_name(&self) -> String { pub fn get_name(&self) -> String {
self.name.clone() self.name.clone()
} }
pub fn get_hash(&self) -> Vec<u8> {
self.hash.to_vec()
}
} }
impl Default for Package { impl Default for Package {

View file

@ -1,5 +1,7 @@
use std::env; use std::env;
use crate::file::calculate_hash;
fn env_collector() -> Vec<String> { fn env_collector() -> Vec<String> {
let mut env_values = env::args().collect::<Vec<String>>(); let mut env_values = env::args().collect::<Vec<String>>();
env_values.remove(0); env_values.remove(0);
@ -47,6 +49,25 @@ pub async fn user_interaction() {
delete_package(package_name).await; delete_package(package_name).await;
return; 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"); eprintln!("Need an Argument");
return; return;
@ -92,3 +113,65 @@ async fn delete_package(package_name: &String) {
Err(err_val) => eprintln!("Error: Delete Package | {}", err_val), 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),
}
}