use crate::https; use crate::java; use crate::system_dirs::{ get_data_directory, get_java_executable, get_local_data_directory, get_prism_executable, }; use crate::util; use reqwest::IntoUrl; use serde::de::value::Error; use serde::Deserialize; use serde::Serialize; use serde_json::Value; use std::fs; use std::fs::File; use std::io::{Read, Seek, Write}; use std::process::Command; use std::time::Duration; use std::{env, thread}; use std::{io::Cursor, path::PathBuf}; #[derive(Serialize, Deserialize, Clone)] pub struct ModpackEntry { pub name: String, pub id: String, pub last_updated: String, } #[derive(Serialize, Deserialize, Clone)] pub struct VersionEntry { pub Version: String, pub File: String, pub Date: String, } async fn get_modpack_name(id: String) -> String { let modpacks = get_modpacks().await; let mut instance_name = String::new(); for pack in modpacks { if pack.id == id { instance_name = pack.name; } } return instance_name; } async fn check_modpack_needs_update(id: String) -> bool { let mut instance_name = get_modpack_name(id.clone()).await; if !get_local_data_directory() .join("prism") .join("instances") .join(&mut instance_name) .exists() { return true; } let versions = get_versions(id).await; if !versions.is_ok() { return false; } let versions = versions.unwrap(); let latest = versions[versions.len() - 1].Version.clone(); let mut file = File::open( get_local_data_directory() .join("prism") .join("instances") .join(instance_name) .join(".minecraft") .join("version.txt"), ) .unwrap(); let mut current = String::new(); file.read_to_string(&mut current); if latest != current { return true; } return false; } #[tauri::command] pub async fn launch_modpack(window: tauri::AppHandle, id: String) { if check_modpack_needs_update(id.clone()).await { install_modpack(window, id.clone()).await; } // Launch let mut child = Command::new( get_local_data_directory() .join("prism") .join(get_prism_executable()), ) .arg("-l") .arg(get_modpack_name(id).await) .spawn() .unwrap(); } async fn install_modpack(window: tauri::AppHandle, id: String) { let versions = get_versions(id.clone()).await.unwrap(); let path = env::temp_dir().join(format!("{}.mrpack", get_modpack_name(id.clone()).await)); let mut file = File::create(path.clone()).unwrap(); let ftp_path = PathBuf::new() .join(id.clone()) .join(versions[versions.len() - 1].File.clone().as_str()); println!("Downloading file {}", ftp_path.to_str().unwrap()); //ftp::ftp_retr(Some(window.clone()), ftp_path, &mut file, |window, data, size| util::download_callback(name.clone(), window, data, size)).unwrap(); https::download( Some(window.clone()), format!( "https://gitea.piwalker.net/fclauncher/{}/{}", id.clone(), versions[versions.len() - 1].File.clone() ), &mut file, get_modpack_name(id.clone()).await, ) .await; let mut child = Command::new( get_local_data_directory() .join("prism") .join(get_prism_executable()), ) .arg("-I") .arg(path) .spawn() .unwrap(); loop { let version_path = get_local_data_directory() .join("prism") .join("instances") .join(get_modpack_name(id.clone()).await) .join(".minecraft") .join("version.txt"); if version_path.clone().exists() { let mut ver_file = File::open(version_path).unwrap(); let mut buf = String::new(); ver_file.read_to_string(&mut buf).unwrap(); if buf == versions[versions.len() - 1].Version.clone().as_str() { break; } } thread::sleep(Duration::from_secs(3)); } thread::sleep(Duration::from_secs(1)); child.kill(); let info_path = get_local_data_directory() .join("prism") .join("instances") .join(get_modpack_name(id.clone()).await) .join("mmc-pack.json"); let mut info_file = File::open(info_path.clone()).unwrap(); let info_json: Value = serde_json::from_reader(info_file).unwrap(); let mut mc_version = "0.0"; for component in info_json["components"].as_array().unwrap() { if component["uid"] == "net.minecraft" { mc_version = component["version"].as_str().unwrap(); } } let java = get_java_version(mc_version); java::install_java(java, window.clone()).await; let option_path = get_local_data_directory() .join("prism") .join("instances") .join(get_modpack_name(id.clone()).await) .join("instance.cfg"); let mut option_file = File::open(option_path.clone()).unwrap(); let mut buf = String::new(); option_file.read_to_string(&mut buf); let mut option_file = File::create(option_path).unwrap(); let mut set = false; for line in buf.lines() { if line.starts_with("JavaPath=") { option_file.write_all( format!( "JavaPath={}/java-{}-{}/bin/{}\n", get_local_data_directory() .join("java") .into_os_string() .to_str() .unwrap() .replace("\\", "/"), java, if env::consts::OS == "windows" { "win" } else { "lin" }, get_java_executable() ) .as_bytes(), ); set = true; } else { option_file.write_all(format!("{}\n", line).as_bytes()); } } if !set { option_file.write_all( format!( "JavaPath={}/java-{}-{}/bin/{}\n", get_local_data_directory() .join("java") .into_os_string() .to_str() .unwrap() .replace("\\", "/"), java, if env::consts::OS == "windows" { "win" } else { "lin" }, get_java_executable() ) .as_bytes(), ); option_file.write_all("OverrideJavaLocation=true\n".as_bytes()); option_file.write_all("OverrideJava=true\n".as_bytes()); } } #[tauri::command] pub async fn get_modpacks() -> Vec { //unsafe{ let mut modpacks: Vec = Vec::new(); //if modpacks.is_empty() { let mut buf = Cursor::new(vec![]); //ftp::ftp_retr(None, PathBuf::new().join("modpacks.json"), &mut buf, |_, _, _| return); https::download( None, format!("https://gitea.piwalker.net/fclauncher/modpacks.json"), &mut buf, format!("modpacks.json"), ) .await; buf.rewind(); let res = serde_json::from_reader(buf); if !res.is_ok() { println!("Result not ok!"); let paths = fs::read_dir(get_local_data_directory().join("prism").join("instances")).unwrap(); for path in paths { let path = path.unwrap(); if fs::metadata(path.path()).unwrap().is_file() { continue; } let name = path.file_name().into_string().unwrap(); if name.starts_with(".") { continue; } modpacks.push(ModpackEntry { name: name.clone(), id: name, last_updated: format!(""), }) } return modpacks.clone(); } let modpacks: Vec = res.unwrap(); //println!("{}", v[0].name); //for pack in v.as_array().unwrap() { //modpacks.push(ModpackEntry{name: pack["name"].as_str().unwrap().to_string(), id: pack["id"].as_str().unwrap().to_string(), last_updated: pack["last-updated"].as_str().unwrap().to_string()}); //} //} return modpacks.clone(); //} } #[tauri::command] pub async fn get_versions(id: String) -> Result, String> { let mut versions: Vec = Vec::new(); let mut buf = Cursor::new(vec![]); //ftp::ftp_retr(None, PathBuf::new().join(id).join("versions.json"), &mut buf, |_, _, _| return); https::download( None, format!( "https://gitea.piwalker.net/fclauncher/{}/versions.json", id.clone() ), &mut buf, format!("{}/versions.json", id.clone()), ) .await; buf.rewind(); let versions: Vec = serde_json::from_reader(buf).or(Err(format!("Unable to parse json")))?; //for version in v.as_array().unwrap() { //versions.push(VersionEntry{version: version["Version"].as_str().unwrap().to_string(), file: version["File"].as_str().unwrap().to_string(), date: version["Date"].as_str().unwrap().to_string()}); //} return Ok(versions.clone()); } fn get_java_version(mc_version: &str) -> u8 { let components: Vec<&str> = mc_version.split(".").collect(); let mut java = 8; if components[1] == "17" { java = 17 } else if components[1] == "18" || components[1] == "19" { java = 17 } else if components[1].parse::().unwrap() > 19 { if components[1] == "20" && components[1].parse::().unwrap() < 5 { java = 17 } else { java = 21 } } return java; } #[tauri::command] pub async fn get_latest_version(id: String) -> Result { let versions = get_versions(id).await.unwrap(); if (versions.len() == 0) { return Ok(format!("")); } Ok(versions[versions.len() - 1].Version.clone()) } //pub fn create_json(modpacks: Vec) -> Result { //}