You've already forked AstralRinth
feat: add ability to auto exec downloaded installer on windows; minor changes
This commit is contained in:
@@ -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 failedFetch = [`Failed to fetch remote releases:`, `Failed to fetch remote commits:`]
|
||||||
|
|
||||||
const osList = ['macos', 'windows', 'linux']
|
const osList = ['macos', 'windows', 'linux']
|
||||||
const macExtensionList = ['.app', '.dmg']
|
const macExtensionList = ['.dmg', '.pkg']
|
||||||
const windowsExtensionList = ['.exe', '.msi']
|
const windowsExtensionList = ['.exe', '.msi']
|
||||||
|
|
||||||
const blacklistPrefixes = [
|
const blacklistPrefixes = [
|
||||||
|
|||||||
@@ -1,42 +1,115 @@
|
|||||||
use reqwest;
|
use reqwest;
|
||||||
|
use std::path::PathBuf;
|
||||||
use tokio::fs::File as AsyncFile;
|
use tokio::fs::File as AsyncFile;
|
||||||
use tokio::io::AsyncWriteExt;
|
use tokio::io::AsyncWriteExt;
|
||||||
use tokio::process::Command;
|
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<dyn std::error::Error>> {
|
pub(crate) async fn get_resource(
|
||||||
let download_dir = dirs::download_dir().ok_or("[AR] • Failed to determine download directory")?;
|
download_url: &str,
|
||||||
|
local_filename: &str,
|
||||||
|
os_type: &str,
|
||||||
|
auto_update_supported: bool,
|
||||||
|
) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
let download_dir = dirs::download_dir()
|
||||||
|
.ok_or("[AR] • Failed to determine download directory")?;
|
||||||
let full_path = download_dir.join(local_filename);
|
let full_path = download_dir.join(local_filename);
|
||||||
|
|
||||||
let response = reqwest::get(download_url).await?;
|
let response = reqwest::get(download_url).await?;
|
||||||
let bytes = response.bytes().await?;
|
let bytes = response.bytes().await?;
|
||||||
let mut dest_file = AsyncFile::create(&full_path).await?;
|
let mut dest_file = AsyncFile::create(&full_path).await?;
|
||||||
dest_file.write_all(&bytes).await?;
|
dest_file.write_all(&bytes).await?;
|
||||||
println!("[AR] • File downloaded to: {:?}", full_path);
|
println!("[AR] • File downloaded to: {:?}", full_path);
|
||||||
|
|
||||||
if auto_update_supported {
|
if auto_update_supported {
|
||||||
let status;
|
let result = match os_type.to_lowercase().as_str() {
|
||||||
if os_type.to_lowercase() == "Windows".to_lowercase() {
|
"windows" => handle_windows_file(&full_path).await,
|
||||||
status = Command::new("explorer")
|
"macos" => open_macos_file(&full_path).await,
|
||||||
.arg(download_dir.display().to_string())
|
_ => open_default(&full_path).await,
|
||||||
.status()
|
};
|
||||||
.await
|
|
||||||
.expect("[AR] • Failed to open downloads folder");
|
match result {
|
||||||
} else if os_type.to_lowercase() == "MacOS".to_lowercase() {
|
Ok(_) => println!("[AR] • File opened successfully!"),
|
||||||
status = Command::new("open")
|
Err(e) => eprintln!("[AR] • Failed to open file: {e}"),
|
||||||
.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());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn handle_windows_file(path: &PathBuf) -> Result<(), Box<dyn std::error::Error>> {
|
||||||
|
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<dyn std::error::Error>> {
|
||||||
|
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<dyn std::error::Error>> {
|
||||||
|
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<dyn std::error::Error>> {
|
||||||
|
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<dyn std::error::Error>> {
|
||||||
|
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(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::state::DirectoryInfo;
|
|
||||||
use crate::ErrorKind;
|
use crate::ErrorKind;
|
||||||
|
use crate::state::DirectoryInfo;
|
||||||
use sqlx::sqlite::{
|
use sqlx::sqlite::{
|
||||||
SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions,
|
SqliteConnectOptions, SqliteJournalMode, SqlitePoolOptions,
|
||||||
};
|
};
|
||||||
@@ -87,14 +87,14 @@ LF -> c0de804f171b5530010edae087a6e75645c0e90177e28365f935c9fdd9a5c68e24850b8c14
|
|||||||
CRLF -> f8c55065e2563fa4738976eb13a052ae4c28da8d33143185550f6e1cee394a3243b1dca090b3e8bc50a93a8286a78c09
|
CRLF -> f8c55065e2563fa4738976eb13a052ae4c28da8d33143185550f6e1cee394a3243b1dca090b3e8bc50a93a8286a78c09
|
||||||
LF -> c17542cb989a0466153e695bfa4717f8970feee185ca186a2caa1f2f6c5d4adb990ab97c26cacfbbe09c39ac81551704
|
LF -> c17542cb989a0466153e695bfa4717f8970feee185ca186a2caa1f2f6c5d4adb990ab97c26cacfbbe09c39ac81551704
|
||||||
*/
|
*/
|
||||||
pub(crate) async fn fix_version_hash(
|
pub(crate) async fn apply_migration_fix(eol: &str) -> crate::Result<bool> {
|
||||||
eol: &str,
|
|
||||||
) -> crate::Result<bool> {
|
|
||||||
let started = Instant::now();
|
let started = Instant::now();
|
||||||
|
|
||||||
// Create connection to the database without migrations
|
// Create connection to the database without migrations
|
||||||
let pool = connect_without_migrate().await?;
|
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
|
// validate EOL input
|
||||||
if eol != "lf" && eol != "crlf" {
|
if eol != "lf" && eol != "crlf" {
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ pub fn read_package_json() -> io::Result<Launcher> {
|
|||||||
|
|
||||||
pub async fn apply_migration_fix(eol: &str) -> Result<bool> {
|
pub async fn apply_migration_fix(eol: &str) -> Result<bool> {
|
||||||
tracing::info!("[AR] • Attempting to apply migration fix");
|
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 {
|
if patched {
|
||||||
tracing::info!("[AR] • Successfully applied migration fix");
|
tracing::info!("[AR] • Successfully applied migration fix");
|
||||||
} else {
|
} else {
|
||||||
@@ -43,7 +43,7 @@ pub async fn init_download(
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
println!("[AR] • Initialize downloading from • {:?}", download_url);
|
println!("[AR] • Initialize downloading from • {:?}", download_url);
|
||||||
println!("[AR] • Save local file name • {:?}", local_filename);
|
println!("[AR] • Save local file name • {:?}", local_filename);
|
||||||
if let Err(e) = update::download_file(
|
if let Err(e) = update::get_resource(
|
||||||
download_url,
|
download_url,
|
||||||
local_filename,
|
local_filename,
|
||||||
os_type,
|
os_type,
|
||||||
|
|||||||
Reference in New Issue
Block a user