From 5d50f446a1a4612c0c931bdbc61f945760392f29 Mon Sep 17 00:00:00 2001 From: fxqnlr Date: Fri, 4 Nov 2022 23:41:21 +0100 Subject: "finished" update, added some tests --- src/commands/modification.rs | 11 +--- src/commands/update.rs | 140 ++++++++++++++++++++++++++++++++++++------- 2 files changed, 120 insertions(+), 31 deletions(-) (limited to 'src/commands') diff --git a/src/commands/modification.rs b/src/commands/modification.rs index 43e2180..b90c82c 100644 --- a/src/commands/modification.rs +++ b/src/commands/modification.rs @@ -1,6 +1,6 @@ use std::io::{Error, ErrorKind}; -use crate::{modrinth::{project, versions, Version}, config::Cfg, db::{insert_mod, remove_mod_from_list, get_mod_id, insert_mod_in_list, get_mods, get_mods_from_list}, input::Input, get_current_list}; +use crate::{modrinth::{project, versions, extract_current_version}, config::Cfg, db::{insert_mod, remove_mod_from_list, get_mod_id, insert_mod_in_list, get_mods, get_mods_from_list}, input::Input, get_current_list}; pub async fn modification(config: Cfg, args: Option>) -> Result<(), Box> { @@ -77,12 +77,3 @@ fn remove(config: Cfg, args: Vec) -> Result<(), Box Ok(()), } } - -fn extract_current_version(versions: Vec) -> Result> { - match versions.len() { - 0 => Err(Box::new(Error::new(ErrorKind::NotFound, "NO_VERSIONS_AVAILABLE"))), - //TODO compare publish dates - 1.. => Ok(versions[0].id.to_string()), - _ => panic!("available_versions should never be negative"), - } -} diff --git a/src/commands/update.rs b/src/commands/update.rs index 14c37ec..6275bce 100644 --- a/src/commands/update.rs +++ b/src/commands/update.rs @@ -1,40 +1,138 @@ -use std::io::{Error, ErrorKind}; +use std::{io::{Error, ErrorKind, Write}, fs::File}; -use crate::{config::Cfg, modrinth::projects, get_current_list, db::{get_mods_from_list, get_versions}}; +use reqwest::Client; + +use futures_util::StreamExt; + +use crate::{config::Cfg, modrinth::{projects, Project, versions, extract_current_version, Version}, get_current_list, db::{get_mods_from_list, get_versions, get_list_version, change_list_versions}, List}; pub async fn update(config: Cfg) -> Result<(), Box> { let current_list = get_current_list(config.clone())?; - let mods = get_mods_from_list(config.clone(), current_list)?; + let mods = get_mods_from_list(config.clone(), current_list.clone())?; + + let mut versions = get_versions(config.clone(), mods.clone())?; + versions.sort_by_key(|ver| ver.mod_id.clone()); - let mut projects = projects(String::from(&config.apis.modrinth), mods.clone()).await; + let mut projects = projects(String::from(&config.apis.modrinth), mods).await; + projects.sort_by_key(|pro| pro.id.clone()); - let mut versions = get_versions(config, mods)?; + let mut updatestack: Vec = vec![]; + for (index, project) in projects.into_iter().enumerate() { + let current_version = &versions[index]; + + let p_id = String::from(&project.id); + let v_id = ¤t_version.mod_id; + + if &p_id != v_id { return Err(Box::new(Error::new(ErrorKind::Other, "SORTING_ERROR"))) }; + + if project.versions.join("|") != current_version.versions { + updatestack.push(match specific_update(config.clone(), current_list.clone(), project).await { + Ok(ver) => ver, + //TODO handle errors (only continue on "NO_UPDATE_AVAILABLE") + Err(_) => { continue; }, + }); + }; + }; + //println!("{:?}", updatestack); + + //download_updates(config, updatestack).await?; + + Ok(()) +} + +async fn specific_update(config: Cfg, list: List, project: Project) -> Result> { + print!("Checking update for '{}' in {}", project.title, list.id); - projects.sort_by_key(|p| p.id.clone()); + let applicable_versions = versions(String::from(&config.apis.modrinth), String::from(&project.id), list.clone()).await; + + let mut versions: Vec = vec![]; - versions.sort_by_key(|v| v.mod_id.clone()); + for ver in &applicable_versions { + versions.push(String::from(&ver.id)); + } - let mut update_stack: Vec = vec![]; + let mut current: Vec = vec![]; + if versions.join("|") != get_list_version(config.clone(), list.clone(), String::from(&project.id))? { + //get new versions + print!(" | getting new version"); + let current_str = extract_current_version(applicable_versions.clone())?; + current.push(applicable_versions.into_iter().find(|ver| ver.id == current_str).unwrap()); + change_list_versions(config, list, current_str, versions, project.id)?; + } - for (index, project) in projects.iter().enumerate() { + if current.is_empty() { return Err(Box::new(Error::new(ErrorKind::NotFound, "NO_UPDATE_AVAILABLE"))) }; + + println!(" | ✔️"); + Ok(current[0].clone()) +} - let cmp_version = &versions[index]; +async fn download_updates(config: Cfg, versions: Vec) -> Result> { - let p_id = &project.id; - let v_id = &cmp_version.mod_id; + let dl_path = String::from(&config.downloads); - if p_id != v_id { return Err(Box::new(Error::new(ErrorKind::Other, "COMPARE_SORTING_ERR"))); }; - println!("{}:{}", p_id, v_id); + for ver in versions { + let primary_file = ver.files.into_iter().find(|file| file.primary).unwrap(); + let dl_path_file = format!("{}/{}", config.downloads, primary_file.filename); + println!("Downloading {}", primary_file.url); - if project.versions.join("|") != cmp_version.versions { - update_stack.push(String::from(&project.id)); - }; - }; + let res = Client::new() + .get(String::from(&primary_file.url)) + .send() + .await + .or(Err(format!("Failed to GET from '{}'", &primary_file.url)))?; + + // download chunks + let mut file = File::create(String::from(&dl_path_file)).or(Err(format!("Failed to create file '{}'", dl_path_file)))?; + let mut stream = res.bytes_stream(); - //TODO UPDATE - dbg!(update_stack); + while let Some(item) = stream.next().await { + let chunk = item.or(Err("Error while downloading file"))?; + file.write_all(&chunk) + .or(Err("Error while writing to file"))?; + } + } - Ok(()) + Ok(dl_path) +} + +#[tokio::test] +async fn download_updates_test() { + + use crate::{modrinth::{Version, VersionFile, Hash, VersionType}, config::{Cfg, Apis}}; + + let config = Cfg { data: "...".to_string(), clean_remove: false, downloads: "./dl".to_string(), apis: Apis { modrinth: "...".to_string() } }; + + let versions = vec![Version { + id: "dEqtGnT9".to_string(), + project_id: "kYuIpRLv".to_string(), + author_id: "Qnt13hO8".to_string(), + featured: true, + name: "1.2.2-1.19 - Fabric".to_string(), + version_number: "1.2.2-1.19".to_string(), + changelog: None, + date_published: "2022-11-02T17:41:43.072267Z".to_string(), + downloads: 58, + version_type: VersionType::release, + files: vec![VersionFile { + hashes: Hash { + sha1: "fdc6dc39427fc92cc1d7ad8b275b5b83325e712b".to_string(), + sha512: "5b372f00d6e5d6a5ef225c3897826b9f6a2be5506905f7f71b9e939779765b41be6f2a9b029cfc752ad0751d0d2d5f8bb4544408df1363eebdde15641e99a849".to_string() + }, + url: "https://cdn.modrinth.com/data/kYuIpRLv/versions/dEqtGnT9/waveycapes-fabric-1.2.2-mc1.19.2.jar".to_string(), + filename: "waveycapes-fabric-1.2.2-mc1.19.2.jar".to_string(), + primary: true, + size: 323176 + }], + game_versions: vec![ + "1.19".to_string(), + "1.19.1".to_string(), + "1.19.2".to_string() + ], + loaders: vec![ + "fabric".to_string() + ] + }]; + assert_eq!(download_updates(config, versions).await.unwrap(), "./dl") } -- cgit v1.2.3