diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 01bd5b8..43f6757 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -2,7 +2,6 @@ name: Rust on: push: - branches: [ "master" ] pull_request: branches: [ "master" ] diff --git a/.gitignore b/.gitignore index a6b9c87..5c2b500 100644 --- a/.gitignore +++ b/.gitignore @@ -3,5 +3,4 @@ shell.nix .direnv/ .envrc -src/default.json testing_jars/ diff --git a/Cargo.lock b/Cargo.lock index 5e64c26..ce6a765 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,8 +8,10 @@ version = "0.1.0" dependencies = [ "futures-util", "reqwest", + "serde", "serde_json", "tokio", + "toml", "zip", ] @@ -1278,6 +1280,15 @@ dependencies = [ "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1536,6 +1547,47 @@ dependencies = [ "tokio", ] +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + [[package]] name = "tower" version = "0.5.2" @@ -1940,6 +1992,15 @@ version = "0.53.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +[[package]] +name = "winnow" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06928c8748d81b05c9be96aad92e1b6ff01833332f281e8cfca3be4b35fc9ec" +dependencies = [ + "memchr", +] + [[package]] name = "wit-bindgen-rt" version = "0.33.0" diff --git a/Cargo.toml b/Cargo.toml index 8384b0d..00e011e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,8 @@ edition = "2024" [dependencies] futures-util = "0.3.31" reqwest = { version = "0.12.14", features = ["stream"] } +serde = { version = "1.0.219", features = ["derive"] } serde_json = "1.0.140" tokio = { version = "1.44.0", features = ["full"] } zip = "2.2.3" +toml = "0.8.23" diff --git a/src/api_calls.rs b/src/api_calls.rs index adb807e..13ece2d 100644 --- a/src/api_calls.rs +++ b/src/api_calls.rs @@ -4,7 +4,8 @@ use serde_json::Value; pub async fn get_api_search_result( client: Client, fabricmod_id: String, - config: Value, + loader_version: String, + server_version: String, ) -> Result> { let search_result = client .get("https://api.modrinth.com/v2/search") @@ -14,8 +15,7 @@ pub async fn get_api_search_result( "facets", format!( "[[\"categories:{}\"],[\"versions:{}\"]]", - config["loader_version"].as_str().unwrap(), - config["server_version"].as_str().unwrap() + loader_version, server_version ), ), ]) diff --git a/src/config.rs b/src/config.rs new file mode 100644 index 0000000..d110f03 --- /dev/null +++ b/src/config.rs @@ -0,0 +1,65 @@ +use serde::{Deserialize, Serialize}; +use std::{ + fs::{self, File}, + io::{self, Read, Write}, + path::{Path, PathBuf}, +}; + +#[derive(Deserialize, Serialize, Debug)] +#[serde(default)] +pub struct Config { + /// Path to the folder containing the mod jar's + pub target_path: PathBuf, + + /// Minecraft Server version as a string + pub server_version: String, + + /// Mod Loader that is being used as a string + pub loader_version: String, + + #[serde(skip)] + path: PathBuf, +} + +impl Default for Config { + fn default() -> Self { + Self { + target_path: Path::new(".").into(), + server_version: String::new(), + loader_version: String::new(), + path: "./settings.toml".into(), + } + } +} + +impl Config { + pub fn open>(path: &P) -> Result { + let mut input_str = String::new(); + if !path.as_ref().exists() { + let new_self = Self { + path: path.as_ref().to_path_buf(), + ..Default::default() + }; + new_self.save()?; + return Ok(new_self); + } else { + File::open(path).unwrap().read_to_string(&mut input_str)?; + } + + let mut parsed_config: Self = toml::from_str(&input_str).unwrap(); + parsed_config.path = path.as_ref().to_path_buf(); + + Ok(parsed_config) + } + + pub fn save(&self) -> Result<(), io::Error> { + let out_path = &self.path.with_extension("new"); + let mut file = File::create(out_path)?; + file.write_all(&toml::to_string_pretty(self).unwrap().into_bytes())?; + + // Overwrite the original DB with + fs::rename(out_path, &self.path)?; + + Ok(()) + } +} diff --git a/src/default.json b/src/default.json deleted file mode 100644 index 74adde4..0000000 --- a/src/default.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "target_path": "path/to/jar.jar", - "server_version": "version", - "loader_version": "loader" -} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 8caa052..ee12796 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,25 +1,19 @@ mod api_calls; +mod config; use crate::api_calls::{get_api_project_result, get_api_search_result, get_api_version_result}; +use crate::config::Config; use futures_util::StreamExt; use reqwest::{Client, get}; use serde_json::Value; use std::fs::{File, read_dir}; -use std::io::{Read, Write}; +use std::io::Write; use std::path::Path; #[tokio::main] async fn main() { - //TODO Change this to a TOML file instead of using JSON. - //********************************************************************** - let mut file = File::open("./src/default.json").unwrap(); - let mut data = String::new(); - file.read_to_string(&mut data).unwrap(); - - let config: Value = serde_json::from_str(&data).unwrap(); - let folder_path = config["target_path"].as_str().unwrap(); - let folder = read_dir(folder_path).unwrap(); - //********************************************************************** + let config = Config::open(&"./settings.toml").expect("Could not open settings file"); + let folder = read_dir(config.target_path.clone()).unwrap(); for file in folder { let jar_path = file.unwrap().path(); @@ -30,25 +24,31 @@ async fn main() { let client = Client::new(); - let project_id = - match get_api_search_result(client.clone(), fabricmod_id, config.clone()).await { - Ok(search_result) => { - if is_compatable( - config["loader_version"].clone(), - config["server_version"].clone(), - search_result["hits"][0]["versions"].as_array().unwrap(), - None, - ) { - search_result["hits"][0]["project_id"] - .as_str() - .unwrap() - .to_string() - } else { - continue; //ToDo add information to console log - } + let project_id = match get_api_search_result( + client.clone(), + fabricmod_id, + config.loader_version.clone(), + config.server_version.clone(), + ) + .await + { + Ok(search_result) => { + if is_compatable( + Value::String(config.loader_version.clone()), + Value::String(config.server_version.clone()), + search_result["hits"][0]["versions"].as_array().unwrap(), + None, + ) { + search_result["hits"][0]["project_id"] + .as_str() + .unwrap() + .to_string() + } else { + continue; //ToDo add information to console log } - Err(_) => continue, - }; + } + Err(_) => continue, + }; let mut version_id_array = match get_api_project_result(client.clone(), project_id.as_str().to_string()).await { @@ -71,8 +71,8 @@ async fn main() { { Ok(version_result) => { if is_compatable( - config["loader_version"].clone(), - config["server_version"].clone(), + Value::String(config.loader_version.clone()), + Value::String(config.server_version.clone()), version_result["game_versions"].as_array().unwrap(), Some(version_result["loaders"].as_array().unwrap()), ) { @@ -101,7 +101,7 @@ async fn main() { None => continue, }; - let download_path = format!("./{}{}", folder_path, filename); + let download_path = format!("./{}/{}", config.target_path.clone().display(), filename); match download_files(download_url, &download_path).await { Ok(_) => println!("file downloaded successfully!"),