diff options
Diffstat (limited to 'src/commands/update.rs')
-rw-r--r-- | src/commands/update.rs | 140 |
1 files changed, 119 insertions, 21 deletions
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 @@ | |||
1 | use std::io::{Error, ErrorKind}; | 1 | use std::{io::{Error, ErrorKind, Write}, fs::File}; |
2 | 2 | ||
3 | use crate::{config::Cfg, modrinth::projects, get_current_list, db::{get_mods_from_list, get_versions}}; | 3 | use reqwest::Client; |
4 | |||
5 | use futures_util::StreamExt; | ||
6 | |||
7 | 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}; | ||
4 | 8 | ||
5 | pub async fn update(config: Cfg) -> Result<(), Box<dyn std::error::Error>> { | 9 | pub 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 = ¤t_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 | |||
45 | async 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]; | 71 | async 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] | ||
101 | async 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 | } |