feat: ✨ list_installed_packages, update_package, update_all_packages for client
This commit is contained in:
parent
0f0e05ef91
commit
4ba4e6fe30
3 changed files with 107 additions and 18 deletions
|
@ -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() {
|
pub async fn calculate_hash(package_name: String) -> Result<Option<Vec<u8>>, std::io::Error> {
|
||||||
return None;
|
|
||||||
}
|
|
||||||
Some(packages)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue