summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/apis/modrinth.rs12
-rw-r--r--src/commands/download.rs39
-rw-r--r--src/commands/update.rs50
-rw-r--r--src/input.rs2
-rw-r--r--src/lib.rs24
5 files changed, 52 insertions, 75 deletions
diff --git a/src/apis/modrinth.rs b/src/apis/modrinth.rs
index ec8d203..c99cfbf 100644
--- a/src/apis/modrinth.rs
+++ b/src/apis/modrinth.rs
@@ -4,7 +4,7 @@ use serde::Deserialize;
4 4
5use crate::{Modloader, List}; 5use crate::{Modloader, List};
6 6
7#[derive(Debug, Deserialize)] 7#[derive(Debug, Deserialize, Clone)]
8pub struct Project { 8pub struct Project {
9 pub slug: String, 9 pub slug: String,
10 pub title: String, 10 pub title: String,
@@ -29,21 +29,21 @@ pub struct Project {
29 pub versions: Vec<String>, 29 pub versions: Vec<String>,
30} 30}
31 31
32#[derive(Debug, Deserialize)] 32#[derive(Debug, Deserialize, Clone)]
33pub struct License { 33pub struct License {
34 pub id: String, 34 pub id: String,
35 pub name: String, 35 pub name: String,
36 pub url: Option<String>, 36 pub url: Option<String>,
37} 37}
38 38
39#[derive(Debug, Deserialize)] 39#[derive(Debug, Deserialize, Clone)]
40pub struct ModeratorMessage { 40pub struct ModeratorMessage {
41 pub message: String, 41 pub message: String,
42 pub body: Option<String>, 42 pub body: Option<String>,
43} 43}
44 44
45#[allow(non_camel_case_types)] 45#[allow(non_camel_case_types)]
46#[derive(Debug, Deserialize)] 46#[derive(Debug, Deserialize, Clone)]
47pub enum Side { 47pub enum Side {
48 required, 48 required,
49 optional, 49 optional,
@@ -51,7 +51,7 @@ pub enum Side {
51} 51}
52 52
53#[allow(non_camel_case_types)] 53#[allow(non_camel_case_types)]
54#[derive(Debug, Deserialize)] 54#[derive(Debug, Deserialize, Clone)]
55pub enum Type { 55pub enum Type {
56 r#mod, 56 r#mod,
57 modpack, 57 modpack,
@@ -59,7 +59,7 @@ pub enum Type {
59} 59}
60 60
61#[allow(non_camel_case_types)] 61#[allow(non_camel_case_types)]
62#[derive(Debug, Deserialize)] 62#[derive(Debug, Deserialize, Clone)]
63pub enum Status { 63pub enum Status {
64 approved, 64 approved,
65 rejected, 65 rejected,
diff --git a/src/commands/download.rs b/src/commands/download.rs
index db0fc93..82d6b02 100644
--- a/src/commands/download.rs
+++ b/src/commands/download.rs
@@ -1,9 +1,3 @@
1use std::{io::Write, fs::File};
2
3use reqwest::Client;
4
5use futures_util::StreamExt;
6
7use crate::{List, get_current_list, config::Cfg, db::userlist_get_all_downloads, input::Input}; 1use crate::{List, get_current_list, config::Cfg, db::userlist_get_all_downloads, input::Input};
8 2
9pub async fn download(config: Cfg, input: Input) -> Result<(), Box<dyn std::error::Error>> { 3pub async fn download(config: Cfg, input: Input) -> Result<(), Box<dyn std::error::Error>> {
@@ -16,9 +10,11 @@ pub async fn download(config: Cfg, input: Input) -> Result<(), Box<dyn std::erro
16 Ok(()) 10 Ok(())
17} 11}
18 12
19async fn download_links(config: Cfg, input: Input, current_list: List, links: Vec<String>) -> Result<String, Box<dyn std::error::Error>> { 13async fn download_links(_config: Cfg, _input: Input, _current_list: List, _links: Vec<String>) -> Result<String, Box<dyn std::error::Error>> {
20 14 println!("NO DL IMPLEMENTATION FOR DOWNLOAD YET");
21 let dl_path = String::from(&config.downloads); 15 //TODO copy dl from update if possible
16 /*
17 let dl_path = String::from(&current_list.download_folder);
22 18
23 if input.clean { 19 if input.clean {
24 let dl_path = &current_list.download_folder; 20 let dl_path = &current_list.download_folder;
@@ -28,28 +24,7 @@ async fn download_links(config: Cfg, input: Input, current_list: List, links: Ve
28 std::fs::remove_file(entry.path())?; 24 std::fs::remove_file(entry.path())?;
29 } 25 }
30 } 26 }
27 */
31 28
32 for link in links { 29 Ok(String::new())
33 let filename = link.split('/').last().unwrap();
34 let dl_path_file = format!("{}/{}", config.downloads, filename);
35 println!("Downloading {}", link);
36
37 let res = Client::new()
38 .get(String::from(&link))
39 .send()
40 .await
41 .or(Err(format!("Failed to GET from '{}'", &link)))?;
42
43 // download chunks
44 let mut file = File::create(String::from(&dl_path_file)).or(Err(format!("Failed to create file '{}'", dl_path_file)))?;
45 let mut stream = res.bytes_stream();
46
47 while let Some(item) = stream.next().await {
48 let chunk = item.or(Err("Error while downloading file"))?;
49 file.write_all(&chunk)
50 .or(Err("Error while writing to file"))?;
51 }
52 }
53
54 Ok(dl_path)
55} 30}
diff --git a/src/commands/update.rs b/src/commands/update.rs
index 85630f5..eba5e91 100644
--- a/src/commands/update.rs
+++ b/src/commands/update.rs
@@ -1,10 +1,6 @@
1use std::{io::{Error, ErrorKind, Write}, fs::File}; 1use std::io::{Error, ErrorKind};
2 2
3use reqwest::Client; 3use crate::{config::Cfg, modrinth::{projects, Project, versions, extract_current_version, Version}, get_current_list, db::{userlist_get_all_ids, mods_get_versions, userlist_get_applicable_versions, userlist_change_versions}, List, input::Input, download_file};
4
5use futures_util::StreamExt;
6
7use crate::{config::Cfg, modrinth::{projects, Project, versions, extract_current_version, Version}, get_current_list, db::{userlist_get_all_ids, mods_get_versions, userlist_get_applicable_versions, userlist_change_versions}, List, input::Input};
8 4
9pub async fn update(config: Cfg, input: Input) -> Result<(), Box<dyn std::error::Error>> { 5pub async fn update(config: Cfg, input: Input) -> Result<(), Box<dyn std::error::Error>> {
10 6
@@ -29,16 +25,16 @@ pub async fn update(config: Cfg, input: Input) -> Result<(), Box<dyn std::error:
29 25
30 //Adding to stack if not the same versions in the list OR if clean == true 26 //Adding to stack if not the same versions in the list OR if clean == true
31 if input.clone().clean || (project.versions.join("|") != current_version.versions) { 27 if input.clone().clean || (project.versions.join("|") != current_version.versions) {
32 updatestack.push(match specific_update(config.clone(), input.clone(), current_list.clone(), project).await { 28 updatestack.push(match specific_update(config.clone(), input.clone(), current_list.clone(), project.clone()).await {
33 Ok(ver) => ver, 29 Ok(ver) => ver,
34 //TODO handle errors (only continue on "NO_UPDATE_AVAILABLE") 30 //TODO handle errors (only continue on "NO_UPDATE_AVAILABLE")
35 Err(_) => { continue; }, 31 Err(_) => { println!("({}) No new version found for the specified minecraft version", project.title); continue; },
36 }); 32 });
33 } else {
34 println!("({}) No new version found", project.title);
37 }; 35 };
38 }; 36 };
39 //println!("{:?}", updatestack); 37
40
41
42 if input.clean { 38 if input.clean {
43 let dl_path = &current_list.download_folder; 39 let dl_path = &current_list.download_folder;
44 println!("Cleaning {}", dl_path); 40 println!("Cleaning {}", dl_path);
@@ -47,8 +43,8 @@ pub async fn update(config: Cfg, input: Input) -> Result<(), Box<dyn std::error:
47 std::fs::remove_file(entry.path())?; 43 std::fs::remove_file(entry.path())?;
48 } 44 }
49 } 45 }
50 46
51 download_updates(config, current_list, updatestack).await?; 47 if input.direct_download { download_updates(current_list, updatestack).await?; };
52 48
53 Ok(()) 49 Ok(())
54} 50}
@@ -82,41 +78,25 @@ async fn specific_update(config: Cfg, input: Input, list: List, project: Project
82 Ok(current[0].clone()) 78 Ok(current[0].clone())
83} 79}
84 80
85async fn download_updates(config: Cfg, current_list: List, versions: Vec<Version>) -> Result<String, Box<dyn std::error::Error>> { 81async fn download_updates(current_list: List, versions: Vec<Version>) -> Result<String, Box<dyn std::error::Error>> {
86 82
87 let dl_path = String::from(&current_list.download_folder); 83 let dl_path = String::from(&current_list.download_folder);
88 84
89 for ver in versions { 85 for ver in versions {
90 let primary_file = ver.files.into_iter().find(|file| file.primary).unwrap(); 86 let primary_file = ver.files.into_iter().find(|file| file.primary).unwrap();
91 let dl_path_file = format!("{}/{}", config.downloads, primary_file.filename); 87 download_file(primary_file.url, current_list.clone().download_folder, primary_file.filename).await?;
92 println!("Downloading {}", primary_file.url);
93
94 let res = Client::new()
95 .get(String::from(&primary_file.url))
96 .send()
97 .await
98 .or(Err(format!("Failed to GET from '{}'", &primary_file.url)))?;
99
100 // download chunks
101 let mut file = File::create(String::from(&dl_path_file)).or(Err(format!("Failed to create file '{}'", dl_path_file)))?;
102 let mut stream = res.bytes_stream();
103
104 while let Some(item) = stream.next().await {
105 let chunk = item.or(Err("Error while downloading file"))?;
106 file.write_all(&chunk)
107 .or(Err("Error while writing to file"))?;
108 }
109 } 88 }
110 89
90
111 Ok(dl_path) 91 Ok(dl_path)
112} 92}
113 93
114#[tokio::test] 94#[tokio::test]
115async fn download_updates_test() { 95async fn download_updates_test() {
116 96
117 use crate::{modrinth::{Version, VersionFile, Hash, VersionType}, config::{Cfg, Apis}}; 97 use crate::{modrinth::{Version, VersionFile, Hash, VersionType}, Modloader, List};
118 98
119 let config = Cfg { data: "...".to_string(), clean_remove: false, downloads: "./dl".to_string(), apis: Apis { modrinth: "...".to_string() } }; 99 let current_list = List { id: String::from("..."), mc_version: String::from("..."), modloader: Modloader::Forge, download_folder: String::from("./dl") };
120 100
121 let versions = vec![Version { 101 let versions = vec![Version {
122 id: "dEqtGnT9".to_string(), 102 id: "dEqtGnT9".to_string(),
@@ -148,5 +128,5 @@ async fn download_updates_test() {
148 "fabric".to_string() 128 "fabric".to_string()
149 ] 129 ]
150 }]; 130 }];
151 assert_eq!(download_updates(config, versions).await.unwrap(), "./dl") 131 assert!(download_updates(current_list, versions).await.is_ok())
152} 132}
diff --git a/src/input.rs b/src/input.rs
index 19aa2c2..0b616d4 100644
--- a/src/input.rs
+++ b/src/input.rs
@@ -129,7 +129,7 @@ pub async fn get_input(config: Cfg) -> Result<(), Box<dyn std::error::Error>> {
129 129
130#[test] 130#[test]
131fn input_from() { 131fn input_from() {
132 let string = "lis add test 1.19.2 fabric"; 132 let string = "list add test 1.19.2 fabric";
133 let input = Input{ command: Cmd::List, subcommand: Some(Subcmd::Add), args: Some(vec![String::from("test"), String::from("1.19.2"), String::from("fabric")]), force_download: false, direct_download: false, all_lists: false, clean: false, delete_old: false }; 133 let input = Input{ command: Cmd::List, subcommand: Some(Subcmd::Add), args: Some(vec![String::from("test"), String::from("1.19.2"), String::from("fabric")]), force_download: false, direct_download: false, all_lists: false, clean: false, delete_old: false };
134 assert_eq!(Input::from(string).unwrap(), input); 134 assert_eq!(Input::from(string).unwrap(), input);
135} 135}
diff --git a/src/lib.rs b/src/lib.rs
index 51b4487..e4ebf76 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,10 +5,12 @@ pub mod input;
5pub mod db; 5pub mod db;
6pub mod error; 6pub mod error;
7 7
8use std::io::{Error, ErrorKind}; 8use std::{io::{Error, ErrorKind, Write}, fs::File};
9 9
10pub use apis::*; 10pub use apis::*;
11pub use commands::*; 11pub use commands::*;
12use futures_util::StreamExt;
13use reqwest::Client;
12 14
13#[derive(Debug, Clone, PartialEq, Eq)] 15#[derive(Debug, Clone, PartialEq, Eq)]
14pub enum Modloader { 16pub enum Modloader {
@@ -32,3 +34,23 @@ impl Modloader {
32 } 34 }
33 } 35 }
34} 36}
37
38pub async fn download_file(url: String, path: String, name: String) -> Result<(), Box<dyn std::error::Error>> {
39 println!("Downloading {}", url);
40 let dl_path_file = format!("{}/{}", path, name);
41 let res = Client::new()
42 .get(String::from(&url))
43 .send()
44 .await?;
45
46 // download chunks
47 let mut file = File::create(String::from(&dl_path_file))?;
48 let mut stream = res.bytes_stream();
49
50 while let Some(item) = stream.next().await {
51 let chunk = item?;
52 file.write_all(&chunk)?;
53 }
54
55 Ok(())
56}