diff --git a/launcher/Cargo.toml b/launcher/Cargo.toml index f010405..dfcd83b 100644 --- a/launcher/Cargo.toml +++ b/launcher/Cargo.toml @@ -4,5 +4,9 @@ version = "0.1.0" edition = "2021" [dependencies] +dirs = "5.0.1" +flate2 = "1.0.30" serde_json = "1.0.117" suppaftp = { version = "6.0.1", features = ["native-tls"] } +tar = "0.4.41" +zip-extract = "0.1.3" diff --git a/launcher/src/ftp.rs b/launcher/src/ftp.rs index ca4f95c..ea1d263 100644 --- a/launcher/src/ftp.rs +++ b/launcher/src/ftp.rs @@ -1,3 +1,6 @@ +use std::io::Write; +use std::path::PathBuf; + use suppaftp::FtpError; use suppaftp::NativeTlsFtpStream; use suppaftp::NativeTlsConnector; @@ -5,7 +8,12 @@ use suppaftp::native_tls::Certificate; use suppaftp::native_tls::TlsConnector; -fn ftpConnection() -> Result{ +fn ftp_connection_anonymous() -> Result{ + ftp_connection("anonymous", "anonymous@") +} + + +fn ftp_connection(username: &str, password: &str) -> Result{ let ftp_stream = NativeTlsFtpStream::connect("gitea.piwalker.net:21").unwrap_or_else(|err| panic!("{}", err) ); @@ -16,3 +24,33 @@ fn ftpConnection() -> Result{ } +pub fn ftp_retr(file: PathBuf , mut writer: impl Write, mut callback: impl FnMut(usize)) -> Result { + let mut ftp_stream = ftp_connection_anonymous().unwrap(); + let file = file.to_str().unwrap().replace("\\", "/"); + let size = ftp_stream.size(&file)?; + let mut total = 0; + ftp_stream.retr(file.as_str(), |stream| { + let mut tx_bytes = [0u8; 1500]; + loop { + let bytes_read = stream.read(&mut tx_bytes).unwrap(); + writer.write_all(&mut tx_bytes.split_at(bytes_read).0).unwrap(); + total += bytes_read; + if total == size || bytes_read == 0 { + break; + }else{ + callback(bytes_read); + } + } + Ok(true) + })?; + Ok(true) + +} + +pub fn ftp_get_size(file: PathBuf) -> Result { + let mut stream = ftp_connection_anonymous()?; + stream.size(file.to_str().unwrap().replace("\\", "/")) +} + + + diff --git a/launcher/src/java.rs b/launcher/src/java.rs new file mode 100644 index 0000000..7c9be22 --- /dev/null +++ b/launcher/src/java.rs @@ -0,0 +1,54 @@ +use std::env; +use std::io::{Cursor, Seek, Read}; +use std::path::{Components, Path, PathBuf}; +use flate2::read::GzDecoder; +use tar::Archive; + + +use crate::system_dirs::get_local_data_directory; +use crate::ftp::{self, ftp_get_size}; +use crate::util; + +fn check_java(version: u8) -> bool { + let dir = get_local_data_directory().join("java").join(format!("java-{}-{}", version, if env::consts::OS == "windows" { "win" } else {"lin"})); + dir.exists() +} + +pub fn install_java(version: u8) { + if check_java(version) { + return; + } + let ftp_dir = PathBuf::new().join("java").join(format!("java-{}-{}", version, if env::consts::OS == "windows" { "win.zip" } else {"lin.tar.gz"})); + let mut buff = Cursor::new(vec![]); + let mut total: usize = 0; + let size = ftp_get_size(ftp_dir.clone()).unwrap(); + ftp::ftp_retr(ftp_dir, &mut buff, |data| util::download_callback(data, &mut total, size)).unwrap(); + + std::fs::create_dir_all(get_local_data_directory().join("java").join(format!("java-{}-{}", version, if env::consts::OS == "windows" { "win" } else {"lin"}))).unwrap(); + buff.rewind().unwrap(); + if env::consts::OS != "windows" { + let tar = GzDecoder::new(buff); + let mut archive = Archive::new(tar); + if !unpack_archive(archive, get_local_data_directory().join("java").join(format!("java-{}-lin", version))).is_ok() { + std::fs::remove_dir_all(get_local_data_directory().join("java").join(format!("java-{}-lin", version))).unwrap(); + } + } else { + if !zip_extract::extract(buff, get_local_data_directory().join("java").join(format!("java-{}-win", version)).as_path(), true).is_ok() { + std::fs::remove_dir_all(get_local_data_directory().join("java").join(format!("java-{}-win", version))).unwrap(); + } + } + +} + +fn unpack_archive(mut archive: Archive, dst: PathBuf) -> Result<(), Box> { + for file in archive.entries()? { + let path = PathBuf::new().join(dst.clone()); + let mut file = file?; + let file_path = file.path()?; + let mut file_path = file_path.components(); + let _ = file_path.next(); + let file_path = file_path.as_path(); + file.unpack(path.join(file_path))?; + } + Ok(()) +} diff --git a/launcher/src/main.rs b/launcher/src/main.rs index f6bb127..2734a18 100644 --- a/launcher/src/main.rs +++ b/launcher/src/main.rs @@ -1,37 +1,32 @@ use std::fs::File; -use std::io::{Read, Write}; +use std::io::{Cursor, Read, Seek, Write}; use std::env::temp_dir; -use std::path::Path; +use std::path::{Path, PathBuf}; use serde_json::{Result, Value}; - -use suppaftp::{FtpError, NativeTlsConnector, NativeTlsFtpStream}; -use suppaftp::native_tls::{Certificate, TlsConnector}; +use std::process::Command; +use std::process::Child; mod ftp; +mod prism; +mod system_dirs; +mod java; +mod util; + fn main() { - println!("test"); - let ftp_stream = NativeTlsFtpStream::connect("gitea.piwalker.net:21").unwrap_or_else(|err| - panic!("{}", err) - ); - let cert = include_bytes!("../res/vsftpd.crt"); - let cert = Certificate::from_pem(cert).unwrap(); - let mut ftp_stream = ftp_stream.into_secure(NativeTlsConnector::from(TlsConnector::builder().add_root_certificate(cert).build().unwrap()), "gitea.piwalker.net").unwrap(); - assert!(ftp_stream.login("anonymous", "anonymous@").is_ok()); - assert!(ftp_stream.size("test").is_ok()); - println!("test"); - let data = ftp_stream.retr_as_buffer("fcs7/versions.json").unwrap(); - println!("test"); - let v: Value = serde_json::from_reader(data).unwrap(); - println!("fcs7/{}",v[0]["File"].as_str().unwrap()); - let mut data = ftp_stream.retr_as_buffer(format!("fcs7/{}",v[v.as_array().unwrap().len()-1]["File"].as_str().unwrap()).as_str()).unwrap_or_else(|err| panic!("Unable to download file")); - println!("{}", temp_dir().join("pack.mrpack").display()); - let mut file = File::create(temp_dir().join("pack.mrpack")).unwrap(); - std::io::copy(&mut data, &mut file).unwrap(); - println!("{}",temp_dir().display()); - + prism::install_prism().unwrap(); + //let mut data = Cursor::new(vec![]); + //ftp::ftpRetr(PathBuf::new().join("fcs7").join("versions.json"), &mut data, |_| return).unwrap(); + //data.seek(std::io::SeekFrom::Start(0)).unwrap(); + //let v: Value = serde_json::from_reader(data).unwrap(); + //println!("fcs7/{}",v[v.as_array().unwrap().len()-1]["File"].as_str().unwrap()); + //println!("{}", temp_dir().join("pack.mrpack").display()); + //let mut file = File::create(temp_dir().join("pack.mrpack")).unwrap(); + //ftp::ftpRetr(PathBuf::new().join("fcs7").join(v[v.as_array().unwrap().len()-1]["File"].as_str().unwrap()),file, |data| println!("Transferred {} Bytes", data)).unwrap(); + //let output = Command::new("prismlauncher").arg("-I").arg(temp_dir().join("pack.mrpack")).spawn(); - assert!(ftp_stream.quit().is_ok()); } + +pub fn test(){} diff --git a/launcher/src/prism.rs b/launcher/src/prism.rs new file mode 100644 index 0000000..3772ca3 --- /dev/null +++ b/launcher/src/prism.rs @@ -0,0 +1,45 @@ +use std::{env, io::{Cursor, Seek}, path::PathBuf}; +use flate2::read::GzDecoder; +use tar::Archive; + +use crate::{ftp, java, system_dirs::get_local_data_directory}; + + +pub fn check_prism() -> bool { + let path = get_local_data_directory().join("prism"); + path.exists() +} + +pub fn install_prism() -> Result<(), Box>{ + if check_prism() { + return Ok(()); + } + java::install_java(21); + let path = PathBuf::new().join("prism").join(format!("prism-{}",if env::consts::OS == "windows" {"win.zip"} else {"lin.tar.gz"})); + let size = ftp::ftp_get_size(path.clone())?; + let mut buff = Cursor::new(vec![]); + let mut total = 0; + ftp::ftp_retr(path, &mut buff, |data| { + total += data; + println!("Downloading Prism: {}MB / {}MB", total/(1024*1024), size/(1024*1024)); + }).unwrap(); + std::fs::create_dir_all(get_local_data_directory().join("prism"))?; + buff.rewind()?; + if env::consts::OS != "windows" { + let tar = GzDecoder::new(buff); + let mut archive = Archive::new(tar); + if !archive.unpack(get_local_data_directory().join("prism")).is_ok() { + std::fs::remove_dir_all(get_local_data_directory().join("prism")); + } + } else { + if !zip_extract::extract(buff, get_local_data_directory().join("prism").as_path(), true).is_ok() { + std::fs::remove_dir_all(get_local_data_directory().join("prism")); + } + } + + let buff = Cursor::new(vec![]); + ftp::ftp_retr(PathBuf, writer, callback) + + + Ok(()) +} diff --git a/launcher/src/system_dirs.rs b/launcher/src/system_dirs.rs new file mode 100644 index 0000000..ba67006 --- /dev/null +++ b/launcher/src/system_dirs.rs @@ -0,0 +1,8 @@ +use std::{env, path::{Path, PathBuf}}; +use dirs::home_dir; + + + +pub fn get_local_data_directory() -> PathBuf { + dirs::data_local_dir().unwrap().join("FCLauncher") +} diff --git a/launcher/src/util.rs b/launcher/src/util.rs new file mode 100644 index 0000000..3195d68 --- /dev/null +++ b/launcher/src/util.rs @@ -0,0 +1,6 @@ + +pub fn download_callback(count: usize, total: &mut usize, size: usize){ + *total += count; + println!("Downloading {}MB / {}MB", *total/(1024*1024), size/(1024*1024)); +} +