Added downloading java

This commit is contained in:
Quentin Legot 2023-10-04 16:48:46 +02:00
parent 6ec89497cb
commit affa6d8535
6 changed files with 114 additions and 11 deletions

25
src-tauri/Cargo.lock generated
View File

@ -68,6 +68,17 @@ version = "1.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6"
[[package]]
name = "async-trait"
version = "0.1.73"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.37",
]
[[package]] [[package]]
name = "atk" name = "atk"
version = "0.15.1" version = "0.15.1"
@ -1593,6 +1604,7 @@ dependencies = [
"reqwest", "reqwest",
"serde", "serde",
"serde_json", "serde_json",
"sha256",
"tauri", "tauri",
"tauri-build", "tauri-build",
"tokio", "tokio",
@ -2890,6 +2902,19 @@ dependencies = [
"digest", "digest",
] ]
[[package]]
name = "sha256"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7895c8ae88588ccead14ff438b939b0c569cd619116f14b4d13fdff7b8333386"
dependencies = [
"async-trait",
"bytes",
"hex",
"sha2",
"tokio",
]
[[package]] [[package]]
name = "sharded-slab" name = "sharded-slab"
version = "0.1.6" version = "0.1.6"

View File

@ -26,6 +26,7 @@ warp = "0.3.3"
anyhow = "1.0.66" anyhow = "1.0.66"
rand = "0.8.5" rand = "0.8.5"
directories = "5.0.0" directories = "5.0.0"
sha256 = "1.4.0"
[features] [features]
# by default Tauri runs in production mode # by default Tauri runs in production mode

View File

