summaryrefslogtreecommitdiff
path: root/src/commands
diff options
context:
space:
mode:
Diffstat (limited to 'src/commands')
-rw-r--r--src/commands/modification.rs11
-rw-r--r--src/commands/update.rs140
2 files changed, 120 insertions, 31 deletions
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 @@
1use std::io::{Error, ErrorKind}; 1use std::io::{Error, ErrorKind};
2 2
3use 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}; 3use 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};
4 4
5pub async fn modification(config: Cfg, args: Option<Vec<String>>) -> Result<(), Box<dyn std::error::Error>> { 5pub async fn modification(config: Cfg, args: Option<Vec<String>>) -> Result<(), Box<dyn std::error::Error>> {
6 6
@@ -77,12 +77,3 @@ fn remove(config: Cfg, args: Vec<String>) -> Result<(), Box<dyn std::error::Erro
77 Ok(()) => Ok(()), 77 Ok(()) => Ok(()),
78 } 78 }
79} 79}
80
81fn extract_current_version(versions: Vec<Version>) -> Result<String, Box<dyn std::error::Error>> {
82 match versions.len() {
83 0 => Err(Box::new(Error::new(ErrorKind::NotFound, "NO_VERSIONS_AVAILABLE"))),
84 //TODO compare publish dates
85 1.. => Ok(versions[0].id.to_string()),
86 _ => panic!("available_versions should never be negative"),
87 }
88}
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 @@
1use std::io::{Error, ErrorKind}; 1use std::{io::{Error, ErrorKind, Write}, fs::File};
2 2
3use crate::{config::Cfg, modrinth::projects, get_current_list, db::{get_mods_from_list, get_versions}}; 3use reqwest::Client;
4
5use futures_util::StreamExt;
6
7use 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};
4 8
5pub async fn update(config: Cfg) -> Result<(), Box<dyn std::error::Error>> { 9pub async fn update(config: Cfg) -> Result<(), Box<dyn std::error::Error>> {
6 10
7 let current_list = get_current_list(config.clone())?; 11 let current_list = get_current_list(config.clone())?;
8 12
9 let mods = get_mods_from_list(config.clone(), current_list)?; 13 let mods = get_mods_from_list(config.clone(), current_list.clone())?;
14
15 let mut versions = get_versions(config.clone(), mods.clone())?;
16 versions.sort_by_key(|ver| ver.mod_id.clone());
10 17
11 let mut projects = projects(String::from(&config.apis.modrinth), mods.clone()).await; 18 let mut projects = projects(String::from(&config.apis.modrinth), mods).await;
19 projects.sort_by_key(|pro| pro.id.clone());
12 20
13 let mut versions = get_versions(config, mods)?; 21 let mut updatestack: Vec<Version> = vec![];
22 for (index, project) in projects.into_iter().enumerate() {
23 let current_version = &versions[index];
24
25 let p_id = String::from(&project.id);
26 let v_id = &current_version.mod_id;
27
28 if &p_id != v_id { return Err(Box::new(Error::new(ErrorKind::Other, "SORTING_ERROR"))) };
29
30 if project.versions.join("|") != current_version.versions {
31 updatestack.push(match specific_update(config.clone(), current_list.clone(), project).await {
32 Ok(ver) => ver,
33 //TODO handle errors (only continue on "NO_UPDATE_AVAILABLE")
34 Err(_) => { continue; },
35 });
36 };
37 };
38 //println!("{:?}", updatestack);
39
40 //download_updates(config, updatestack).await?;
41
42 Ok(())
43}
44
45async fn specific_update(config: Cfg, list: List, project: Project) -> Result<Version, Box<dyn std::error::Error>> {
46 print!("Checking update for '{}' in {}", project.title, list.id);
14 47
15 projects.sort_by_key(|p| p.id.clone()); 48 let applicable_versions = versions(String::from(&config.apis.modrinth), String::from(&project.id), list.clone()).await;
49
50 let mut versions: Vec<String> = vec![];
16 51
17 versions.sort_by_key(|v| v.mod_id.clone()); 52 for ver in &applicable_versions {
53 versions.push(String::from(&ver.id));
54 }
18 55
19 let mut update_stack: Vec<String> = vec![]; 56 let mut current: Vec<Version> = vec![];
57 if versions.join("|") != get_list_version(config.clone(), list.clone(), String::from(&project.id))? {
58 //get new versions
59 print!(" | getting new version");
60 let current_str = extract_current_version(applicable_versions.clone())?;
61 current.push(applicable_versions.into_iter().find(|ver| ver.id == current_str).unwrap());
62 change_list_versions(config, list, current_str, versions, project.id)?;
63 }
20 64
21 for (index, project) in projects.iter().enumerate() { 65 if current.is_empty() { return Err(Box::new(Error::new(ErrorKind::NotFound, "NO_UPDATE_AVAILABLE"))) };
66
67 println!(" | ✔️");
68 Ok(current[0].clone())
69}
22 70
23 let cmp_version = &versions[index]; 71async fn download_updates(config: Cfg, versions: Vec<Version>) -> Result<String, Box<dyn std::error::Error>> {
24 72
25 let p_id = &project.id; 73 let dl_path = String::from(&config.downloads);
26 let v_id = &cmp_version.mod_id;
27 74
28 if p_id != v_id { return Err(Box::new(Error::new(ErrorKind::Other, "COMPARE_SORTING_ERR"))); }; 75 for ver in versions {
29 println!("{}:{}", p_id, v_id); 76 let primary_file = ver.files.into_iter().find(|file| file.primary).unwrap();
77 let dl_path_file = format!("{}/{}", config.downloads, primary_file.filename);
78 println!("Downloading {}", primary_file.url);
30 79
31 if project.versions.join("|") != cmp_version.versions { 80 let res = Client::new()
32 update_stack.push(String::from(&project.id)); 81 .get(String::from(&primary_file.url))
33 }; 82 .send()
34 }; 83 .await
84 .or(Err(format!("Failed to GET from '{}'", &primary_file.url)))?;
85
86 // download chunks
87 let mut file = File::create(String::from(&dl_path_file)).or(Err(format!("Failed to create file '{}'", dl_path_file)))?;
88 let mut stream = res.bytes_stream();
35 89
36 //TODO UPDATE 90 while let Some(item) = stream.next().await {
37 dbg!(update_stack); 91 let chunk = item.or(Err("Error while downloading file"))?;
92 file.write_all(&chunk)
93 .or(Err("Error while writing to file"))?;
94 }
95 }
38 96
39 Ok(()) 97 Ok(dl_path)
98}
99
100#[tokio::test]
101async fn download_updates_test() {
102
103 use crate::{modrinth::{Version, VersionFile, Hash, VersionType}, config::{Cfg, Apis}};
104
105 let config = Cfg { data: "...".to_string(), clean_remove: false, downloads: "./dl".to_string(), apis: Apis { modrinth: "...".to_string() } };
106
107 let versions = vec![Version {
108 id: "dEqtGnT9".to_string(),
109 project_id: "kYuIpRLv".to_string(),
110 author_id: "Qnt13hO8".to_string(),
111 featured: true,
112 name: "1.2.2-1.19 - Fabric".to_string(),
113 version_number: "1.2.2-1.19".to_string(),
114 changelog: None,
115 date_published: "2022-11-02T17:41:43.072267Z".to_string(),
116 downloads: 58,
117 version_type: VersionType::release,
118 files: vec![VersionFile {
119 hashes: Hash {
120 sha1: "fdc6dc39427fc92cc1d7ad8b275b5b83325e712b".to_string(),
121 sha512: "5b372f00d6e5d6a5ef225c3897826b9f6a2be5506905f7f71b9e939779765b41be6f2a9b029cfc752ad0751d0d2d5f8bb4544408df1363eebdde15641e99a849".to_string()
122 },
123 url: "https://cdn.modrinth.com/data/kYuIpRLv/versions/dEqtGnT9/waveycapes-fabric-1.2.2-mc1.19.2.jar".to_string(),
124 filename: "waveycapes-fabric-1.2.2-mc1.19.2.jar".to_string(),
125 primary: true,
126 size: 323176
127 }],
128 game_versions: vec![
129 "1.19".to_string(),
130 "1.19.1".to_string(),
131 "1.19.2".to_string()
132 ],
133 loaders: vec![
134 "fabric".to_string()
135 ]
136 }];
137 assert_eq!(download_updates(config, versions).await.unwrap(), "./dl")
40} 138}