chore: add inline updater

This commit is contained in:
2025-07-30 20:26:05 +02:00
parent 9b3cb0bd26
commit 084e006f06
8 changed files with 206 additions and 87 deletions

124
src-tauri/Cargo.lock generated
View File

@@ -134,7 +134,7 @@ dependencies = [
"futures-lite",
"parking",
"polling",
"rustix 1.0.8",
"rustix",
"slab",
"windows-sys 0.60.2",
]
@@ -165,7 +165,7 @@ dependencies = [
"cfg-if",
"event-listener",
"futures-lite",
"rustix 1.0.8",
"rustix",
]
[[package]]
@@ -191,7 +191,7 @@ dependencies = [
"cfg-if",
"futures-core",
"futures-io",
"rustix 1.0.8",
"rustix",
"signal-hook-registry",
"slab",
"windows-sys 0.60.2",
@@ -438,12 +438,12 @@ dependencies = [
[[package]]
name = "cargo_toml"
version = "0.22.1"
version = "0.22.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02260d489095346e5cafd04dea8e8cb54d1d74fcd759022a9b72986ebe9a1257"
checksum = "374b7c592d9c00c1f4972ea58390ac6b18cbb6ab79011f3bdc90a0b82ca06b77"
dependencies = [
"serde",
"toml 0.8.23",
"toml 0.9.4",
]
[[package]]
@@ -901,9 +901,9 @@ checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813"
[[package]]
name = "dyn-clone"
version = "1.0.19"
version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1c7a8fb8a9fbf66c1f703fe16184d10ca0ee9d23be5b4436400408ba54a95005"
checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
[[package]]
name = "embed-resource"
@@ -914,7 +914,7 @@ dependencies = [
"cc",
"memchr",
"rustc_version",
"toml 0.9.2",
"toml 0.9.4",
"vswhom",
"winreg 0.55.0",
]
@@ -1010,7 +1010,7 @@ dependencies = [
[[package]]
name = "ezpplauncher"
version = "3.0.3"
version = "3.0.2"
dependencies = [
"base64 0.22.1",
"discord-rich-presence",
@@ -2113,25 +2113,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07033963ba89ebaf1584d767badaa2e8fcec21aedea6b8c0346d487d49c28667"
dependencies = [
"cfg-if",
"windows-targets 0.53.2",
"windows-targets 0.53.3",
]
[[package]]
name = "libredox"
version = "0.1.6"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4488594b9328dee448adb906d8b126d9b7deb7cf5c22161ee591610bb1be83c0"
checksum = "360e552c93fa0e8152ab463bc4c4837fce76a225df11dfaeea66c313de5e61f7"
dependencies = [
"bitflags 2.9.1",
"libc",
]
[[package]]
name = "linux-raw-sys"
version = "0.4.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab"
[[package]]
name = "linux-raw-sys"
version = "0.9.4"
@@ -2146,9 +2140,9 @@ checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956"
[[package]]
name = "litrs"
version = "0.4.1"
version = "0.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4ce301924b7887e9d637144fdade93f9dfff9b60981d4ac161db09720d39aa5"
checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed"
[[package]]
name = "lock_api"
@@ -2259,9 +2253,9 @@ dependencies = [
[[package]]
name = "muda"
version = "0.17.0"
version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58b89bf91c19bf036347f1ab85a81c560f08c0667c8601bece664d860a600988"
checksum = "01c1738382f66ed56b3b9c8119e794a2e23148ac8ea214eda86622d4cb9d415a"
dependencies = [
"crossbeam-channel",
"dpi",
@@ -2275,7 +2269,7 @@ dependencies = [
"png",
"serde",
"thiserror 2.0.12",
"windows-sys 0.59.0",
"windows-sys 0.60.2",
]
[[package]]
@@ -2982,7 +2976,7 @@ dependencies = [
"concurrent-queue",
"hermit-abi",
"pin-project-lite",
"rustix 1.0.8",
"rustix",
"windows-sys 0.60.2",
]
@@ -3305,9 +3299,9 @@ checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
[[package]]
name = "redox_syscall"
version = "0.5.15"
version = "0.5.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e8af0dde094006011e6a740d4879319439489813bd0bcdc7d821beaeeff48ec"
checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77"
dependencies = [
"bitflags 2.9.1",
]
@@ -3462,9 +3456,9 @@ dependencies = [
[[package]]
name = "rustc-demangle"
version = "0.1.25"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "989e6739f80c4ad5b13e0fd7fe89531180375b18520cc8c82080e4dc4035b84f"
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
[[package]]
name = "rustc-hash"
@@ -3481,19 +3475,6 @@ dependencies = [
"semver",
]
[[package]]
name = "rustix"
version = "0.38.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
dependencies = [
"bitflags 2.9.1",
"errno",
"libc",
"linux-raw-sys 0.4.15",
"windows-sys 0.59.0",
]
[[package]]
name = "rustix"
version = "1.0.8"
@@ -3503,15 +3484,15 @@ dependencies = [
"bitflags 2.9.1",
"errno",
"libc",
"linux-raw-sys 0.9.4",
"linux-raw-sys",
"windows-sys 0.60.2",
]
[[package]]
name = "rustls"
version = "0.23.29"
version = "0.23.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1"
checksum = "c0ebcbd2f03de0fc1122ad9bb24b127a5a6cd51d72604a3f3c50ac459762b6cc"
dependencies = [
"once_cell",
"ring",
@@ -4356,9 +4337,9 @@ dependencies = [
[[package]]
name = "tauri-plugin-dialog"
version = "2.3.1"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "05bedd4c3cf6f7aa97918a8814a736bd3695c9ddf3ede2d50eda6069c3290edc"
checksum = "37e5858cc7b455a73ab4ea2ebc08b5be33682c00ff1bf4cad5537d4fb62499d9"
dependencies = [
"log",
"raw-window-handle",
@@ -4537,7 +4518,7 @@ dependencies = [
"fastrand",
"getrandom 0.3.3",
"once_cell",
"rustix 1.0.8",
"rustix",
"windows-sys 0.59.0",
]
@@ -4650,9 +4631,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "tokio"
version = "1.46.1"
version = "1.47.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0cc3a2344dafbe23a245241fe8b09735b521110d30fcefbbd5feb1797ca35d17"
checksum = "43864ed400b6043a4757a25c7a64a8efde741aed79a056a2fb348a406701bb35"
dependencies = [
"backtrace",
"bytes",
@@ -4663,10 +4644,10 @@ dependencies = [
"pin-project-lite",
"signal-hook-registry",
"slab",
"socket2 0.5.10",
"socket2 0.6.0",
"tokio-macros",
"tracing",
"windows-sys 0.52.0",
"windows-sys 0.59.0",
]
[[package]]
@@ -4727,9 +4708,9 @@ dependencies = [
[[package]]
name = "toml"
version = "0.9.2"
version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed0aee96c12fa71097902e0bb061a5e1ebd766a6636bb605ba401c45c1650eac"
checksum = "41ae868b5a0f67631c14589f7e250c1ea2c574ee5ba21c6c8dd4b1485705a5a1"
dependencies = [
"indexmap 2.10.0",
"serde",
@@ -4893,9 +4874,9 @@ dependencies = [
[[package]]
name = "tray-icon"
version = "0.21.0"
version = "0.21.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2da75ec677957aa21f6e0b361df0daab972f13a5bee3606de0638fd4ee1c666a"
checksum = "a0d92153331e7d02ec09137538996a7786fe679c629c279e82a6be762b7e6fe2"
dependencies = [
"crossbeam-channel",
"dirs",
@@ -5222,13 +5203,13 @@ dependencies = [
[[package]]
name = "wayland-backend"
version = "0.3.10"
version = "0.3.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe770181423e5fc79d3e2a7f4410b7799d5aab1de4372853de3c6aa13ca24121"
checksum = "673a33c33048a5ade91a6b139580fa174e19fb0d23f396dca9fa15f2e1e49b35"
dependencies = [
"cc",
"downcast-rs",
"rustix 0.38.44",
"rustix",
"scoped-tls",
"smallvec",
"wayland-sys",
@@ -5236,21 +5217,21 @@ dependencies = [
[[package]]
name = "wayland-client"
version = "0.31.10"
version = "0.31.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "978fa7c67b0847dbd6a9f350ca2569174974cd4082737054dbb7fbb79d7d9a61"
checksum = "c66a47e840dc20793f2264eb4b3e4ecb4b75d91c0dd4af04b456128e0bdd449d"
dependencies = [
"bitflags 2.9.1",
"rustix 0.38.44",
"rustix",
"wayland-backend",
"wayland-scanner",
]
[[package]]
name = "wayland-protocols"
version = "0.32.8"
version = "0.32.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "779075454e1e9a521794fed15886323ea0feda3f8b0fc1390f5398141310422a"
checksum = "efa790ed75fbfd71283bd2521a1cfdc022aabcc28bdcff00851f9e4ae88d9901"
dependencies = [
"bitflags 2.9.1",
"wayland-backend",
@@ -5260,9 +5241,9 @@ dependencies = [
[[package]]
name = "wayland-scanner"
version = "0.31.6"
version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "896fdafd5d28145fce7958917d69f2fd44469b1d4e861cb5961bcbeebc6d1484"
checksum = "54cb1e9dc49da91950bdfd8b848c49330536d9d1fb03d4bfec8cae50caa50ae3"
dependencies = [
"proc-macro2",
"quick-xml 0.37.5",
@@ -5271,9 +5252,9 @@ dependencies = [
[[package]]
name = "wayland-sys"
version = "0.31.6"
version = "0.31.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dbcebb399c77d5aa9fa5db874806ee7b4eba4e73650948e8f93963f128896615"
checksum = "34949b42822155826b41db8e5d0c1be3a2bd296c747577a43a3e6daefc296142"
dependencies = [
"dlib",
"log",
@@ -5587,7 +5568,7 @@ version = "0.60.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb"
dependencies = [
"windows-targets 0.53.2",
"windows-targets 0.53.3",
]
[[package]]
@@ -5623,10 +5604,11 @@ dependencies = [
[[package]]
name = "windows-targets"
version = "0.53.2"
version = "0.53.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c66f69fcc9ce11da9966ddb31a40968cad001c5bedeb5c2b82ede4253ab48aef"
checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91"
dependencies = [
"windows-link",
"windows_aarch64_gnullvm 0.53.0",
"windows_aarch64_msvc 0.53.0",
"windows_i686_gnu 0.53.0",

View File

@@ -1,6 +1,6 @@
[package]
name = "ezpplauncher"
version = "3.0.3"
version = "3.0.2"
description = "EZPPLauncher redefined."
authors = ["HorizonCode"]
edition = "2024"

6
src-tauri/nsis-hooks.nsh Normal file
View File

@@ -0,0 +1,6 @@
!macro NSIS_HOOK_POSTINSTALL
${If} $PassiveMode = 1
${OrIf} ${Silent}
Exec '"$INSTDIR\${MAINBINARYNAME}.exe"'
${EndIf}
!macroend

View File

@@ -6,6 +6,7 @@ use std::path::PathBuf;
use sysinfo::System;
use tauri::AppHandle;
use tauri::Emitter;
use tauri::Manager;
use tokio::fs;
use tokio::io::AsyncWriteExt;
use tokio::process::Command;
@@ -729,3 +730,79 @@ pub fn encrypt_string(string: String, entropy: String) -> String {
Err(_) => string,
}
}
#[tauri::command]
pub async fn download_ezpp_launcher_update(app: AppHandle, url: String) -> Result<(), String> {
let client = Client::new();
let mut response = client.get(&url).send().await.map_err(|e| e.to_string())?;
if !response.status().is_success() {
return Err(format!("Failed to download update: {}", response.status()));
}
let temp_dir = app.path().temp_dir().expect("Failed to get temp directory");
let file_path = temp_dir.join("ezpplauncher_update.exe");
let mut file_out = fs::File::create(&file_path)
.await
.map_err(|e| e.to_string())?;
let mut downloaded = 0u64;
let size = response
.content_length()
.ok_or("Failed to get content length")? as usize;
while let Some(chunk) = response.chunk().await.map_err(|e| e.to_string())? {
downloaded += chunk.len() as u64;
file_out
.write_all(&chunk)
.await
.map_err(|e| e.to_string())?;
app.emit(
"download-progress",
UpdateStatus {
file_name: "Update".to_string(),
downloaded,
size: size,
progress: ((downloaded as f64 / size as f64 * 100.0) * 100.0).trunc() / 100.0,
},
)
.unwrap_or_default();
}
Ok(())
}
#[cfg(windows)]
#[tauri::command]
pub async fn install_ezpp_launcher_update(app: AppHandle) -> Result<(), String> {
let temp_dir = app.path().temp_dir().expect("Failed to get temp directory");
let file_path = temp_dir.join("ezpplauncher_update.exe");
if !file_path.exists() {
return Err("Update file does not exist".to_string());
}
// run this app detached and exit
const DETACHED_PROCESS: u32 = 0x00000008;
const CREATE_NEW_PROCESS_GROUP: u32 = 0x00000200;
Command::new(&file_path)
.arg("/QN")
.creation_flags(DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP)
.spawn()
.map_err(|e| format!("Failed to spawn updater: {}", e))?;
sleep(Duration::from_millis(250)).await;
app.exit(0x0100);
Ok(())
}
#[cfg(not(windows))]
#[tauri::command]
pub async fn install_ezpp_launcher_update(_app: AppHandle) -> Result<(), String> {
Ok(())
}

View File

@@ -5,10 +5,11 @@ pub mod commands;
pub mod presence;
pub mod utils;
use crate::commands::{
check_for_corruption, download_ezpp_launcher_update_files, encrypt_string, exit,
find_osu_installation, get_beatmapsets_count, get_ezpp_launcher_update_files, get_hwid,
get_launcher_version, get_osu_release_stream, get_osu_skin, get_osu_version, get_platform,
get_skins_count, has_net8, has_osuwinello, has_wmctrl, is_osu_running, open_url_in_browser,
check_for_corruption, download_ezpp_launcher_update, download_ezpp_launcher_update_files,
encrypt_string, exit, find_osu_installation, get_beatmapsets_count,
get_ezpp_launcher_update_files, get_hwid, get_launcher_version, get_osu_release_stream,
get_osu_skin, get_osu_version, get_platform, get_skins_count, has_net8, has_osuwinello,
has_wmctrl, install_ezpp_launcher_update, is_osu_running, open_url_in_browser,
presence_connect, presence_disconnect, presence_is_connected, presence_update_status,
presence_update_user, replace_ui_files, run_osu, run_osu_updater, set_osu_config_values,
set_osu_user_config_values, valid_osu_folder,
@@ -61,7 +62,9 @@ pub fn run() {
has_osuwinello,
has_wmctrl,
has_net8,
encrypt_string
encrypt_string,
download_ezpp_launcher_update,
install_ezpp_launcher_update
])
.plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_dialog::init())

View File

@@ -2,7 +2,8 @@
"$schema": "https://schema.tauri.app/config/2",
"productName": "EZPPLauncher",
"version": "3.0.3",
"identifier": "farm.ezpp.launcher",
"identifier": "farm.EZPPFarm.Launcher",
"mainBinaryName": "ezpplauncher",
"build": {
"beforeDevCommand": "bun run vite:dev",
"devUrl": "http://localhost:1420",
@@ -41,7 +42,8 @@
},
"nsis": {
"installMode": "currentUser",
"compression": "lzma"
"compression": "lzma",
"installerHooks": "./nsis-hooks.nsh"
}
},
"icon": [

View File

@@ -138,3 +138,17 @@ export const hasOsuWinello = async () => await invoke<boolean>('has_osuwinello')
export const hasNet8 = async () => await invoke<boolean>('has_net8');
export const encryptString = async (str: string, entropy: string) =>
await invoke<string>('encrypt_string', { string: str, entropy });
export const downloadUpdate = async (
url: string,
progressCallback: (file: UpdateStatus) => void
) => {
const downloadStatusListen = await listen('download-progress', (event) =>
progressCallback(event.payload as UpdateStatus)
);
try {
await invoke<string>('download_ezpp_launcher_update', { url });
} finally {
downloadStatusListen();
}
};
export const installUpdate = async () => await invoke('install_ezpp_launcher_update');

View File

@@ -83,6 +83,7 @@
import { osuapi } from '@/api/osuapi';
import {
downloadEZPPLauncherUpdateFiles,
downloadUpdate,
encryptString,
exit,
getBeatmapSetsCount,
@@ -94,6 +95,7 @@
hasNet8,
hasOsuWinello,
hasWMCTRL,
installUpdate,
isOsuCorrupted,
isOsuRunning,
isValidOsuFolder,
@@ -114,6 +116,8 @@
let launchInfo = $state('');
let launchError = $state<Error | undefined>(undefined);
let downloadingUpdate = $state(false);
let selectedGamemode = $derived(
getGamemodeInt(modeIntToStr($preferredMode), typeIntToStr($preferredType))
);
@@ -577,6 +581,36 @@
</div>
</div>
<div class="flex items-center justify-center mb-3">
{#if $platform === 'windows'}
{#if downloadingUpdate}
<div class="flex flex-col items-center justify-center gap-2 p-3 rounded-lg w-full">
<Progress indeterminate={progress === -1} value={progress} />
<span class="text-muted-foreground text-sm mt-4">{launchInfo}</span>
</div>
{:else}
<Button
onclick={async () => {
const updateFile = $newVersion?.assets.find((asset) => asset.name.endsWith('.exe'));
if (!updateFile) {
toast.error('Hmmm...', {
description: 'No update file found.',
});
$newVersion = undefined;
return;
}
downloadingUpdate = true;
launchInfo = 'Downloading Update...';
await downloadUpdate(updateFile.browser_download_url, (file) => {
progress = file.progress;
launchInfo = `Downloading Update (${formatBytes(file.downloaded)}/${formatBytes(file.size)})...`;
});
progress = -1;
launchInfo = 'Update downloaded, installing...';
await installUpdate();
}}>Install Update now</Button
>
{/if}
{:else}
<Button
onclick={async () => {
if ($newVersion) {
@@ -585,6 +619,7 @@
}
}}>Update now</Button
>
{/if}
</div>
</AlertDialog.Content>
</AlertDialog.Root>