diff options
author | fxqnlr <[email protected]> | 2022-10-31 22:41:18 +0100 |
---|---|---|
committer | fxqnlr <[email protected]> | 2022-10-31 22:41:18 +0100 |
commit | fc1cb1acc0dce412e948475002666bcd1d4b0348 (patch) | |
tree | 6b7667b453af8f2065681fa4dd850b0675b7bbde /src | |
parent | 3320da719669f37dd5f55693b4d76edb27dbce02 (diff) | |
download | modlist-fc1cb1acc0dce412e948475002666bcd1d4b0348.tar modlist-fc1cb1acc0dce412e948475002666bcd1d4b0348.tar.gz modlist-fc1cb1acc0dce412e948475002666bcd1d4b0348.zip |
add first impl
Diffstat (limited to 'src')
-rw-r--r-- | src/apis/modrinth.rs | 101 | ||||
-rw-r--r-- | src/commands/add.rs | 34 | ||||
-rw-r--r-- | src/commands/mod.rs | 3 | ||||
-rw-r--r-- | src/config.rs | 23 | ||||
-rw-r--r-- | src/db.rs | 18 | ||||
-rw-r--r-- | src/input.rs | 59 | ||||
-rw-r--r-- | src/lib.rs | 11 | ||||
-rw-r--r-- | src/main.rs | 7 | ||||
-rw-r--r-- | src/update.rs | 8 |
9 files changed, 227 insertions, 37 deletions
diff --git a/src/apis/modrinth.rs b/src/apis/modrinth.rs index ce9fdd4..3af5bbd 100644 --- a/src/apis/modrinth.rs +++ b/src/apis/modrinth.rs | |||
@@ -1,25 +1,6 @@ | |||
1 | use serde::{Deserialize, Serialize}; | 1 | use serde::Deserialize; |
2 | 2 | ||
3 | async fn get(path: String) -> Result<Vec<u8>, Box<dyn std::error::Error>> { | 3 | use crate::Modloader; |
4 | dbg!(&path); | ||
5 | let api = String::from("https://api.modrinth.com/v2/"); | ||
6 | //let api = String::from("localhost:8080/"); | ||
7 | //let api = String::from("https://www.rust-lang.org/"); | ||
8 | let url = format!(r#"{}{}"#, api, path); | ||
9 | |||
10 | println!("{}", &url); | ||
11 | |||
12 | |||
13 | let data = reqwest::get(r#"https://api.modrinth.com/v2/projects?ids=["kYuIpRLv","89Wsn8GD"]"#) | ||
14 | .await? | ||
15 | .bytes() | ||
16 | .await? | ||
17 | .to_vec(); | ||
18 | |||
19 | //println!("body = {:?}", data); | ||
20 | |||
21 | Ok(data) | ||
22 | } | ||
23 | 4 | ||
24 | #[derive(Debug, Deserialize)] | 5 | #[derive(Debug, Deserialize)] |
25 | pub struct Project { | 6 | pub struct Project { |
@@ -86,19 +67,89 @@ pub enum Status { | |||
86 | processing, | 67 | processing, |
87 | unknown | 68 | unknown |
88 | } | 69 | } |
89 | pub async fn project(name: &str) -> Project { | 70 | |
71 | #[derive(Debug, Deserialize)] | ||
72 | pub struct Version { | ||
73 | pub name: String, | ||
74 | pub version_number: String, | ||
75 | pub changelog: Option<String>, | ||
76 | pub game_versions: Vec<String>, | ||
77 | pub version_type: VersionType, | ||
78 | pub loaders: Vec<String>, | ||
79 | pub featured: bool, | ||
80 | pub id: String, | ||
81 | pub project_id: String, | ||
82 | pub author_id: String, | ||
83 | pub date_published: String, | ||
84 | pub downloads: u32, | ||
85 | pub files: Vec<VersionFile>, | ||
86 | } | ||
87 | |||
88 | #[allow(non_camel_case_types)] | ||
89 | #[derive(Debug, Deserialize)] | ||
90 | pub enum VersionType { | ||
91 | release, | ||
92 | beta, | ||
93 | alpha | ||
94 | } | ||
95 | |||
96 | #[derive(Debug, Deserialize)] | ||
97 | pub struct VersionFile { | ||
98 | pub hashes: Hash, | ||
99 | pub url: String, | ||
100 | pub filename: String, | ||
101 | pub primary: bool, | ||
102 | pub size: u32, | ||
103 | } | ||
104 | |||
105 | #[derive(Debug, Deserialize)] | ||
106 | pub struct Hash { | ||
107 | pub sha512: String, | ||
108 | pub sha1: String, | ||
109 | } | ||
110 | |||
111 | async fn get(api: String, path: String) -> Result<Vec<u8>, Box<dyn std::error::Error>> { | ||
112 | let url = format!(r#"{}{}"#, api, path); | ||
113 | |||
114 | dbg!(&url); | ||
115 | |||
116 | let data = reqwest::get(url) | ||
117 | .await? | ||
118 | .bytes() | ||
119 | .await? | ||
120 | .to_vec(); | ||
121 | |||
122 | Ok(data) | ||
123 | } | ||
124 | |||
125 | |||
126 | pub async fn project(api: String, name: &str) -> Project { | ||
90 | let url = format!("project/{}", name); | 127 | let url = format!("project/{}", name); |
91 | let data = get(url); | 128 | let data = get(api, url); |
92 | 129 | ||
93 | serde_json::from_slice(&data.await.unwrap()).unwrap() | 130 | serde_json::from_slice(&data.await.unwrap()).unwrap() |
94 | } | 131 | } |
95 | 132 | ||
96 | pub async fn projects(ids: Vec<&str>) -> Vec<Project> { | 133 | pub async fn projects(api: String, ids: Vec<&str>) -> Vec<Project> { |
97 | let all = ids.join(r#"",""#); | 134 | let all = ids.join(r#"",""#); |
98 | let url = format!(r#"projects?ids=["{}"]"#, all); | 135 | let url = format!(r#"projects?ids=["{}"]"#, all); |
99 | println!("{}", url); | 136 | println!("{}", url); |
100 | 137 | ||
101 | let data = get(url); | 138 | let data = get(api, url); |
102 | 139 | ||
103 | serde_json::from_slice(&data.await.unwrap()).unwrap() | 140 | serde_json::from_slice(&data.await.unwrap()).unwrap() |
104 | } | 141 | } |
142 | |||
143 | pub async fn versions(api: String, id: String, loader: Modloader, mc_version: String) -> Vec<Version> { | ||
144 | |||
145 | let loaderstr = match loader { | ||
146 | Modloader::Forge => String::from("forge"), | ||
147 | Modloader::Fabric => String::from("fabric"), | ||
148 | }; | ||
149 | |||
150 | let url = format!(r#"project/{}/version?loaders=["{}"]&game_versions=["{}"]"#, id, loaderstr, mc_version); | ||
151 | |||
152 | let data = get(api, url); | ||
153 | |||
154 | serde_json::from_slice(&data.await.unwrap()).unwrap() | ||
155 | } | ||
diff --git a/src/commands/add.rs b/src/commands/add.rs new file mode 100644 index 0000000..67f63de --- /dev/null +++ b/src/commands/add.rs | |||
@@ -0,0 +1,34 @@ | |||
1 | use std::io::{Error, ErrorKind}; | ||
2 | |||
3 | use crate::{modrinth::{project, versions}, config::Cfg, db::insert_mod, Modloader}; | ||
4 | |||
5 | pub async fn add(config: Cfg, mc_mod: String) -> Result<(), Box<dyn std::error::Error>> { | ||
6 | println!("Adding"); | ||
7 | |||
8 | let project = project(String::from(&config.apis.modrinth), &mc_mod).await; | ||
9 | |||
10 | dbg!(&project); | ||
11 | |||
12 | let loader = Modloader::Fabric; | ||
13 | |||
14 | if project.versions.is_empty() { panic!("This should never happen"); }; | ||
15 | |||
16 | let current_version = get_current(config, String::from(&project.id)).await?; | ||
17 | |||
18 | match insert_mod(project.id, project.title, current_version, project.versions, loader, String::from("1.19.2")) { | ||
19 | Err(err) => { Err(Box::new(err)) }, | ||
20 | Ok(()) => Ok(()), | ||
21 | } | ||
22 | |||
23 | } | ||
24 | |||
25 | async fn get_current(config: Cfg, id: String) -> Result<String, Box<dyn std::error::Error>> { | ||
26 | let available_versions = versions(config.apis.modrinth, id, Modloader::Fabric, String::from("1.19.2")).await; | ||
27 | |||
28 | match available_versions.len() { | ||
29 | 0 => Err(Box::new(Error::new(ErrorKind::NotFound, "NO_VERSIONS_AVAILABLE"))), | ||
30 | //TODO compare publish dates | ||
31 | 1.. => Ok(available_versions[0].id.to_string()), | ||
32 | _ => panic!("available_versions should never be negative"), | ||
33 | } | ||
34 | } | ||
diff --git a/src/commands/mod.rs b/src/commands/mod.rs new file mode 100644 index 0000000..0cc183a --- /dev/null +++ b/src/commands/mod.rs | |||
@@ -0,0 +1,3 @@ | |||
1 | pub mod add; | ||
2 | |||
3 | pub use add::*; | ||
diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..a0dfbbe --- /dev/null +++ b/src/config.rs | |||
@@ -0,0 +1,23 @@ | |||
1 | use config::{Config, File, FileFormat}; | ||
2 | use serde::Deserialize; | ||
3 | |||
4 | #[derive(Debug, Deserialize)] | ||
5 | pub struct Cfg { | ||
6 | pub apis: Apis, | ||
7 | } | ||
8 | |||
9 | #[derive(Debug, Deserialize)] | ||
10 | pub struct Apis { | ||
11 | pub modrinth: String, | ||
12 | } | ||
13 | |||
14 | impl Cfg { | ||
15 | pub fn init(path: &str) -> Self { | ||
16 | Config::builder() | ||
17 | .add_source(File::new(path, FileFormat::Ini)) | ||
18 | .build() | ||
19 | .unwrap() | ||
20 | .try_deserialize() | ||
21 | .unwrap() | ||
22 | } | ||
23 | } | ||
@@ -0,0 +1,18 @@ | |||
1 | use crate::Modloader; | ||
2 | |||
3 | pub fn insert_mod(id: String, name: String, current_version: String, old_versions: Vec<String>, mod_loader: Modloader, desired_mc_version: String) -> Result<(), sqlite::Error> { | ||
4 | |||
5 | let connection = sqlite::open("./data.db").unwrap(); | ||
6 | |||
7 | let loader = match mod_loader { | ||
8 | Modloader::Fabric => "fabric", | ||
9 | Modloader::Forge => "forge", | ||
10 | }; | ||
11 | |||
12 | let sql = format!("INSERT INTO mods VALUES ('{}', '{}', '{}', '{}', '{}', '{}')", id, name, current_version, old_versions.join("|"), loader, desired_mc_version); | ||
13 | |||
14 | dbg!(&sql); | ||
15 | |||
16 | connection.execute(sql) | ||
17 | |||
18 | } | ||
diff --git a/src/input.rs b/src/input.rs new file mode 100644 index 0000000..689389e --- /dev/null +++ b/src/input.rs | |||
@@ -0,0 +1,59 @@ | |||
1 | use std::io::{stdin, Error, ErrorKind}; | ||
2 | use crate::{add, config::Cfg}; | ||
3 | |||
4 | pub struct Input { | ||
5 | pub command: String, | ||
6 | pub args: Option<Vec<String>>, | ||
7 | } | ||
8 | |||
9 | impl Input { | ||
10 | pub fn from(string: String) -> Result<Self, Box<dyn std::error::Error>> { | ||
11 | let mut split: Vec<&str> = string.split(' ').collect(); | ||
12 | |||
13 | let command: String; | ||
14 | let mut args: Option<Vec<String>> = None; | ||
15 | |||
16 | if split[0].is_empty() { split.remove(0); }; | ||
17 | |||
18 | dbg!(&split); | ||
19 | |||
20 | match split.len() { | ||
21 | 0 => { Err(Box::new(Error::new(ErrorKind::InvalidInput, "NO_ARGS"))) } | ||
22 | 1 => Ok( Input { command: split[0].to_string(), args }), | ||
23 | 2.. => { | ||
24 | command = split[0].to_string(); | ||
25 | split.remove(0); | ||
26 | let mut str_args: Vec<String> = vec![]; | ||
27 | for e in split { | ||
28 | str_args.push(e.to_string()); | ||
29 | } | ||
30 | args = Some(str_args); | ||
31 | Ok(Input { command, args }) | ||
32 | }, | ||
33 | _ => { panic!("This should never happen") } | ||
34 | } | ||
35 | |||
36 | |||
37 | } | ||
38 | } | ||
39 | |||
40 | pub async fn get_input(config: Cfg) -> Result<(), Box<dyn std::error::Error>> { | ||
41 | let mut user_input = String::new(); | ||
42 | stdin() | ||
43 | .read_line(&mut user_input) | ||
44 | .expect("ERROR"); | ||
45 | |||
46 | dbg!(&user_input); | ||
47 | |||
48 | let input = Input::from(user_input.trim().to_string())?; | ||
49 | |||
50 | match input.command.as_str() { | ||
51 | "add" => { | ||
52 | if input.args == None { return Err(Box::new(Error::new(ErrorKind::InvalidInput, "TOO_FEW_ARGUMENTS"))) }; | ||
53 | if input.args.as_ref().unwrap().len() != 1 { return Err(Box::new(Error::new(ErrorKind::InvalidInput, "TOO_MANY_ARGUMENTS"))) }; | ||
54 | add(config, input.args.unwrap()[0].to_string()).await?; | ||
55 | Ok(()) | ||
56 | }, | ||
57 | _ => Err(Box::new(Error::new(ErrorKind::InvalidInput, "UNKNOWN_COMMAND"))), | ||
58 | } | ||
59 | } | ||
@@ -1,4 +1,13 @@ | |||
1 | pub mod update; | ||
2 | pub mod apis; | 1 | pub mod apis; |
2 | pub mod config; | ||
3 | pub mod commands; | ||
4 | pub mod input; | ||
5 | pub mod db; | ||
3 | 6 | ||
4 | pub use apis::*; | 7 | pub use apis::*; |
8 | pub use commands::*; | ||
9 | |||
10 | pub enum Modloader { | ||
11 | Fabric, | ||
12 | Forge | ||
13 | } | ||
diff --git a/src/main.rs b/src/main.rs index 8d1a1bd..957e5aa 100644 --- a/src/main.rs +++ b/src/main.rs | |||
@@ -1,7 +1,8 @@ | |||
1 | use modlist::modrinth::projects; | 1 | use modlist::{config::Cfg, input::get_input}; |
2 | 2 | ||
3 | #[tokio::main] | 3 | #[tokio::main] |
4 | async fn main() { | 4 | async fn main() { |
5 | //projects(vec!["kYuIpRLv", "89Wsn8GD"]); | 5 | let config = Cfg::init("config.ini"); |
6 | println!("{:?}", projects(vec!["kYuIpRLv", "89Wsn8GD"]).await); | 6 | //TODO Error Handling |
7 | get_input(config).await.unwrap(); | ||
7 | } | 8 | } |
diff --git a/src/update.rs b/src/update.rs deleted file mode 100644 index 2e70f43..0000000 --- a/src/update.rs +++ /dev/null | |||
@@ -1,8 +0,0 @@ | |||
1 | pub fn update_mods() { | ||
2 | |||
3 | } | ||
4 | |||
5 | fn get_version(link: String) { | ||
6 | |||
7 | |||
8 | } | ||