feat: user interactions -> read_package, read_all_packages, install_package, delete_package

This commit is contained in:
Ahmet Kaan GÜMÜŞ 2024-11-22 22:31:19 +03:00
parent 2fab4c6099
commit 041f685031
6 changed files with 243 additions and 14 deletions

View file

@ -1,22 +1,27 @@
use tokio::{
fs::{read_dir, remove_file, File},
io::AsyncWriteExt,
fs::{read_dir, remove_file, DirBuilder, File, OpenOptions},
io::{AsyncReadExt, AsyncWriteExt},
};
const FILE_LOCATION: &str = "./packages/";
const PACKAGE_PATH: &str = "./packages/";
pub async fn save_package(package_name: String, package_data: &[u8]) -> Result<(), std::io::Error> {
let file_location = format!("{}{}", FILE_LOCATION, package_name);
let file_location = format!("{}{}", PACKAGE_PATH, package_name);
if let Err(_) = File::open(PACKAGE_PATH).await {
DirBuilder::new().create(PACKAGE_PATH).await?;
}
let mut package_file = File::create(file_location).await?;
package_file.write_all(package_data).await
package_file.write_all(package_data).await?;
save_metadata(package_name).await
}
pub async fn delete_package(package_name: String) -> Result<(), std::io::Error> {
remove_file(format!("{}{}", FILE_LOCATION, package_name)).await
remove_file(format!("{}{}", PACKAGE_PATH, package_name)).await?;
delete_metadata(package_name).await
}
pub async fn list_packages() -> Option<Vec<String>> {
let mut folder_elements = read_dir(FILE_LOCATION).await.ok()?;
let mut folder_elements = read_dir(PACKAGE_PATH).await.ok()?;
let mut packages = vec![];
loop {
match folder_elements.next_entry().await.ok()? {
@ -30,3 +35,85 @@ pub async fn list_packages() -> Option<Vec<String>> {
}
Some(packages)
}
async fn search_metadata(package_name: String) -> Result<Option<usize>, std::io::Error> {
let file_location = format!("{}{}", PACKAGE_PATH, "metadata.txt");
let mut file = match File::open(file_location.clone()).await {
Ok(file) => file,
Err(_) => {
return Ok(None);
}
};
let mut file_data = String::default();
_ = file.read_to_string(&mut file_data).await?;
for (index, line) in file_data.lines().enumerate() {
let line = line.trim_end();
if line == package_name {
return Ok(Some(index));
}
}
Ok(None)
}
async fn search_and_retrieve_metadata(
package_name: String,
) -> Result<(Option<usize>, Vec<String>), std::io::Error> {
let file_location = format!("{}{}", PACKAGE_PATH, "metadata.txt");
let mut file = match File::open(file_location.clone()).await {
Ok(file) => file,
Err(_) => {
return Ok((None, vec![]));
}
};
let mut file_data = String::default();
_ = file.read_to_string(&mut file_data).await?;
let mut lines = vec![];
let mut target_index = None;
for (index, line) in file_data.lines().enumerate() {
if line.trim_end() == package_name {
target_index = Some(index);
}
lines.push(line.to_string());
}
Ok((target_index, lines))
}
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 mut file = OpenOptions::new()
.append(true)
.create(true)
.write(true)
.open(file_location)
.await?;
file.write_all(package_name.as_bytes()).await?;
file.write_all(b"\n").await?;
}
Ok(())
}
async fn delete_metadata(package_name: String) -> Result<(), std::io::Error> {
let (target_index, mut file_data) = search_and_retrieve_metadata(package_name).await?;
let target_index = match target_index {
Some(target_index) => target_index,
None => return Err(std::io::ErrorKind::NotFound.into()),
};
let file_location = format!("{}{}", PACKAGE_PATH, "metadata.txt");
let mut file = OpenOptions::new()
.append(false)
.create(false)
.write(true)
.open(file_location)
.await?;
file_data.remove(target_index);
if file_data.is_empty() {
file.set_len(0).await
} else {
file.write_all(&file_data.concat().as_bytes()).await
}
}

View file

@ -2,3 +2,4 @@ pub mod file;
pub mod package;
pub mod request;
mod test;
pub mod user;

View file

@ -1,4 +1,7 @@
use rust_package_manager_client::user::user_interaction;
#[tokio::main]
async fn main() {
println!("Hello, world!");
user_interaction().await
}

View file

@ -40,6 +40,7 @@ async fn test_save_package() {
use crate::file::save_package;
let saved_or_not = save_package("test_package".to_string(), &package_data.unwrap()[..]).await;
println!("{:#?}", saved_or_not);
assert_eq!(saved_or_not.is_ok(), true);
}
@ -54,10 +55,12 @@ async fn test_delete_package() {
use crate::file::save_package;
let saved_or_not = save_package("test_package".to_string(), &package_data.unwrap()[..]).await;
println!("{:#?}", saved_or_not);
assert_eq!(saved_or_not.is_ok(), true);
use crate::file::delete_package;
let deleted_or_not = delete_package("test_package".to_string()).await;
println!("{:#?}", deleted_or_not);
assert_eq!(deleted_or_not.is_ok(), true);
}

