From 5e91749a7c884b96bd5c600f101ff2d670cbdf78 Mon Sep 17 00:00:00 2001 From: Loudbook Date: Sun, 4 Feb 2024 13:55:19 -0500 Subject: [PATCH] Version lister, Fix https://github.com/Loudbooks/Minecraft-Server-Installer/issues/3 --- src/downloader.rs | 1 + src/downloaders/bungeecord.rs | 6 +++ src/downloaders/fabric.rs | 10 +++++ src/downloaders/forge.rs | 15 ++++++++ src/downloaders/geyser.rs | 8 ++++ src/downloaders/mod.rs | 2 +- src/downloaders/neoforge.rs | 18 ++++++++- src/downloaders/paper.rs | 14 +++++++ src/downloaders/purpur.rs | 14 +++++++ src/downloaders/vanilla.rs | 4 ++ src/downloaders/velocity.rs | 8 ++++ src/downloaders/waterfall.rs | 14 +++++++ src/main.rs | 71 ++++++++++++++++++++++++++++++++--- 13 files changed, 177 insertions(+), 8 deletions(-) diff --git a/src/downloader.rs b/src/downloader.rs index 2469875..a749a6c 100644 --- a/src/downloader.rs +++ b/src/downloader.rs @@ -19,6 +19,7 @@ pub trait Installer: Sync { fn custom_script(&self) -> bool; fn version_required(&self) -> bool { true } + async fn get_versions(&self, client: Client) -> Vec; async fn startup_message(&self, string: String) -> Option; async fn download(&self, client: Client, minecraft_version: Option) -> Result; async fn build(&self, _java_path: String, _minecraft_version: Option) {} diff --git a/src/downloaders/bungeecord.rs b/src/downloaders/bungeecord.rs index e780c96..b065849 100644 --- a/src/downloaders/bungeecord.rs +++ b/src/downloaders/bungeecord.rs @@ -27,6 +27,12 @@ impl Installer for BungeeCord { false } + async fn get_versions(&self, client: reqwest::Client) -> Vec { + let version = client.get("https://ci.md-5.net/job/BungeeCord/lastSuccessfulBuild/buildNumber").send().await.expect("Failed to get latest version for ").text(); + + vec![version.await.unwrap_or("".to_string())] + } + async fn startup_message(&self, string: String) -> Option { basic_proxy_address_from_string(string).await } diff --git a/src/downloaders/fabric.rs b/src/downloaders/fabric.rs index a9ae32e..7855f6e 100644 --- a/src/downloaders/fabric.rs +++ b/src/downloaders/fabric.rs @@ -27,6 +27,16 @@ impl Installer for Fabric { false } + async fn get_versions(&self, client: Client) -> Vec { + let json: serde_json::Value = client.get("https://meta.fabricmc.net/v2/versions/game").send().await.expect("Failed to get latest version for Fabric").json().await.expect("Failed to get latest version for Fabric"); + + let versions: Vec = json.as_array().map(|versions| { + versions.iter().map(|version| version["version"].as_str().unwrap().to_string()).collect() + }).unwrap_or_default(); + + versions + } + async fn startup_message(&self, string: String) -> Option { basic_server_address_from_string(string).await } diff --git a/src/downloaders/forge.rs b/src/downloaders/forge.rs index 59b1aa6..114b5d8 100644 --- a/src/downloaders/forge.rs +++ b/src/downloaders/forge.rs @@ -32,6 +32,21 @@ impl Installer for Forge { false } + async fn get_versions(&self, client: Client) -> Vec { + let url = "https://files.minecraftforge.net/maven/net/minecraftforge/forge/promotions_slim.json"; + let response = client.get(url).send().await.expect("Failed to get latest version for Forge"); + let json: Value = response.json().await.expect("Failed to get latest version for Forge"); + + let game_versions = json["promos"].as_object().expect("Invalid JSON format"); + + let versions: Vec = game_versions + .iter() + .map(|(version, _)| version.to_string().replace("-latest", "").replace("-recommended", "")) + .collect(); + + versions + } + async fn startup_message(&self, string: String) -> Option { basic_server_address_from_string(string).await } diff --git a/src/downloaders/geyser.rs b/src/downloaders/geyser.rs index 51137e7..82b7d61 100644 --- a/src/downloaders/geyser.rs +++ b/src/downloaders/geyser.rs @@ -1,5 +1,6 @@ use async_trait::async_trait; +use reqwest::Client; use crate::downloader::{basic_server_address_from_string, download_file, Installer}; use crate::servertype::ServerType; use crate::servertype::ServerType::Server; @@ -28,6 +29,13 @@ impl Installer for Geyser { false } + async fn get_versions(&self, client: Client) -> Vec { + let json: serde_json::Value = client.get("https://download.geysermc.org/v2/projects/geyser/versions/latest").send().await.expect("Failed to get latest version for Geyser").json().await.expect("Failed to get latest version for Geyser"); + let version = json["version"].as_str().unwrap().to_string(); + + vec![version] + } + async fn startup_message(&self, string: String) -> Option { basic_server_address_from_string(string).await } diff --git a/src/downloaders/mod.rs b/src/downloaders/mod.rs index 81294e4..79ccbd3 100644 --- a/src/downloaders/mod.rs +++ b/src/downloaders/mod.rs @@ -8,4 +8,4 @@ pub(crate) mod bungeecord; pub(crate) mod velocity; pub(crate) mod waterfall; pub(crate) mod geyser; -pub(crate) mod purpur; +pub(crate) mod purpur; \ No newline at end of file diff --git a/src/downloaders/neoforge.rs b/src/downloaders/neoforge.rs index cc1e6d0..4c7cef4 100644 --- a/src/downloaders/neoforge.rs +++ b/src/downloaders/neoforge.rs @@ -1,6 +1,7 @@ use std::fs::File; use std::io::Read; use async_trait::async_trait; +use reqwest::Client; use serde_json::Value; use tokio::fs; use xml2json_rs::JsonBuilder; @@ -28,11 +29,26 @@ impl Installer for NeoForge { true } + async fn get_versions(&self, _client: Client) -> Vec { + let mut versions: Vec = vec![]; + + for version in get_version_array().await { + let array = version.as_str().unwrap().split('.').collect::>(); + let full_string = format!("1.{}", array[0].to_string() + "." + array[1]); + + if !versions.contains(&full_string) { + versions.push(full_string); + } + } + + versions + } + async fn startup_message(&self, string: String) -> Option { crate::downloader::basic_server_address_from_string(string).await } - async fn download(&self, client: reqwest::Client, minecraft_version: Option) -> Result { + async fn download(&self, client: Client, minecraft_version: Option) -> Result { let neo_version = get_neoforge_version(minecraft_version).await.expect("Failed to get latest NeoForge version"); println!("Using NeoForge version {}.", neo_version); diff --git a/src/downloaders/paper.rs b/src/downloaders/paper.rs index 58b2b50..57589f7 100644 --- a/src/downloaders/paper.rs +++ b/src/downloaders/paper.rs @@ -28,6 +28,20 @@ impl Installer for Paper { false } + async fn get_versions(&self, client: Client) -> Vec { + let json: serde_json::Value = client.get("https://papermc.io/api/v2/projects/paper").send().await.expect("Failed to get latest version for Paper").json().await.expect("Failed to get latest version for Paper"); + + let versions = json["versions"].as_array().unwrap(); + let mut version_strings = Vec::new(); + + for version in versions { + let version_string = version.as_str().unwrap().to_string(); + version_strings.push(version_string); + } + + version_strings + } + async fn startup_message(&self, string: String) -> Option { basic_server_address_from_string(string).await } diff --git a/src/downloaders/purpur.rs b/src/downloaders/purpur.rs index babc187..59b6f1a 100644 --- a/src/downloaders/purpur.rs +++ b/src/downloaders/purpur.rs @@ -29,6 +29,20 @@ impl Installer for Purpur { false } + async fn get_versions(&self, client: Client) -> Vec { + let json: serde_json::Value = client.get("https://api.purpurmc.org/v2/purpur/").send().await.expect("Failed to get latest version for Purpur").json().await.expect("Failed to get latest version for Purpur"); + + let versions = json["versions"].as_array().unwrap(); + let mut version_strings = Vec::new(); + + for version in versions { + let version_string = version.as_str().unwrap().to_string(); + version_strings.push(version_string); + } + + version_strings + } + async fn startup_message(&self, string: String) -> Option { basic_server_address_from_string(string).await } diff --git a/src/downloaders/vanilla.rs b/src/downloaders/vanilla.rs index e832708..fd60625 100644 --- a/src/downloaders/vanilla.rs +++ b/src/downloaders/vanilla.rs @@ -26,6 +26,10 @@ impl Installer for Vanilla { false } + async fn get_versions(&self, _client: Client) -> Vec { + vec!["All Versions".to_string()] // Literally all versions. This is a Vanilla server, after all. + } + async fn startup_message(&self, string: String) -> Option { basic_server_address_from_string(string).await } diff --git a/src/downloaders/velocity.rs b/src/downloaders/velocity.rs index 29a56ed..0e2c562 100644 --- a/src/downloaders/velocity.rs +++ b/src/downloaders/velocity.rs @@ -32,6 +32,14 @@ impl Installer for Velocity { false } + async fn get_versions(&self, client: Client) -> Vec { + let json: serde_json::Value = client.get("https://papermc.io/api/v2/projects/velocity").send().await.expect("Failed to get latest version for Velocity").json().await.expect("Failed to get latest version for Velocity"); + + let versions = json["versions"].as_array().unwrap().last(); + + vec![versions.unwrap().as_str().unwrap().to_string()] + } + async fn startup_message(&self, string: String) -> Option { basic_proxy_address_from_string(string).await } diff --git a/src/downloaders/waterfall.rs b/src/downloaders/waterfall.rs index 46d4e96..e26056f 100644 --- a/src/downloaders/waterfall.rs +++ b/src/downloaders/waterfall.rs @@ -28,6 +28,20 @@ impl Installer for Waterfall { false } + async fn get_versions(&self, client: Client) -> Vec { + let json: serde_json::Value = client.get("https://papermc.io/api/v2/projects/waterfall").send().await.expect("Failed to get latest version for Waterfall").json().await.expect("Failed to get latest version for Waterfall"); + + let versions = json["versions"].as_array().unwrap(); + let mut version_strings = Vec::new(); + + for version in versions { + let version_string = version.as_str().unwrap().to_string(); + version_strings.push(version_string); + } + + version_strings + } + async fn startup_message(&self, string: String) -> Option { basic_server_address_from_string(string).await } diff --git a/src/main.rs b/src/main.rs index 9eac871..71bdce2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -151,19 +151,40 @@ async fn main() { let client = Client::new(); - println!("What kind of server do you want to run?"); - println!("Servers:" ); + let mut out_string: Vec = vec![]; + + println!("Gathering server information..."); + + out_string.push("Servers:".to_string()); let server_downloaders = downloaders.iter().filter(|downloader| downloader.get_type() == Server).collect::>>(); for (mut index, downloader) in server_downloaders.iter().enumerate() { + let mut versions = downloader.get_versions(client.clone()).await; + + if versions.len() > 20 { + versions = vec![format!("Too many versions, type {}V to list.", index + 1)]; + } + index += 1; - println!(" {}. {} - {}", index, downloader.get_name(), downloader.get_description()); + out_string.push(format!(" {}. {} - {} - [{}]", index, downloader.get_name(), downloader.get_description(), versions.join(", "))); } - println!("Proxies:"); + out_string.push("Proxies:".to_string()); let proxy_downloaders = downloaders.iter().filter(|downloader| downloader.get_type() == Proxy).collect::>>(); for (mut index, downloader) in proxy_downloaders.iter().enumerate() { + let mut versions = downloader.get_versions(client.clone()).await; + + if versions.len() > 20 { + versions = vec![format!("Too many versions, type {}V to list.", index + 1)]; + } + index += 1; - println!(" {}. {} - {}", index + server_downloaders.len(), downloader.get_name(), downloader.get_description()); + out_string.push(format!(" {}. {} - {} - [{}]", index + server_downloaders.len(), downloader.get_name(), downloader.get_description(), versions.join(", "))); + } + + println!("What kind of server do you want to run?"); + + for line in out_string { + println!("{}", line); } println!(); @@ -176,7 +197,45 @@ async fn main() { Ok(value) => !(1..=total_types).contains(&value), Err(_) => true, } { - print!("Please enter a valid number: "); + if server_type.ends_with('V') || server_type.ends_with('v') { + let index = server_type.replace(['V', 'v'], "").parse::().expect("Failed to parse index"); + let downloader = downloaders.get(index - 1).expect("Failed to get downloader"); + + let versions = downloader.get_versions(client.clone()).await; + let mut out_string: Vec = vec![]; + + for version in versions { + let start = if version.contains('.') { + let version_string = version.split('.').collect::>().first().unwrap().to_string() + "." + version.split('.').collect::>().get(1).unwrap().split('-').collect::>().first().unwrap(); + version_string + } else { + version.split('w').collect::>().first().unwrap().to_string() + }; + + if out_string.iter().any(|s| s.starts_with(start.as_str())) { + out_string = out_string.iter().map(|s| { + if s.starts_with(start.as_str()) { + format!("{}, {}", s, version) + } else { + s.to_string() + } + }).collect::>(); + } else { + out_string.push(version); + } + } + + println!("Versions for {}:", downloader.get_name()); + for version in out_string { + println!("{}", version); + println!(); + } + + print!("Enter the number of the server you want to run: (1-{}): ", downloaders.len()); + } else { + print!("Please enter a valid number: "); + } + server_type = user_input(); }