feat: ✨ user interactions -> read_package, read_all_packages, install_package, delete_package
This commit is contained in:
parent
2fab4c6099
commit
041f685031
6 changed files with 243 additions and 14 deletions
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,3 +2,4 @@ pub mod file;
|
|||
pub mod package;
|
||||
pub mod request;
|
||||
mod test;
|
||||
pub mod user;
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
use rust_package_manager_client::user::user_interaction;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() {
|
||||
println!("Hello, world!");
|
||||
user_interaction().await
|
||||
}
|
||||
|
|
|
@ -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
94
client/src/user.rs
Normal 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),
|
||||
}
|
||||
}
|
|
@ -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)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue