Skip to content

Commit

Permalink
feat: re-try webview download and log to console
Browse files Browse the repository at this point in the history
  • Loading branch information
1zun4 committed Mar 22, 2024
1 parent aadbb70 commit 9614b01
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 33 deletions.
15 changes: 12 additions & 3 deletions src-tauri/src/app/gui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

use std::{sync::{Arc, Mutex}, thread, path::PathBuf};

use anyhow::anyhow;
use tokio::fs;
use tracing::{error, info, debug};
use tauri::{Manager, Window};
Expand Down Expand Up @@ -203,14 +204,22 @@ async fn delete_custom_mod(branch: &str, mc_version: &str, mod_name: &str) -> Re
Ok(())
}

pub fn log(window: &Arc<std::sync::Mutex<Window>>, msg: &str) {
info!("{}", msg);

if let Ok(k) = window.lock() {
let _ = k.emit("process-output", msg);
}
}

fn handle_stdout(window: &Arc<std::sync::Mutex<Window>>, data: &[u8]) -> anyhow::Result<()> {
let data = String::from_utf8(data.to_vec())?;
if data.is_empty() {
return Ok(()); // ignore empty lines
}

info!("{}", data);
window.lock().unwrap().emit("process-output", data)?;
window.lock().map_err(|_| anyhow!("Window lock is poisoned"))?.emit("process-output", data)?;
Ok(())
}

Expand All @@ -221,12 +230,12 @@ fn handle_stderr(window: &Arc<std::sync::Mutex<Window>>, data: &[u8]) -> anyhow:
}

error!("{}", data);
window.lock().unwrap().emit("process-output", data)?;
window.lock().map_err(|_| anyhow!("Window lock is poisoned"))?.emit("process-output", data)?;
Ok(())
}

fn handle_progress(window: &Arc<std::sync::Mutex<Window>>, progress_update: ProgressUpdate) -> anyhow::Result<()> {
window.lock().unwrap().emit("progress-update", progress_update)?;
window.lock().map_err(|_| anyhow!("Window lock is poisoned"))?.emit("progress-update", progress_update)?;
Ok(())
}

Expand Down
58 changes: 46 additions & 12 deletions src-tauri/src/app/webview.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,51 @@

use std::{sync::{atomic::{AtomicBool, Ordering}, Arc, Mutex}, time::Duration};
use serde::Deserialize;
use anyhow::{bail, Context, Result};
use anyhow::{anyhow, bail, Context, Result};
use tracing::{info, debug};
use tauri::{Manager, Url, WebviewUrl, WebviewWindowBuilder};
use tokio::time::sleep;
use crate::utils::download_file;
use crate::minecraft::progress::{ProgressReceiver, ProgressUpdate};