@ -106,6 +106,7 @@ pub enum OSName {
Windows Windows
} }
#[derive(Serialize, Deserialize)] #[derive(Serialize, Deserialize)]
pub struct LibraryArtifact { pub struct LibraryArtifact {
pub path: String, pub path: String,

View File

@ -6,11 +6,11 @@ use std::path::{Path, self, PathBuf};
use anyhow::{Result, bail}; use anyhow::{Result, bail};
use reqwest::{Client, StatusCode}; use reqwest::{Client, StatusCode};
use serde::{Serialize, Deserialize}; use serde::{Serialize, Deserialize};
use tokio::{fs::{self, File}, io::{AsyncWriteExt, AsyncSeekExt}, sync::mpsc}; use tokio::{fs::{self, File, OpenOptions}, io::{AsyncWriteExt, AsyncSeekExt}, sync::mpsc};
use crate::authentification::GameProfile; use crate::authentification::GameProfile;
use self::manifest::{VersionDetail, get_version_manifest, get_version_from_manifest, get_version_detail, Library, OSName, get_version_assets, AssetsManifest}; use self::{manifest::{VersionDetail, get_version_manifest, get_version_from_manifest, get_version_detail, Library, OSName, get_version_assets, AssetsManifest}, altarik::Chapter};
#[cfg(target_os="windows")] #[cfg(target_os="windows")]
@ -20,6 +20,9 @@ const ACTUAL_OS: OSName = OSName::Linux;
#[cfg(target_os="macos")] #[cfg(target_os="macos")]
const ACTUAL_OS: OSName = OSName::MacOsX; const ACTUAL_OS: OSName = OSName::MacOsX;
#[cfg(not(any(target_arch="x86_64", target_arch="x86")))]
compile_error!("Your architecture is not supported");
#[derive(Clone, serde::Serialize, Debug)] #[derive(Clone, serde::Serialize, Debug)]
pub struct ProgressMessage { pub struct ProgressMessage {
p_type: String, p_type: String,
@ -32,6 +35,7 @@ pub struct ClientOptions<'a> {
pub log_channel: mpsc::Sender<ProgressMessage>, pub log_channel: mpsc::Sender<ProgressMessage>,
pub root_path: &'a Path, pub root_path: &'a Path,
pub java_path: &'a Path, pub java_path: &'a Path,
/// deprecated, will be remove
pub version_number: String, pub version_number: String,
pub version_type: VersionType, pub version_type: VersionType,
// version_custom: String, // for a next update // version_custom: String, // for a next update
@ -73,7 +77,8 @@ impl<'a> MinecraftClient<'_> {
let folders = vec![ let folders = vec![
self.opts.root_path.join("libraries"), self.opts.root_path.join("libraries"),
self.opts.root_path.join("assets").join("objects"), self.opts.root_path.join("assets").join("objects"),
self.opts.root_path.join("assets").join("indexes") self.opts.root_path.join("assets").join("indexes"),
self.opts.root_path.join("runtime").join("download"),
]; ];
let mut tasks = Vec::with_capacity(folders.len()); let mut tasks = Vec::with_capacity(folders.len());
for folder in folders { for folder in folders {
@ -102,18 +107,73 @@ impl<'a> MinecraftClient<'_> {
} }
} }
pub async fn download_requirements(&mut self) -> Result<()> { pub async fn download_requirements(&mut self, chapter: Chapter) -> Result<()> {
// create root folder if it doesn't exist // create root folder if it doesn't exist
self.create_dirs().await?; self.create_dirs().await?;
let lib = &self.opts.root_path.join("libraries"); let lib = &self.opts.root_path.join("libraries");
let asset = &self.opts.root_path.join("assets").join("objects"); let asset = &self.opts.root_path.join("assets").join("objects");
self.save_version_index().await?; self.save_version_index().await?;
self.download_java(chapter).await?;
self.download_libraries(lib).await?; self.download_libraries(lib).await?;
self.download_assets(asset).await?; self.download_assets(asset).await?;
self.opts.log_channel.send(ProgressMessage { p_type: "completed".to_string(), current: 0, total: 0 }).await?; self.opts.log_channel.send(ProgressMessage { p_type: "completed".to_string(), current: 0, total: 0 }).await?;
Ok(()) Ok(())
} }
async fn download_java(&mut self, chapter: Chapter) -> Result<()> {
let download_path = self.opts.root_path.join("runtime").join("download");
// let extract_path = self.opts.root_path.join("runtime");
let (url, extension) = match ACTUAL_OS {
OSName::Linux => {
(chapter.java.platform.linux, "tar.gz")
},
OSName::Windows => {
(chapter.java.platform.win32, "zip")
},
_ => {
bail!("Your current is not supported")
}
};
let url = match url {
Some(url) => url,
None => bail!("No available executable available for your platform")
};
let filepath = download_path.join(format!("{}.{}", url.x64.name.clone(), extension));
let mut should_download = false;
if !filepath.exists() {
should_download = true;
} else {
let hash = sha256::try_digest(filepath.clone());
match hash {
Ok(hash) => {
if hash != url.x64.sha256sum {
println!("Hash of java archive is not correct, redownloading");
should_download = true;
}
},
Err(_) => should_download = true
}
}
if should_download {
println!("Downloading java");
if filepath.exists() {
fs::remove_file(filepath.clone()).await?; // remove content before writing and appending to it
}
let mut file = OpenOptions::new()
.write(true)
.create(true)
.open(filepath)
.await?;
let b = self.reqwest_client.get(url.x64.link.clone()).send().await?.bytes().await?;
file.write(&b).await?;
println!("{} downloaded", url.x64.name)
} else {
println!("{} already downloaded", url.x64.name)
}
Ok(())
}
async fn download_libraries(&mut self, lib: &PathBuf) -> Result<()> { async fn download_libraries(&mut self, lib: &PathBuf) -> Result<()> {
self.filter_non_necessary_librairies(); self.filter_non_necessary_librairies();
let total = self.details.libraries.len(); let total = self.details.libraries.len();

View File

@ -11,7 +11,7 @@ use std::sync::Mutex;
use authentification::{Authentification, Prompt, GameProfile}; use authentification::{Authentification, Prompt, GameProfile};
use anyhow::Result; use anyhow::Result;
use directories::BaseDirs; use directories::BaseDirs;
use launcher::{MinecraftClient, ClientOptions, ProgressMessage, altarik::AltarikManifest}; use launcher::{MinecraftClient, ClientOptions, ProgressMessage, altarik::{AltarikManifest, Chapter}};
use reqwest::Client; use reqwest::Client;
use tauri::Manager; use tauri::Manager;
use tokio::sync::mpsc; use tokio::sync::mpsc;
@ -62,7 +62,23 @@ async fn load_altarik_manifest(state: tauri::State<'_, Mutex<CustomState>>) -> R
} }
#[tauri::command] #[tauri::command]
async fn download(game_version: String, app: tauri::AppHandle, state: tauri::State<'_, Mutex<CustomState>>) -> Result<String, String> { async fn download(selected_chapter: usize, app: tauri::AppHandle, state: tauri::State<'_, Mutex<CustomState>>) -> Result<String, String> {
let chapter = match state.lock() {
Ok(lock) => {
match &lock.1 {
Some(manifest) => {
match manifest.chapters.get(selected_chapter) {
Some(val) => {
val.clone()
},
None => return Err("Selected chapter doesn't exist".to_string())
}
},
None => return Err("Cannot load altarik manifest".to_string())
}
},
Err(err) => return Err(err.to_string())
};
if let Some(base_dir) = BaseDirs::new() { if let Some(base_dir) = BaseDirs::new() {
let data_folder = base_dir.data_dir().join(".altarik_test"); let data_folder = base_dir.data_dir().join(".altarik_test");
let root_path = data_folder.as_path(); let root_path = data_folder.as_path();
@ -80,14 +96,14 @@ async fn download(game_version: String, app: tauri::AppHandle, state: tauri::Sta
log_channel: sender.clone(), log_channel: sender.clone(),
root_path, root_path,
java_path: &java_path.as_path(), java_path: &java_path.as_path(),
version_number: game_version, version_number: chapter.minecraft_version.clone(),
version_type: launcher::VersionType::Release, version_type: launcher::VersionType::Release,
memory_min: "2G".to_string(), memory_min: "2G".to_string(),
memory_max: "4G".to_string(), memory_max: "4G".to_string(),
}; };
drop(sender); drop(sender);
let res = tokio::join!( let res = tokio::join!(
download_libraries(opts), download_libraries(opts, chapter),
read_channel(receiver, app), read_channel(receiver, app),
); );
res.0 res.0
@ -97,11 +113,11 @@ async fn download(game_version: String, app: tauri::AppHandle, state: tauri::Sta
} }
async fn download_libraries(opts: ClientOptions<'_>) -> Result<String, String> { async fn download_libraries(opts: ClientOptions<'_>, chapter: Chapter) -> Result<String, String> {
let client = MinecraftClient::new(&opts).await; let client = MinecraftClient::new(&opts).await;
let res = match client { let res = match client {
Ok(mut client) => { Ok(mut client) => {
match client.download_requirements().await { match client.download_requirements(chapter).await {
Ok(_) => { Ok(_) => {
Ok("Content downloaded".to_string()) Ok("Content downloaded".to_string())
}, },

View File

@ -55,7 +55,7 @@ export default function LoginPage() {
async function download() { async function download() {
if(isLogged) { if(isLogged) {
if(selectedChapter !== -1 && altarikManifest !== undefined) { if(selectedChapter !== -1 && altarikManifest !== undefined) {
invoke("download", { gameVersion: altarikManifest?.chapters[selectedChapter].minecraftVersion }).then(value => { invoke("download", { selectedChapter: selectedChapter }).then(value => {
setGreetMessage(String(value)) setGreetMessage(String(value))
}).catch(err => { }).catch(err => {
console.log("An error occured") console.log("An error occured")