From 8d5a7eba98fc01999d54ee89d1455ed024801359 Mon Sep 17 00:00:00 2001 From: GeckoEidechse Date: Fri, 9 Sep 2022 23:03:39 +0200 Subject: Add initial Northstar install support still Steam version only --- src-tauri/Cargo.lock | 1 + src-tauri/Cargo.toml | 2 ++ src-tauri/src/lib.rs | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++- src-tauri/src/main.rs | 21 +++++++++++-- src-ui/src/main.ts | 17 ++++++++++ 5 files changed, 125 insertions(+), 3 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index e9d51e6a..70d1ca2f 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -87,6 +87,7 @@ dependencies = [ "tauri", "tauri-build", "tokio", + "zip", ] [[package]] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index ae3be596..384da83e 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -26,6 +26,8 @@ steamlocate = "1.0.2" anyhow = "1.0" # libthermite for Northstar/mod install handling libthermite = "0.1.0" +# zip stuff +zip = "0.6.2" [features] # by default Tauri runs in production mode diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 3542cab5..cf1213d1 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -1,4 +1,5 @@ -use anyhow::anyhow; +use anyhow::{anyhow, Context, Result}; +use zip::ZipArchive; #[derive(Debug)] pub enum InstallType { @@ -103,3 +104,87 @@ pub fn check_is_valid_game_path(game_install_path: &str) -> Result<(), anyhow::E } Ok(()) } + +/// Copied from `papa` source code and modified +///Extract N* zip file to target game path +// fn extract(ctx: &Ctx, zip_file: File, target: &Path) -> Result<()> { +fn extract(zip_file: std::fs::File, target: &std::path::Path) -> Result<()> { + let mut archive = ZipArchive::new(&zip_file).context("Unable to open zip archive")?; + for i in 0..archive.len() { + let mut f = archive.by_index(i).unwrap(); + + //This should work fine for N* because the dir structure *should* always be the same + if f.enclosed_name().unwrap().starts_with("Northstar") { + let out = target.join( + f.enclosed_name() + .unwrap() + .strip_prefix("Northstar") + .unwrap(), + ); + + if (*f.name()).ends_with('/') { + println!("Create directory {}", f.name()); + std::fs::create_dir_all(target.join(f.name())) + .context("Unable to create directory")?; + continue; + } else if let Some(p) = out.parent() { + std::fs::create_dir_all(&p).context("Unable to create directory")?; + } + + let mut outfile = std::fs::OpenOptions::new() + .create(true) + .write(true) + .truncate(true) + .open(&out)?; + + println!("Write file {}", out.display()); + + std::io::copy(&mut f, &mut outfile).context("Unable to write to file")?; + } + } + + Ok(()) +} + +/// Copied from `papa` source code and modified +///Install N* from the provided mod +/// +///Checks cache, else downloads the latest version +async fn do_install(nmod: &thermite::model::Mod, game_path: &std::path::Path) -> Result<()> { + let filename = format!("northstar-{}.zip", nmod.version); + let download_directory = format!("{}/flightcore-temp-download-dir/", game_path.display()); + + std::fs::create_dir_all(download_directory.clone())?; + + + let download_path = format!("{}/{}", download_directory, filename); + println!("{}", download_path); + + let nfile = thermite::core::actions::download_file( + &nmod.url, + download_path, + ) + .await + .unwrap(); + + println!("Extracting Northstar..."); + extract(nfile, game_path)?; + println!("Done!"); + + Ok(()) +} + +pub async fn install_northstar(game_path: &str) -> Result { + let index = thermite::api::get_package_index().await.unwrap().to_vec(); + let nmod = index + .iter() + .find(|f| f.name.to_lowercase() == "northstar") + .ok_or_else(|| panic!("Couldn't find Northstar on thunderstore???")) + .unwrap(); + + do_install(nmod, std::path::Path::new(game_path)) + .await + .unwrap(); + + Ok(nmod.version.clone()) +} diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index c83ddaeb..9328d7ce 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -9,7 +9,10 @@ use std::{ time::Duration, }; -use app::{check_is_valid_game_path, find_game_install_location, get_northstar_version_number}; +use app::{ + check_is_valid_game_path, find_game_install_location, get_northstar_version_number, + install_northstar, +}; use tauri::{Manager, State}; use tokio::time::sleep; @@ -50,7 +53,8 @@ fn main() { get_northstar_version_number_caller, check_is_northstar_outdated, verify_install_location, - get_host_os + get_host_os, + install_northstar_caller ]) .run(tauri::generate_context!()) .expect("error while running tauri application"); @@ -154,3 +158,16 @@ fn verify_install_location(game_path: String) -> bool { fn get_host_os() -> String { env::consts::OS.to_string() } + +#[tauri::command] +/// Installs Northstar to the given path +async fn install_northstar_caller(game_path: String) -> bool { + println!("Running"); + match install_northstar(&game_path).await { + Ok(_) => true, + Err(err) => { + println!("{}", err); + false + } + } +} diff --git a/src-ui/src/main.ts b/src-ui/src/main.ts index 09c7f057..a9fe0301 100644 --- a/src-ui/src/main.ts +++ b/src-ui/src/main.ts @@ -83,6 +83,23 @@ document.addEventListener("DOMContentLoaded", async function () { // } switch (omniButtonEl.textContent) { + case "Install": + omniButtonEl.textContent = "Installing"; + await invoke("install_northstar_caller", { gamePath: globalState.gamepath }) as boolean; + alert("Done?"); + + // TODO: move this to function + let northstar_version_number = await invoke("get_northstar_version_number_caller") as string; + if (northstar_version_number && northstar_version_number.length > 0) { + globalState.installed_northstar_version = northstar_version_number; + omniButtonEl.textContent = `Play (${northstar_version_number})`; + let northstar_is_outdated = await invoke("check_is_northstar_outdated") as boolean; + if (northstar_is_outdated) { + omniButtonEl.textContent = "Update"; + } + } + + break; default: alert("Not implemented yet"); break; -- cgit v1.2.3