pub(crate) async fn download_client<F>(url: &str, on_progress: F, window: &Arc<Mutex<tauri::Window>>) -> Result<Vec<u8>> where F : Fn(u64, u64){
use super::gui::log;

const MAX_DOWNLOAD_ATTEMPTS: u8 = 5;

pub async fn open_download_page(url: &str, on_progress: &impl ProgressReceiver, window: &Arc<Mutex<tauri::Window>>) -> Result<String> {
let download_page: Url = format!("{}&liquidlauncher=1", url).parse()
.context("Failed to parse download page URL")?;

let mut count = 0;

let url = loop {
count += 1;

if count > MAX_DOWNLOAD_ATTEMPTS {
bail!("Failed to open download page after {} attempts", MAX_DOWNLOAD_ATTEMPTS);
}

log(&window, &format!("Opening download page... (Attempt {}/{})", count, MAX_DOWNLOAD_ATTEMPTS));
on_progress.progress_update(ProgressUpdate::SetLabel(format!("Opening download page... (Attempt {}/{})", count, MAX_DOWNLOAD_ATTEMPTS)));

match show_webview(download_page.clone(), window).await {
Ok(url) => break url,
Err(e) => {
log(&window, &format!("Failed to open download page: {}", e));
sleep(Duration::from_millis(500)).await;
}
}
};

Ok(url)
}

async fn show_webview(url: Url, window: &Arc<Mutex<tauri::Window>>) -> Result<String> {
let download_view = WebviewWindowBuilder::new(
window.lock().unwrap().app_handle(),
window.lock()
.map_err(|_| anyhow!("Unable to lock window due to poisoned mutex"))?
.app_handle(),
"download_view",
WebviewUrl::External(download_page)
WebviewUrl::External(url)
).title("Download of LiquidBounce")
.center()
.focused(true)
Expand Down Expand Up @@ -74,24 +106,26 @@ pub(crate) async fn download_client<F>(url: &str, on_progress: F, window: &Arc<M
});

let url = loop {
// sleep for 25ms
sleep(Duration::from_millis(25)).await;
// sleep for 100ms
sleep(Duration::from_millis(100)).await;

// check if we got the download link
if let Ok(mg) = download_link_cell.lock() {
if let Some(received) = mg.clone() {
break received;
if let Ok(link) = download_link_cell.lock() {
if let Some(link) = link.clone() {
break link;
}
}

if cloned_close_request.load(Ordering::SeqCst) {
bail!("Download view was closed before the download link was received. \
Aborting download...");
}

download_view.is_visible()
.context("Download view was closed unexpected")?;
};

let _ = download_view.destroy();

info!("Downloading LiquidBounce from {}", url);
return download_file(&url, on_progress).await;
Ok(url)
}
27 changes: 16 additions & 11 deletions src-tauri/src/minecraft/launcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,14 @@ use std::process::exit;
use std::sync::{Arc, Mutex};
use std::sync::atomic::{AtomicU64, Ordering};

use anyhow::{bail, Result};
use anyhow::{anyhow, bail, Result};
use futures::stream::{self, StreamExt};

use tracing::*;
use path_absolutize::*;
use tokio::{fs, fs::OpenOptions};

use crate::app::gui::log;
use crate::{utils::{OS, OS_VERSION}, LAUNCHER_VERSION};
use crate::app::api::LaunchManifest;
use crate::error::LauncherError;
Expand Down Expand Up @@ -61,8 +62,7 @@ pub async fn launch<D: Send + Sync>(data: &Path, manifest: LaunchManifest, versi
let launcher_data_arc = Arc::new(launcher_data);

let features: HashSet<String> = HashSet::new();

info!("Determined OS to be {} {}", OS, OS_VERSION.clone());
log(&window, &format!("Determined OS to be {} {}", OS, OS_VERSION.clone()));

// JRE download
let runtimes_folder = data.join("runtimes");
Expand All @@ -73,15 +73,15 @@ pub async fn launch<D: Send + Sync>(data: &Path, manifest: LaunchManifest, versi
let java_bin = match &launching_parameter.custom_java_path {
Some(path) => PathBuf::from(path),
None => {
info!("Checking for JRE...");
log(&window, "Checking for JRE...");
launcher_data_arc.progress_update(ProgressUpdate::set_label("Checking for JRE..."));

match find_java_binary(&runtimes_folder, &manifest.build.jre_distribution, &*manifest.build.jre_version.to_string()).await {
Ok(jre) => jre,
Err(e) => {
error!("Failed to find JRE: {}", e);
log(&window, &format!("Failed to find JRE: {}", e));

info!("Download JRE...");
log(&window, "Downloading JRE...");
launcher_data_arc.progress_update(ProgressUpdate::set_label("Download JRE..."));
jre_downloader::jre_download(&runtimes_folder, &manifest.build.jre_distribution, &*manifest.build.jre_version.to_string(), |a, b| {
launcher_data_arc.progress_update(ProgressUpdate::set_for_step(ProgressUpdateSteps::DownloadJRE, get_progress(0, a, b), get_max(1)));
Expand All @@ -90,8 +90,8 @@ pub async fn launch<D: Send + Sync>(data: &Path, manifest: LaunchManifest, versi
}
}
};
debug!("Java binary: {}", java_bin.to_str().unwrap());

log(&window, &format!("Java binary: {:?}", java_bin));
if !java_bin.exists() {
bail!("Java binary not found");
}
Expand Down Expand Up @@ -299,18 +299,23 @@ pub async fn launch<D: Send + Sync>(data: &Path, manifest: LaunchManifest, versi

launcher_data_arc.progress_update(ProgressUpdate::set_label("Launching..."));
launcher_data_arc.progress_update(ProgressUpdate::set_to_max());
log(&window, "Launching...");

let mut running_task = java_runtime.execute(mapped, &game_dir).await?;

launcher_data_arc.progress_update(ProgressUpdate::set_label("Running..."));

if !launching_parameter.keep_launcher_open {
// Hide launcher window
window.lock().unwrap().hide().unwrap();
if let Err(err) = window.lock()
.map_err(|_| anyhow!("Unable to lock window due to poisoned mutex"))?
.hide() {
error!("Failed to hide window: {}", err);
}
}

let launcher_data = Arc::try_unwrap(launcher_data_arc)
.unwrap_or_else(|_| panic!());
.map_err(|_| anyhow!("Failed to unwrap launcher data"))?;
let terminator = launcher_data.terminator;
let data = launcher_data.data;

Expand Down
22 changes: 15 additions & 7 deletions src-tauri/src/minecraft/prelauncher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,9 @@ use tokio::fs;
use tokio::io::AsyncReadExt;

use crate::app::api::{LaunchManifest, LoaderSubsystem, ModSource, LoaderMod};
use crate::app::gui::log;
use crate::error::LauncherError;
use crate::app::webview::download_client;
use crate::app::webview::open_download_page;
use crate::LAUNCHER_DIRECTORY;
use crate::minecraft::launcher;
use crate::minecraft::launcher::{LauncherData, LaunchingParameter};
Expand All @@ -40,7 +41,7 @@ use crate::utils::{download_file, get_maven_artifact_path};
/// Prelaunching client
///
pub(crate) async fn launch<D: Send + Sync>(launch_manifest: LaunchManifest, launching_parameter: LaunchingParameter, additional_mods: Vec<LoaderMod>, progress: LauncherData<D>, window: Arc<Mutex<tauri::Window>>) -> Result<()> {
info!("Loading minecraft version manifest...");
log(&window, "Loading minecraft version manifest...");
let mc_version_manifest = VersionManifest::fetch().await?;

let build = &launch_manifest.build;
Expand All @@ -59,7 +60,7 @@ pub(crate) async fn launch<D: Send + Sync>(launch_manifest: LaunchManifest, laun
retrieve_and_copy_mods(&data_directory, &launch_manifest, &launch_manifest.mods, &progress, &window).await?;
retrieve_and_copy_mods(&data_directory, &launch_manifest, &additional_mods, &progress, &window).await?;

info!("Loading version profile...");
log(&window, "Loading version profile...");
let manifest_url = match subsystem {
LoaderSubsystem::Fabric { manifest, .. } => manifest
.replace("{MINECRAFT_VERSION}", &build.mc_version)
Expand All @@ -76,14 +77,14 @@ pub(crate) async fn launch<D: Send + Sync>(launch_manifest: LaunchManifest, laun
.ok_or_else(|| LauncherError::InvalidVersionProfile(format!("unable to find inherited version manifest {}", inherited_version)))?;

debug!("Determined {}'s download url to be {}", inherited_version, url);
info!("Downloading inherited version {}...", inherited_version);
log(&window, &format!("Downloading inherited version {}...", inherited_version));

let parent_version = VersionProfile::load(url).await?;

version.merge(parent_version)?;
}

info!("Launching {}...", launch_manifest.build.commit_id);
log(&window, &format!("Launching {}...", launch_manifest.build.commit_id));
launcher::launch(&data_directory, launch_manifest, version, launching_parameter, progress, window).await?;
Ok(())
}
Expand Down Expand Up @@ -134,6 +135,7 @@ pub async fn retrieve_and_copy_mods(data: &Path, manifest: &LaunchManifest, mods
fs::copy(mod_custom_path.join(file_name), mods_path.join(file_name))
.await
.with_context(|| format!("Failed to copy custom mod {}", current_mod.name))?;
log(&window, &format!("Copied custom mod {}", current_mod.name));
progress.progress_update(ProgressUpdate::set_label(format!("Copied custom mod {}", current_mod.name)));
continue;
}
Expand All @@ -149,7 +151,13 @@ pub async fn retrieve_and_copy_mods(data: &Path, manifest: &LaunchManifest, mods

let contents = match &current_mod.source {
ModSource::SkipAd { artifact_name: _, url, extract } => {
let retrieved_bytes = download_client(url, |a, b| progress.progress_update(ProgressUpdate::set_for_step(ProgressUpdateSteps::DownloadLiquidBounceMods, get_progress(mod_idx, a, b) as u64, max)), window).await?;
log(&window, &format!("Opening download page for mod {} on {}", current_mod.name, url));
progress.progress_update(ProgressUpdate::set_label(format!("Opening download page for mod {}", current_mod.name)));
let direct_url = open_download_page(url, progress, window).await?;

log(&window, &format!("Downloading mod {} from {}", current_mod.name, direct_url));
progress.progress_update(ProgressUpdate::set_label(format!("Downloading mod {}", current_mod.name)));
let retrieved_bytes = download_file(&direct_url, |a, b| progress.progress_update(ProgressUpdate::set_for_step(ProgressUpdateSteps::DownloadLiquidBounceMods, get_progress(mod_idx, a, b) as u64, max))).await?;

// Extract bytes
if *extract {
Expand All @@ -174,7 +182,7 @@ pub async fn retrieve_and_copy_mods(data: &Path, manifest: &LaunchManifest, mods
}
},
ModSource::Repository { repository, artifact } => {
info!("downloading mod {} from {}", artifact, repository);
log(&window, &format!("Downloading mod {} from {}", artifact, repository));
let repository_url = manifest.repositories.get(repository)
.ok_or_else(|| LauncherError::InvalidVersionProfile(format!("There is no repository specified with the name {}", repository)))?;

Expand Down

0 comments on commit 9614b01

Please sign in to comment.