94
client/src/user.rs Normal file
View file

@ -0,0 +1,94 @@
use std::env;
fn env_collector() -> Vec<String> {
let mut env_values = env::args().collect::<Vec<String>>();
env_values.remove(0);
env_values
}
pub async fn user_interaction() {
let env_values = env_collector();
for (i, env_value) in env_values.iter().enumerate() {
match env_value.as_str() {
"read_all_packages" => {
read_all_packages().await;
return;
}
"read_package" => {
let package_name = match env_values.get(i + 1) {
Some(package_name) => package_name,
None => {
eprintln!("Length is not enough");
return;
}
};
read_package(package_name).await;
return;
}
"install_package" => {
let package_name = match env_values.get(i + 1) {
Some(package_name) => package_name,
None => {
eprintln!("Length is not enough");
return;
}
};
install_package(package_name).await;
return;
}
"delete_package" => {
let package_name = match env_values.get(i + 1) {
Some(package_name) => package_name,
None => {
eprintln!("Length is not enough");
return;
}
};
delete_package(package_name).await;
return;
}
_ => {
eprintln!("Need an Argument");
return;
}
}
}
}
async fn read_all_packages() {
let packages = crate::request::read_all_packages().await;
match packages {
Ok(packages) => {
for package in packages {
println!("{}", package.get_name());
}
}
Err(err_val) => eprintln!("Error: Read All Packages | {}", err_val),
}
}
async fn read_package(package_name: &String) {
match crate::request::read_package(package_name.to_owned()).await {
Some(package) => println!("{:#?}", package),
None => eprintln!("Error: Package Name is Invalid"),
}
}
async fn install_package(package_name: &String) {
match crate::request::download_package(package_name.to_owned()).await {
Some(package_data) => {
match crate::file::save_package(package_name.to_owned(), &package_data).await {
Ok(_) => println!("{} is Installed", package_name),
Err(err_val) => eprintln!("Error: Save Package | {}", err_val),
}
}
None => eprintln!("Error: Download Package"),
}
}
async fn delete_package(package_name: &String) {
match crate::file::delete_package(package_name.to_owned()).await {
Ok(_) => println!("{} is Deleted", package_name),
Err(err_val) => eprintln!("Error: Delete Package | {}", err_val),
}
}

View file

@ -1,5 +1,8 @@
use axum::extract::Multipart;
use tokio::{fs::File, io::AsyncWriteExt};
use tokio::{
fs::{DirBuilder, File},
io::AsyncWriteExt,
};
use tokio_util::io::ReaderStream;
use crate::{database, routing, PACKAGE_PATH};
@ -62,24 +65,62 @@ pub async fn delete_package(package_name: String) -> Option<Package> {
pub async fn download_package(package_name: String) -> Option<ReaderStream<File>> {
let package = crate::package::utils::read_package(package_name).await?;
let package_file_stream = package.serve().await.ok()?;
let package_file_stream = match package.serve().await {
Ok(package_file_stream) => package_file_stream,
Err(err_val) => {
eprintln!("Error: Download | File Stream | {}", err_val);
return None;
}
};
Some(package_file_stream)
}
pub async fn upload_package(mut package_file: Multipart) -> Option<Package> {
let package_file_part = package_file.next_field().await.ok()??;
let package_file_part = match package_file.next_field().await {
Ok(field_unchecked) => field_unchecked?,
Err(err_val) => {
eprintln!("Error: Upload | Multipart | {}", err_val);
return None;
}
};
let package_file_name = package_file_part.name()?.to_string();
let file_location = format!("{}/{}", PACKAGE_PATH, package_file_name);
if let Err(_) = File::open(PACKAGE_PATH).await {
if let Err(err_val) = DirBuilder::new().create(PACKAGE_PATH).await {
eprintln!("Error: Upload | Create Directory | {}", err_val);
return None;
}
}
let package_file_data = package_file_part.bytes().await.ok()?;
let package_file_data = match package_file_part.bytes().await {
Ok(package_file_data) => package_file_data,
Err(err_val) => {
eprintln!("Error: Upload | Multipart Bytes | {}", err_val);
return None;
}
};
let mut package = crate::package::utils::read_package(package_file_name).await?;
let mut file_descriptor = File::create(&file_location).await.ok()?;
file_descriptor.write_all(&package_file_data).await.ok()?;
let mut file_descriptor = match File::create(&file_location).await {
Ok(file_descriptor) => file_descriptor,
Err(err_val) => {
eprintln!(
"Error: Upload | File Descriptor | {} |{}",
file_location, err_val
);
return None;
}
};
if let Err(err_val) = file_descriptor.write_all(&package_file_data).await {
eprintln!("Error: Upload | File Descriptor Write | {}", err_val);
return None;
}
package.set_location(&file_location.to_string());
package.set_hash().await.ok()?;
if let Err(err_val) = package.set_hash().await {
eprintln!("Error: Hash | {}", err_val);
}
let package = crate::package::utils::update_package(package.get_name(), package).await?;
Some(package)