Skip to content

Commit

Permalink
feat: Migrate emit function to Tauri v2 and re-implement Northstar in…
Browse files Browse the repository at this point in the history
…stallation logic
  • Loading branch information
GeckoEidechse committed Jan 4, 2025
1 parent 8cfad71 commit 5cab6b3
Showing 1 changed file with 146 additions and 8 deletions.
154 changes: 146 additions & 8 deletions src-tauri/src/northstar/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use anyhow::Result;
use serde::{Deserialize, Serialize};
use std::time::Duration;
use std::{cell::RefCell, time::Instant};
use tauri::{AppHandle, Emitter};
use ts_rs::TS;

use crate::constants::{CORE_MODS, NORTHSTAR_DEFAULT_PROFILE, NORTHSTAR_DLL};
Expand Down Expand Up @@ -32,7 +33,7 @@ struct InstallProgress {
/// Installs Northstar to the given path
#[tauri::command]
pub async fn install_northstar_wrapper(
window: tauri::Window,
app: AppHandle,
game_install: GameInstall,
northstar_package_name: Option<String>,
version_number: Option<String>,
Expand All @@ -50,7 +51,7 @@ pub async fn install_northstar_wrapper(
})
.unwrap_or("Northstar".to_string());

match install_northstar(window, game_install, northstar_package_name, version_number).await {
match install_northstar(app, game_install, northstar_package_name, version_number).await {
Ok(_) => Ok(true),
Err(err) => {
log::error!("{}", err);
Expand All @@ -62,22 +63,22 @@ pub async fn install_northstar_wrapper(
/// Update Northstar install in the given path
#[tauri::command]
pub async fn update_northstar(
window: tauri::Window,
app: AppHandle,
game_install: GameInstall,
northstar_package_name: Option<String>,
) -> Result<bool, String> {
log::info!("Updating Northstar");

// Simply re-run install with up-to-date version for upate
install_northstar_wrapper(window, game_install, northstar_package_name, None).await
install_northstar_wrapper(app, game_install, northstar_package_name, None).await
}

/// Copied from `papa` source code and modified
///Install N* from the provided mod
///
///Checks cache, else downloads the latest version
async fn do_install(
window: tauri::Window,
app: AppHandle,
nmod: &thermite::model::ModVersion,
game_install: GameInstall,
) -> Result<()> {
Expand All @@ -100,11 +101,148 @@ async fn do_install(
.truncate(true)
.create(true)
.open(download_path)?;
todo!()
thermite::core::manage::download_with_progress(
&mut nfile,
&nmod.url,
|delta, current, total| {
if delta != 0 {
// Only emit a signal once every 100ms
// This way we don't bombard the frontend with events on fast download speeds
let time_since_last_emit = Instant::now().duration_since(*last_emit.borrow());
if time_since_last_emit >= Duration::from_millis(100) {
app.emit(
"northstar-install-download-progress",
InstallProgress {
current_downloaded: current,
total_size: total,
state: InstallState::Downloading,
},
)
.unwrap();
*last_emit.borrow_mut() = Instant::now();
}
}
},
)?;

app.emit(
"northstar-install-download-progress",
InstallProgress {
current_downloaded: 0,
total_size: 0,
state: InstallState::Extracting,
},
)
.unwrap();

log::info!("Extracting Northstar...");
extract(nfile, std::path::Path::new(&extract_directory))?;

// Prepare Northstar for Installation
log::info!("Preparing Northstar...");
if game_install.profile != NORTHSTAR_DEFAULT_PROFILE {
// We are using a non standard Profile, we must:
// - move the DLL
// - rename the Profile

// Move DLL into the default R2Northstar Profile
let old_dll_path = format!("{}/{}", extract_directory, NORTHSTAR_DLL);
let new_dll_path = format!(
"{}/{}/{}",
extract_directory, NORTHSTAR_DEFAULT_PROFILE, NORTHSTAR_DLL
);
std::fs::rename(old_dll_path, new_dll_path)?;

// rename default R2Northstar Profile to the profile we want to use
let old_profile_path = format!("{}/{}/", extract_directory, NORTHSTAR_DEFAULT_PROFILE);
let new_profile_path = format!("{}/{}/", extract_directory, game_install.profile);
std::fs::rename(old_profile_path, new_profile_path)?;
}

log::info!("Installing Northstar...");

// Delete previous version here
for core_mod in CORE_MODS {
let path_to_delete_string = format!(
"{}/{}/mods/{}/",
game_install.game_path, game_install.profile, core_mod
);
log::info!("Preparing to remove {}", path_to_delete_string);

// Check if folder exists
let path_to_delete = std::path::Path::new(&path_to_delete_string);

// Check if path even exists before we attempt to remove
if !path_to_delete.exists() {
log::info!("{} does not exist. Skipping", path_to_delete_string);
continue;
}

if !path_to_delete.is_dir() {
log::error!(
"{} exists but is a file? This should never happen",
path_to_delete_string
);
continue;
}

// Safety check for mod.json
// Just so that we won't ever have a https://github.com/ValveSoftware/steam-for-linux/issues/3671 moment
let mod_json_path = format!("{}/mod.json", path_to_delete_string);
let mod_json_path = std::path::Path::new(&mod_json_path);

if !mod_json_path.exists() {
log::error!("Missing mod.json for {path_to_delete_string} this shouldn't happen");
continue;
}

// Finally delete file
match std::fs::remove_dir_all(path_to_delete) {
Ok(()) => {
log::info!("Succesfully removed")
}
Err(err) => {
log::error!("Failed removing {} due to {}", path_to_delete_string, err)
}
};
}

for entry in std::fs::read_dir(extract_directory).unwrap() {
let entry = entry.unwrap();
let destination = format!(
"{}/{}",
game_install.game_path,
entry.path().file_name().unwrap().to_str().unwrap()
);

log::info!("Installing {}", entry.path().display());
if !entry.file_type().unwrap().is_dir() {
std::fs::rename(entry.path(), destination)?;
} else {
move_dir_all(entry.path(), destination)?;
}
}

// Delete old copy
log::info!("Delete temporary directory");
std::fs::remove_dir_all(temp_dir).unwrap();

log::info!("Done installing Northstar!");
app.emit(
"northstar-install-download-progress",
InstallProgress {
current_downloaded: 0,
total_size: 0,
state: InstallState::Done,
},
)
.unwrap();

Ok(())
}

pub async fn install_northstar(
window: tauri::Window,
app: AppHandle,
game_install: GameInstall,
northstar_package_name: String,
version_number: Option<String>,
Expand All @@ -128,7 +266,7 @@ pub async fn install_northstar(
let game_path = game_install.game_path.clone();
log::info!("Install path \"{}\"", game_path);

match do_install(window, nmod.versions.get(version).unwrap(), game_install).await {
match do_install(app, nmod.versions.get(version).unwrap(), game_install).await {
Ok(_) => (),
Err(err) => {
if game_path
Expand Down

0 comments on commit 5cab6b3

Please sign in to comment.