From 188a81beca7d105fc997c749be47884e93da19e6 Mon Sep 17 00:00:00 2001 From: kdeng00 Date: Tue, 11 Jun 2024 20:09:16 -0400 Subject: [PATCH] Delete functionality is operational --- Cargo.toml | 2 +- README.md | 63 ++++++++++---------------------- src/constants/file_extensions.rs | 2 +- src/main.rs | 7 ---- src/managers/action_managers.rs | 4 +- src/managers/commit_manager.rs | 45 +++++++++++++---------- src/managers/token_manager.rs | 11 ++---- src/managers/user_manager.rs | 2 +- src/models/song.rs | 7 ++-- src/models/user.rs | 2 +- src/parsers/api_parser.rs | 6 +-- src/syncers/delete.rs | 29 ++++++++++----- src/syncers/download.rs | 2 +- src/syncers/mod.rs | 1 - src/syncers/retrieve_records.rs | 2 - src/syncers/syncer_base.rs | 28 -------------- src/syncers/upload.rs | 7 ++-- src/utilities/checks.rs | 17 ++++----- src/utilities/conversions.rs | 6 +-- 19 files changed, 93 insertions(+), 150 deletions(-) delete mode 100644 src/syncers/syncer_base.rs diff --git a/Cargo.toml b/Cargo.toml index 4c91136..4f4458b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,8 +10,8 @@ edition = "2021" [dependencies] futures = { version = "0.3.30" } -reqwest = { version = "0.12.4", features = ["json", "blocking", "multipart", "stream"] } http = { version = "1.1.0" } +reqwest = { version = "0.12.4", features = ["json", "blocking", "multipart", "stream"] } serde = { version = "1.0.197", features = ["derive"] } serde_json = "1.0.115" tokio = { version = "1.37", features = ["full"] } diff --git a/README.md b/README.md index 6eb57d6..212eb62 100644 --- a/README.md +++ b/README.md @@ -1,86 +1,67 @@ # IcarusDownloadManager -IcarusDownloadManager is a Linux CLI software client application that has the feature of uploading and downloading songs from the [Icarus](https://github.com/kdeng00/Icarus) Music Server. +IcarusDownloadManager is a CLI software client application that has the feature of uploading and downloading songs from the [Icarus](https://github.com/kdeng00/Icarus) Music Server. ## Built With -* C++ with C++20 features -* CMake -* GCC >= 10 or Visual Studio >= 17 [2022] -* [vcpkg](https://github.com/microsoft/vcpkg) -* [json](https://github.com/nlohmann/json) -* [openssl](https://github.com/openssl/openssl) -* [curl](https://github.com/curl/curl) -* [cpr](https://github.com/libcpr/cpr) +* Rust +* Cargo +* futures +* http +* reqwst +* serde +* serde_json +* tokio +* tokio-util ### Getting Started Clone the repo -``` +```BASH git clone --recursive https://github.com/kdeng00/IcarusDownloadManager ``` -Install packages - -``` -vcpkg install nlohman-json -vcpkg install openssl -vcpkg install curl -vcpkg install cpr -``` - Build the project: -``` +```BASH cd IcarusDownloadManager -mkdir build -cd build - -cmake .. -cmake --build . --config release -j +cargo build ``` -The program has been built and can be executed by the binary file *icd*. For information on how to use icd, merely execute the program without any command line arguments. +The program has been built and can be executed by the binary file *icarus-dm*. For information on how to use icarua-dm, merely execute the program without any command line arguments. ### Downloading Song ```BASH -icd download -u spacecadet -p stellar40 -h https://icarus.com -b 15 -``` - -### Uploading Song - -```BASH -icd upload -u spacecadet -p stellar40 -h https://icarus.com -s /path/of/song.mp3 +icarus-dm download -u spacecadet -p stellar40 -h https://icarus.com -b 15 ``` ### Uploading Song with metadata ```BASH -icd upload-meta -u spacecadet -p stellar40 -h https://icarus.com -s /path/of/song.mp3 -t 1 -m /path/to/metadata/config/collection.json -ca /path/to/cover/art/image.png +icarus-dm upload-meta -u spacecadet -p stellar40 -h https://icarus.com -s /path/of/song.mp3 -t 1 -m /path/to/metadata/config/collection.json -ca /path/to/cover/art/image.png ``` ### Uploading Song with metadata from directory ```BASH -icd upload-meta -u spacecadet -p stellar40 -h https://icarus.com -smca /path/where/songs/and/metadata/exists/ +icarus-dm upload-meta -u spacecadet -p stellar40 -h https://icarus.com -smca /path/where/songs/and/metadata/exists/ ``` - ### Retrieving Song in json ```Bash -icd retrieve -u spacecadet -p stellar40 -h https://icarus.com -rt songs +icarus-dm retrieve -u spacecadet -p stellar40 -h https://icarus.com -rt songs ``` ### Deleting Song ```BASH -icd delete -u spacecadet -p stellar40 -h https://icarus.com -D 15 +icarus-dm delete -u spacecadet -p stellar40 -h https://icarus.com -D 15 ``` @@ -97,12 +78,6 @@ Please read [CONTRIBUTING.md](CONTRIBUTING.md) for details on the code of conduc [v0.1.1](https://github.com/kdeng00/IcarusDownloadManager/releases/tag/v0.1.1) [v0.1.0](https://github.com/kdeng00/IcarusDownloadManager/releases/tag/0.1.0) -## Authors - -* **Kun Deng** - [kdeng00](https://github.com/kdeng00) - -See also the list of [contributors](https://github.com/kdeng00/Icarus/graphs/contributors) who participated in this project. - ## License This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details diff --git a/src/constants/file_extensions.rs b/src/constants/file_extensions.rs index e490697..edf058e 100644 --- a/src/constants/file_extensions.rs +++ b/src/constants/file_extensions.rs @@ -1,3 +1,3 @@ pub const WAV_FILE_EXTENSION: &str = ".wav"; -pub const MP3_FILE_EXTENSION: &str = ".mp3"; +pub const _MP3_FILE_EXTENSION: &str = ".mp3"; pub const JPG_FILE_EXTENSION: &str = ".jpg"; diff --git a/src/main.rs b/src/main.rs index abcd279..1b90844 100644 --- a/src/main.rs +++ b/src/main.rs @@ -18,7 +18,6 @@ fn print_help() { Actions download - upload (Search NOTE) upload-meta retrieve delete @@ -29,12 +28,6 @@ fn print_help() { -p password -h host - Required for upload - -s path of song - -sd directory where to search for songs to upload (Optional) - -sr directory where to recursively search for songs to upload (Optional) - -nc will not prompt the user when uploading from a directory - Required for upload with metadata -s path of song -t track number diff --git a/src/managers/action_managers.rs b/src/managers/action_managers.rs index 6c7bb51..68d52b4 100644 --- a/src/managers/action_managers.rs +++ b/src/managers/action_managers.rs @@ -124,7 +124,7 @@ impl ActionManager { } } - fn print_action(&self) { + fn _print_action(&self) { if self.action.len() == 0 { println!("Action is empty"); } else { @@ -132,7 +132,7 @@ impl ActionManager { } } - fn print_flags(&self) { + fn _print_flags(&self) { println!("Printing flags..."); for flag in &self.flags { println!("Flag {}", flag.flag); diff --git a/src/managers/commit_manager.rs b/src/managers/commit_manager.rs index d280713..400f0a3 100644 --- a/src/managers/commit_manager.rs +++ b/src/managers/commit_manager.rs @@ -1,21 +1,18 @@ use std::collections::HashMap; use std::default::Default; -use std::fmt::Display; -use std::fs::{read_dir, DirEntry}; -use std::io::{Error, Read, Result, Write}; -use std::path::Path; +use std::fs::read_dir; +use std::io::{Result, Write}; use std::str::FromStr; -use futures::{FutureExt, TryFutureExt}; use serde::{Deserialize, Serialize}; use tokio::runtime::Runtime; +use crate::managers; use crate::models::song::Album; -use crate::models::{self, song}; +use crate::models::{self}; use crate::syncers; use crate::utilities; use crate::{constants, parsers}; -use crate::{exit_program, managers}; #[derive(Debug, Deserialize, Serialize)] pub struct CommitManager { @@ -32,7 +29,7 @@ enum ActionValues { None, } -enum RetrieveTypes { +enum _RetrieveTypes { Songs, } @@ -45,7 +42,7 @@ enum En { } impl Album { - pub fn print_info(&self) { + pub fn _print_info(&self) { println!("Album: {}", self.title); println!("Album Artist: {}", self.album_artist); println!("Genre: {}", self.genre); @@ -126,7 +123,6 @@ impl CommitManager { return actions; } - // TODO: Implement fn delete_song(&self) { let mut prsr = parsers::api_parser::APIParser { ica_act: self.ica_action.clone(), @@ -150,11 +146,20 @@ impl CommitManager { } } - let del = syncers::delete::Delete { api: api }; + let mut del = syncers::delete::Delete { api: api.clone() }; println!("Deleting song.."); - del.delete_song(&token, &song); + let res_fut = del.delete_song(&token, &song); + let result = Runtime::new().unwrap().block_on(res_fut); + match result { + Ok(o) => { + println!("Song (Id {:?}) has been successfully deleted", o.id); + } + Err(er) => { + println!("Error {:?}", er); + } + } } fn download_song(&self) { @@ -213,8 +218,8 @@ impl CommitManager { let result = Runtime::new().unwrap().block_on(result_fut); match result { Ok(o) => { - for song in o { - println!("{:?} - {:?}", song.artist, song.title); + for son in o { + son.print_info(); } } Err(er) => { @@ -280,9 +285,9 @@ impl CommitManager { println!("metadata path: {}", metadata_path); println!("cover art path: {}", coverpath); - self.sing_target_upload(&songpath, &track_id, &metadata_path, &coverpath); + let _ = self.sing_target_upload(&songpath, &track_id, &metadata_path, &coverpath); } else if multitarget { - self.multi_target_upload(&uni); + let _ = self.multi_target_upload(&uni); } else { println!("Single or Multi target has not been chosen"); } @@ -681,8 +686,8 @@ impl CommitManager { song.track = Some(track); } - fn parse_disc_and_track(&self, song: &mut models::song::Song, track_id: &String) { - let sep = |a: &char, b: &char| -> bool { + fn _parse_disc_and_track(&self, song: &mut models::song::Song, track_id: &String) { + let sep = |_a: &char, _b: &char| -> bool { return false; }; @@ -690,7 +695,7 @@ impl CommitManager { if index == -1 { let mut d_str: String = String::new(); - let mut t_str = String::new(); + let t_str = String::new(); for c in track_id.chars().skip(0).take(index as usize) { d_str.push(c); @@ -712,7 +717,7 @@ impl CommitManager { } } - fn check_for_no_confirm(&self) -> bool { + fn _check_for_no_confirm(&self) -> bool { for flag in self.ica_action.flags.iter() { if flag.flag == "-nc" { return true; diff --git a/src/managers/token_manager.rs b/src/managers/token_manager.rs index b256f3b..48689c8 100644 --- a/src/managers/token_manager.rs +++ b/src/managers/token_manager.rs @@ -24,9 +24,7 @@ impl TokenManager { pub async fn request_token(&self) -> Result { println!("Sending request for a token"); - // let endpoint = self.construct_endpoint(); - let mut url = self.retrieve_url(); - // url += &endpoint; + let url = self.retrieve_url(); println!("URL: {}", url); @@ -59,7 +57,7 @@ impl TokenManager { } pub fn init(&mut self) { - let mut api = &mut self.api; + let api = &mut self.api; api.version = String::from("v1"); api.endpoint = String::from(format!("api/{}/login", api.version)); } @@ -67,9 +65,6 @@ impl TokenManager { pub fn retrieve_url(&self) -> String { let api = &self.api; let mut url = String::from(&api.url); - // url += &String::from("api/"); - // url += &String::from(&api.version); - // url += &String::from("/"); url += &String::from(&api.endpoint); url += &String::from("/"); @@ -77,7 +72,7 @@ impl TokenManager { } // NOTE: This can get deleted. Redundant - fn construct_endpoint(&self) -> String { + fn _construct_endpoint(&self) -> String { let mut endpoint: String = String::from("api/"); endpoint += &self.api.version; endpoint += "/login"; diff --git a/src/managers/user_manager.rs b/src/managers/user_manager.rs index 44ff366..61607e2 100644 --- a/src/managers/user_manager.rs +++ b/src/managers/user_manager.rs @@ -2,7 +2,7 @@ use std::default::Default; use serde::{Deserialize, Serialize}; -use crate::models::{self, user::User}; +use crate::models::{self}; #[derive(Debug, Deserialize, Serialize)] pub struct UserManager { diff --git a/src/models/song.rs b/src/models/song.rs index 2a897f7..068010a 100644 --- a/src/models/song.rs +++ b/src/models/song.rs @@ -9,6 +9,7 @@ use crate::constants; #[derive(Clone, Debug, Deserialize, Serialize)] pub struct Song { + #[serde(alias = "song_id")] pub id: Option, pub title: Option, pub artist: Option, @@ -111,7 +112,7 @@ impl Song { } // if 1 - wav, if 0 - mp3, anything else defaults to wav - pub fn generate_filename_from_track(&mut self, i_type: i32) -> i32 { + pub fn _generate_filename_from_track(&mut self, i_type: i32) -> i32 { let mut filename: String = String::new(); if self.track.unwrap() < 10 { filename += "0"; @@ -120,7 +121,7 @@ impl Song { filename += &self.track.unwrap().to_string(); if i_type == 0 { - filename += constants::file_extensions::MP3_FILE_EXTENSION; + filename += constants::file_extensions::_MP3_FILE_EXTENSION; } else { filename += constants::file_extensions::WAV_FILE_EXTENSION; } @@ -130,7 +131,7 @@ impl Song { return 0; } - pub fn to_metadata_json(&self) -> Result { + pub fn _to_metadata_json(&self) -> Result { return serde_json::to_string_pretty(&self); } } diff --git a/src/models/user.rs b/src/models/user.rs index d788787..46a37c0 100644 --- a/src/models/user.rs +++ b/src/models/user.rs @@ -18,7 +18,7 @@ impl Default for User { } impl User { - pub fn to_json(&self) -> Result { + pub fn _to_json(&self) -> Result { return serde_json::to_string_pretty(&self); } } diff --git a/src/parsers/api_parser.rs b/src/parsers/api_parser.rs index 790c3b7..7a8396f 100644 --- a/src/parsers/api_parser.rs +++ b/src/parsers/api_parser.rs @@ -15,22 +15,18 @@ impl APIParser { let flags = self.ica_act.flags.clone(); println!("Parsing api"); - let mut i = 0; - // for (i, elem) in flags { for elem in flags { let arg = elem.flag; let value = elem.value; if arg == "-h" { - if value.chars().nth((value.len() - 1)) == Some('/') { + if value.chars().nth(value.len() - 1) == Some('/') { self.api.url = value; } else { self.api.url = value + "/"; } break; } - - i += 1; } self.api.version = "v1".to_string(); diff --git a/src/syncers/delete.rs b/src/syncers/delete.rs index 9f1df55..8ae73f2 100644 --- a/src/syncers/delete.rs +++ b/src/syncers/delete.rs @@ -1,16 +1,9 @@ use std::default::Default; -use std::io::Error; use reqwest; -use reqwest::Response; -use serde; -// use serde::Deserialize; -// use serde::Serialize; use crate::models; -use super::syncer_base; - #[derive(Clone, Debug)] pub struct Delete { pub api: models::api::API, @@ -25,9 +18,14 @@ impl Default for Delete { } impl Delete { - pub async fn delete_song(&self, token: &models::token::Token, song: &models::song::Song) { + pub async fn delete_song( + &mut self, + token: &models::token::Token, + song: &models::song::Song, + ) -> Result { + self.api.endpoint = "song/data/delete".to_owned(); let url = self.retrieve_url(&song); - let client = reqwest::Client::new(); + let client = reqwest::Client::builder().build().unwrap(); let access_token = token.bearer_token(); let response = client .delete(&url) @@ -35,15 +33,28 @@ impl Delete { .send() .await .unwrap(); + let mut sng = models::song::Song::default(); match response.status() { reqwest::StatusCode::OK => { println!("Success!"); + let s = response.json::().await; + match s { + // + Ok(parsed) => { + sng = parsed; + } + Err(er) => { + println!("Error {:?}", er); + } + }; } other => { panic!("Issue occurred: {:?}", other); } } + + return Ok(sng); } fn retrieve_url(&self, song: &models::song::Song) -> String { diff --git a/src/syncers/download.rs b/src/syncers/download.rs index 4282e0a..39f0c12 100644 --- a/src/syncers/download.rs +++ b/src/syncers/download.rs @@ -16,7 +16,7 @@ impl Default for Download { #[derive(Debug)] pub enum MyError { - Request(reqwest::Error), + _Request(reqwest::Error), Other(String), } diff --git a/src/syncers/mod.rs b/src/syncers/mod.rs index 29f57f6..cb8e326 100644 --- a/src/syncers/mod.rs +++ b/src/syncers/mod.rs @@ -1,5 +1,4 @@ pub mod delete; pub mod download; pub mod retrieve_records; -pub mod syncer_base; pub mod upload; diff --git a/src/syncers/retrieve_records.rs b/src/syncers/retrieve_records.rs index 7fb3162..b312cb4 100644 --- a/src/syncers/retrieve_records.rs +++ b/src/syncers/retrieve_records.rs @@ -3,8 +3,6 @@ use std::io::Error; use crate::models; -// use super::syncer_base::Result; - pub struct RetrieveRecords { pub api: models::api::API, } diff --git a/src/syncers/syncer_base.rs b/src/syncers/syncer_base.rs deleted file mode 100644 index 6f8144f..0000000 --- a/src/syncers/syncer_base.rs +++ /dev/null @@ -1,28 +0,0 @@ -// use crate::models; - -pub struct Syncer { - // pub api: models::api::API, - ok: i32, - unauthorized: i32, - not_found: i32, -} - -impl Syncer { - pub fn ok() -> i32 { - return 200; - } - - pub fn unauthorized() -> i32 { - return 401; - } - - pub fn not_found() -> i32 { - return 404; - } -} - -pub enum Result { - OK, - UNAUTHORIZED, - NOTFOUND, -} diff --git a/src/syncers/upload.rs b/src/syncers/upload.rs index 84c5d0d..8c9a240 100644 --- a/src/syncers/upload.rs +++ b/src/syncers/upload.rs @@ -5,7 +5,6 @@ use http::HeaderValue; use reqwest; use reqwest::multipart::Form; use serde::{Deserialize, Serialize}; -use tokio::fs::File; use crate::constants; use crate::models; @@ -112,7 +111,7 @@ impl Upload { return Ok(response_text); } - fn initialize_form( + fn _initialize_form( &self, song_raw_data: Vec, cover_raw_data: Vec, @@ -124,14 +123,14 @@ impl Upload { http::HeaderValue::from_static("application/octet-stream"), ); - let mut file = reqwest::multipart::Part::bytes(song_raw_data).headers(headers); + let file = reqwest::multipart::Part::bytes(song_raw_data).headers(headers); let mut headers_i = HeaderMap::new(); headers_i.insert( http::header::CONTENT_TYPE, http::HeaderValue::from_static("image/jpeg"), ); - let mut cover = reqwest::multipart::Part::bytes(cover_raw_data).headers(headers_i); + let cover = reqwest::multipart::Part::bytes(cover_raw_data).headers(headers_i); let mut song_filename = String::from("audio"); song_filename += constants::file_extensions::WAV_FILE_EXTENSION; diff --git a/src/utilities/checks.rs b/src/utilities/checks.rs index 42bd519..48f97c4 100644 --- a/src/utilities/checks.rs +++ b/src/utilities/checks.rs @@ -9,24 +9,23 @@ impl Checks { } // TODO: Implement - pub fn item_in_container( - container: &Vec, - item: &String, - func: fn(a: &String, b: &String) -> String, + pub fn _item_in_container( + _container: &Vec, + _item: &String, + _func: fn(a: &String, b: &String) -> String, ) -> String { return String::from(""); } // TODO: Implement - pub fn item_iter_in_container( - container: &Vec, - item: &String, - func: fn(a: &String, b: &String) -> String, + pub fn _item_iter_in_container( + _container: &Vec, + _item: &String, + _func: fn(a: &String, b: &String) -> String, ) -> String { return String::from(""); } - // TODO: Implement pub fn index_of_item_in_container(container: &String, item: &char, func: F) -> i32 where F: Fn(&char, &char) -> bool, diff --git a/src/utilities/conversions.rs b/src/utilities/conversions.rs index 53493d1..d404723 100644 --- a/src/utilities/conversions.rs +++ b/src/utilities/conversions.rs @@ -4,15 +4,15 @@ use serde::{Deserialize, Serialize}; pub struct Conversions {} impl Conversions { - pub fn to_lower_char(val: &mut char) { + pub fn _to_lower_char(val: &mut char) { if val.is_alphabetic() { *val = val.to_lowercase().next().unwrap(); } } - pub fn initialize_values(&self) {} + pub fn _initialize_values(&self) {} - pub fn print_value(&self, val: T) { + pub fn _print_value(&self, val: T) { println!("Going to print value"); println!("{:?}", val); }