diff --git a/apps/app-frontend/src/helpers/update.js b/apps/app-frontend/src/helpers/update.js index 6f3d87a1..cea6c6bd 100644 --- a/apps/app-frontend/src/helpers/update.js +++ b/apps/app-frontend/src/helpers/update.js @@ -11,7 +11,7 @@ const releaseLink = `https://git.astralium.su/api/v1/repos/didirus/AstralRinth/r const failedFetch = [`Failed to fetch remote releases:`, `Failed to fetch remote commits:`] const osList = ['macos', 'windows', 'linux'] -const macExtensionList = ['.app', '.dmg'] +const macExtensionList = ['.dmg', '.pkg'] const windowsExtensionList = ['.exe', '.msi'] const blacklistPrefixes = [ diff --git a/packages/app-lib/src/api/update.rs b/packages/app-lib/src/api/update.rs index b1943dec..fe24ec01 100644 --- a/packages/app-lib/src/api/update.rs +++ b/packages/app-lib/src/api/update.rs @@ -1,42 +1,115 @@ use reqwest; +use std::path::PathBuf; use tokio::fs::File as AsyncFile; use tokio::io::AsyncWriteExt; use tokio::process::Command; -pub(crate) async fn download_file(download_url: &str, local_filename: &str, os_type: &str, auto_update_supported: bool) -> Result<(), Box> { - let download_dir = dirs::download_dir().ok_or("[AR] • Failed to determine download directory")?; +pub(crate) async fn get_resource( + download_url: &str, + local_filename: &str, + os_type: &str, + auto_update_supported: bool, +) -> Result<(), Box> { + let download_dir = dirs::download_dir() + .ok_or("[AR] • Failed to determine download directory")?; let full_path = download_dir.join(local_filename); + let response = reqwest::get(download_url).await?; let bytes = response.bytes().await?; let mut dest_file = AsyncFile::create(&full_path).await?; dest_file.write_all(&bytes).await?; println!("[AR] • File downloaded to: {:?}", full_path); + if auto_update_supported { - let status; - if os_type.to_lowercase() == "Windows".to_lowercase() { - status = Command::new("explorer") - .arg(download_dir.display().to_string()) - .status() - .await - .expect("[AR] • Failed to open downloads folder"); - } else if os_type.to_lowercase() == "MacOS".to_lowercase() { - status = Command::new("open") - .arg(full_path.to_str().unwrap_or_default()) - .status() - .await - .expect("[AR] • Failed to execute command"); - } else { - status = Command::new(".") - .arg(full_path.to_str().unwrap_or_default()) - .status() - .await - .expect("[AR] • Failed to execute command"); - } - if status.success() { - println!("[AR] • File opened successfully!"); - } else { - eprintln!("[AR] • Failed to open the file. Exit code: {:?}", status.code()); + let result = match os_type.to_lowercase().as_str() { + "windows" => handle_windows_file(&full_path).await, + "macos" => open_macos_file(&full_path).await, + _ => open_default(&full_path).await, + }; + + match result { + Ok(_) => println!("[AR] • File opened successfully!"), + Err(e) => eprintln!("[AR] • Failed to open file: {e}"), } } + Ok(()) -} \ No newline at end of file +} + +async fn handle_windows_file(path: &PathBuf) -> Result<(), Box> { + let filename = path + .file_name() + .and_then(|f| f.to_str()) + .unwrap_or_default() + .to_lowercase(); + + if filename.ends_with(".exe") || filename.ends_with(".msi") { + println!("[AR] • Detected installer: {}", filename); + run_windows_installer(path).await + } else { + open_windows_folder(path).await + } +} + +async fn run_windows_installer(path: &PathBuf) -> Result<(), Box> { + let installer_path = path.to_str().unwrap_or_default(); + + let status = if installer_path.ends_with(".msi") { + Command::new("msiexec") + .args(&["/i", installer_path, "/quiet"]) + .status() + .await? + } else { + Command::new("cmd") + .args(&["/C", installer_path]) + .status() + .await? + }; + + if status.success() { + println!("[AR] • Installer started successfully."); + Ok(()) + } else { + Err(format!("Installer failed. Exit code: {:?}", status.code()).into()) + } +} + +async fn open_windows_folder(path: &PathBuf) -> Result<(), Box> { + let folder = path.parent().unwrap_or(path); + let status = Command::new("explorer") + .arg(folder.display().to_string()) + .status() + .await?; + + if !status.success() { + Err(format!("Exit code: {:?}", status.code()).into()) + } else { + Ok(()) + } +} + +async fn open_macos_file(path: &PathBuf) -> Result<(), Box> { + let status = Command::new("open") + .arg(path.to_str().unwrap_or_default()) + .status() + .await?; + + if !status.success() { + Err(format!("Exit code: {:?}", status.code()).into()) + } else { + Ok(()) + } +} + +async fn open_default(path: &PathBuf) -> Result<(), Box> { + let status = Command::new(".") + .arg(path.to_str().unwrap_or_default()) + .status() + .await?; + + if !status.success() { + Err(format!("Exit code: {:?}", status.code()).into()) + } else { + Ok(()) + } +} diff --git a/packages/app-lib/src/state/db.rs b/packages/app-lib/src/state/db.rs index bebcf5fb..fe81e412 100644 --- a/packages/app-lib/src/state/db.rs +++ b/packages/app-lib/src/state/db.rs @@ -1,5 +1,5 @@ -use crate::state::DirectoryInfo; use crate::ErrorKind; +use crate::state::DirectoryInfo; use sqlx::sqlite::{ SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions, }; @@ -87,14 +87,14 @@ LF -> c0de804f171b5530010edae087a6e75645c0e90177e28365f935c9fdd9a5c68e24850b8c14 CRLF -> f8c55065e2563fa4738976eb13a052ae4c28da8d33143185550f6e1cee394a3243b1dca090b3e8bc50a93a8286a78c09 LF -> c17542cb989a0466153e695bfa4717f8970feee185ca186a2caa1f2f6c5d4adb990ab97c26cacfbbe09c39ac81551704 */ -pub(crate) async fn fix_version_hash( - eol: &str, -) -> crate::Result { +pub(crate) async fn apply_migration_fix(eol: &str) -> crate::Result { let started = Instant::now(); // Create connection to the database without migrations let pool = connect_without_migrate().await?; - tracing::info!("⚙️ Patching Modrinth corrupted migration checksums using EOL standard: {eol}"); + tracing::info!( + "⚙️ Patching Modrinth corrupted migration checksums using EOL standard: {eol}" + ); // validate EOL input if eol != "lf" && eol != "crlf" { diff --git a/packages/app-lib/src/util/utils.rs b/packages/app-lib/src/util/utils.rs index 678ddb69..adebc3a6 100644 --- a/packages/app-lib/src/util/utils.rs +++ b/packages/app-lib/src/util/utils.rs @@ -26,7 +26,7 @@ pub fn read_package_json() -> io::Result { pub async fn apply_migration_fix(eol: &str) -> Result { tracing::info!("[AR] • Attempting to apply migration fix"); - let patched = db::fix_version_hash(eol).await?; + let patched = db::apply_migration_fix(eol).await?; if patched { tracing::info!("[AR] • Successfully applied migration fix"); } else { @@ -43,7 +43,7 @@ pub async fn init_download( ) -> Result<()> { println!("[AR] • Initialize downloading from • {:?}", download_url); println!("[AR] • Save local file name • {:?}", local_filename); - if let Err(e) = update::download_file( + if let Err(e) = update::get_resource( download_url, local_filename, os_type,