diff --git a/.gitignore b/.gitignore index c371942..5fa16cd 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,4 @@ /.vscode .env +/resources diff --git a/Cargo.lock b/Cargo.lock index dd7d37c..26fde4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -135,6 +135,7 @@ version = "1.0.83" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" dependencies = [ + "jobserver", "libc", ] @@ -346,6 +347,21 @@ version = "0.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +[[package]] +name = "git2" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf97ba92db08df386e10c8ede66a2a0369bd277090afd8710e19e38de9ec0cd" +dependencies = [ + "bitflags 2.4.1", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + [[package]] name = "h2" version = "0.3.22" @@ -459,6 +475,20 @@ dependencies = [ "want", ] +[[package]] +name = "hyper-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + [[package]] name = "hyper-tls" version = "0.5.0" @@ -527,12 +557,22 @@ version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" +[[package]] +name = "jobserver" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + [[package]] name = "jonas_jones-api" version = "0.3.0" dependencies = [ "chrono", "dotenv", + "git2", "lastfm", "log", "parking_lot", @@ -556,9 +596,9 @@ dependencies = [ [[package]] name = "lastfm" -version = "0.7.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b2b8e3a1ad7d64fae5e5542beccb5596402aafeb69c7259e3baa2dfdfa364e1" +checksum = "aed1b6ed29669ba37e7a2a8a939b7e2ff456883f0eb71a173635fae0ddc1cb5b" dependencies = [ "async-stream", "chrono", @@ -588,6 +628,46 @@ version = "0.2.150" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "89d92a4743f9a61002fae18374ed11e7973f530cb3a3255fb354818118b2203c" +[[package]] +name = "libgit2-sys" +version = "0.16.1+1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2a2bb3680b094add03bb3732ec520ece34da31a8cd2d633d1389d0f0fb60d0c" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libssh2-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037731f5d3aaa87a5675e895b63ddff1a87624bc29f77004ea829809654e48f6" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "linux-raw-sys" version = "0.4.12" @@ -940,6 +1020,7 @@ dependencies = [ "http", "http-body", "hyper", + "hyper-rustls", "hyper-tls", "ipnet", "js-sys", @@ -949,20 +1030,38 @@ dependencies = [ "once_cell", "percent-encoding", "pin-project-lite", + "rustls", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", "system-configuration", "tokio", "tokio-native-tls", + "tokio-rustls", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots", "winreg", ] +[[package]] +name = "ring" +version = "0.17.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom", + "libc", + "spin", + "untrusted", + "windows-sys 0.48.0", +] + [[package]] name = "rustc-demangle" version = "0.1.23" @@ -982,6 +1081,18 @@ dependencies = [ "windows-sys 0.52.0", ] +[[package]] +name = "rustls" +version = "0.21.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +dependencies = [ + "log", + "ring", + "rustls-webpki", + "sct", +] + [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -991,6 +1102,16 @@ dependencies = [ "base64", ] +[[package]] +name = "rustls-webpki" +version = "0.101.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "ryu" version = "1.0.15" @@ -1018,6 +1139,16 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring", + "untrusted", +] + [[package]] name = "security-framework" version = "2.9.2" @@ -1274,6 +1405,16 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-rustls" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" +dependencies = [ + "rustls", + "tokio", +] + [[package]] name = "tokio-stream" version = "0.1.14" @@ -1464,6 +1605,12 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "url" version = "2.5.0" @@ -1615,6 +1762,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.25.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 1321e14..6d174f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,10 +11,11 @@ parking_lot = "0.12.1" serde = { version = "1.0", features = ["derive"] } tokio = { version = "1.35", features = ["macros"] } dotenv = "0.15.0" -lastfm = "0.7.0" +lastfm = "0.8.1" log = "0.4.20" chrono = "0.4.31" toml = "0.8.8" reqwest = { version = "0.11.22", features = ["json"] } serde_json = "1.0.108" regex = "1" +git2 = "0.18.1" diff --git a/src/v1/mod.rs b/src/v1/mod.rs index cd12a16..49c86a4 100644 --- a/src/v1/mod.rs +++ b/src/v1/mod.rs @@ -2,17 +2,17 @@ mod builtin; mod debug; mod kcomebacks; mod projects; -mod updates; +mod update; pub use builtin::get_builtin_routes as get_v1_builtin_routes; pub use debug::get_debug_routes as get_v1_debug_routes; pub use kcomebacks::get_kcomebacks_routes as get_v1_kcomebacks_routes; pub use projects::get_project_routes as get_v1_project_routes; -pub use updates::get_updates_routes as get_v1_updates_routes; +pub use update::get_update_routes as get_v1_updates_routes; use warp::Filter; -pub fn get_v1_routes() -> impl warp::Filter + Clone { +pub fn get_v1_routes() -> impl warp::Filter + Clone { return get_v1_builtin_routes() .or(get_v1_debug_routes()) .or(get_v1_kcomebacks_routes()) diff --git a/src/v1/update/mod.rs b/src/v1/update/mod.rs new file mode 100644 index 0000000..68e97dc --- /dev/null +++ b/src/v1/update/mod.rs @@ -0,0 +1,248 @@ +use std::fs; +use std::io::BufRead; +use std::process::{Stdio, Command}; + +use serde::{Deserialize, Serialize}; +use serde_json::json; +use tokio::sync::mpsc; +use tokio::task; +use warp::Filter; +use crate::error_responses::InternalServerError; +use crate::Logger; + +// DiscographyQuery +#[derive(Debug, Deserialize, Serialize)] +pub struct DiscographyQuery { + artists: String, +} + +pub fn get_update_routes() -> impl warp::Filter + Clone { + warp::path("v1").and(warp::path("update")) + // update/kcomebacks + // update/projects + // update/makediscography?artists=artist1,artist2,artist3 + // update/synclikedsongs + .and((warp::path("kcomebacks").and_then(update_kcomebacks)) + .or(warp::path("projects").and_then(update_projects)) + .or(warp::path("makediscography").map(||"Not implemented yet")) + .or(warp::path("synclikedsongs").and_then(sync_liked_songs)) + ) +} + +async fn update_kcomebacks() -> Result { + // check if the local repository exists, if not, clone it + if !fs::metadata("./resources/turbo_octo_potato").is_ok() { + setup().unwrap(); + }; + + if let Err(err) = run_kcomebacks_command() { + // Handle the error here + eprintln!("Error: {}", err); + // Return an appropriate response or error + return Err(warp::reject::custom(InternalServerError)); + } + + Ok(warp::reply::json(&json!({"status": "updating..."}))) + +} + +async fn update_projects() -> Result { + // check if the local repository exists, if not, clone it + if !fs::metadata("./resources/turbo_octo_potato").is_ok() { + setup().unwrap(); + }; + + if let Err(err) = run_projects_command() { + // Handle the error here + eprintln!("Error: {}", err); + // Return an appropriate response or error + return Err(warp::reject::custom(InternalServerError)); + } + + Ok(warp::reply::json(&json!({"status": "updating..."}))) + +} + +async fn sync_liked_songs() -> Result { + // check if the local repository exists, if not, clone it + if !fs::metadata("./resources/turbo_octo_potato").is_ok() { + setup().unwrap(); + }; + + if let Err(err) = run_likedsongs_command() { + // Handle the error here + eprintln!("Error: {}", err); + // Return an appropriate response or error + return Err(warp::reject::custom(InternalServerError)); + } + + Ok(warp::reply::json(&json!({"status": "updating..."}))) + +} + +fn setup() -> Result<(), git2::Error> { + let repository_url = "https://github.com/JonasunderscoreJones/turbo-octo-potato.git"; + let local_directory = "resources/turbo_octo_potato"; + + git2::Repository::clone(repository_url, local_directory)?; + + Ok(()) +} + +// fn run_command() -> Result<(), std::io::Error> { +// let (tx, mut rx) = mpsc::channel(1); + +// task::spawn_blocking(move || { +// let mut child = Command::new("python3") +// .arg(&py_file) +// .arg(&args) +// .current_dir("resources/turbo_octo_potato") +// .stdout(Stdio::piped()) +// .spawn() +// .expect("failed to execute child"); + +// let stdout = child.stdout.as_mut().unwrap(); + +// let mut reader = std::io::BufReader::new(stdout); + +// let mut line = String::new(); + +// loop { +// let len = reader.read_line(&mut line).unwrap(); +// if len == 0 { +// break; +// } +// tx.blocking_send(line.clone()).unwrap(); +// line.clear(); +// } + +// child.wait().unwrap(); +// }); + +// task::spawn(async move { +// while let Some(line) = rx.recv().await { +// println!("{}", line); +// } +// }); + +// Ok(()) +// } + +// run_command with python file and args as parameters + + +fn run_kcomebacks_command() -> Result<(), std::io::Error> { + let (tx, mut rx) = mpsc::channel(1); + + task::spawn_blocking(move || { + let mut child = Command::new("python3") + .arg("rpopfetch.py") + .arg("--cdn") + .current_dir("resources/turbo_octo_potato") + .stdout(Stdio::piped()) + .spawn() + .expect("failed to execute child"); + + let stdout = child.stdout.as_mut().unwrap(); + + let mut reader = std::io::BufReader::new(stdout); + + let mut line = String::new(); + + loop { + let len = reader.read_line(&mut line).unwrap(); + if len == 0 { + break; + } + tx.blocking_send(line.clone()).unwrap(); + line.clear(); + } + + child.wait().unwrap(); + }); + + task::spawn(async move { + while let Some(line) = rx.recv().await { + Logger::info(&format!("[/v1/kcomebacks/update]: {}", line)); + } + }); + + Ok(()) +} + +fn run_projects_command() -> Result<(), std::io::Error> { + let (tx, mut rx) = mpsc::channel(1); + + task::spawn_blocking(move || { + let mut child = Command::new("python3") + .arg("update_projects.py") + .arg("--cdn") + .current_dir("resources/turbo_octo_potato") + .stdout(Stdio::piped()) + .spawn() + .expect("failed to execute child"); + + let stdout = child.stdout.as_mut().unwrap(); + + let mut reader = std::io::BufReader::new(stdout); + + let mut line = String::new(); + + loop { + let len = reader.read_line(&mut line).unwrap(); + if len == 0 { + break; + } + tx.blocking_send(line.clone()).unwrap(); + line.clear(); + } + + child.wait().unwrap(); + }); + + task::spawn(async move { + while let Some(line) = rx.recv().await { + Logger::info(&format!("[/v1/projects/update]: {}", line)); + } + }); + + Ok(()) +} + +fn run_likedsongs_command() -> Result<(), std::io::Error> { + let (tx, mut rx) = mpsc::channel(1); + + task::spawn_blocking(move || { + let mut child = Command::new("python3") + .arg("likedsongsync2.py") + .current_dir("resources/turbo_octo_potato") + .stdout(Stdio::piped()) + .spawn() + .expect("failed to execute child"); + + let stdout = child.stdout.as_mut().unwrap(); + + let mut reader = std::io::BufReader::new(stdout); + + let mut line = String::new(); + + loop { + let len = reader.read_line(&mut line).unwrap(); + if len == 0 { + break; + } + tx.blocking_send(line.clone()).unwrap(); + line.clear(); + } + + child.wait().unwrap(); + }); + + task::spawn(async move { + while let Some(line) = rx.recv().await { + Logger::info(&format!("[/v1/synclikedsongs]: {}", line)); + } + }); + + Ok(()) +} \ No newline at end of file