diff --git a/main.js b/main.js index 1c3746a..f037aeb 100644 --- a/main.js +++ b/main.js @@ -84,11 +84,20 @@ cmdApp.get('/__tauri_cmd/:cmd', (req, res) => { }); cmdApp.listen(4892, '127.0.0.1', () => debugLog("[CMD-SERVER] Dedicated command server listening on 127.0.0.1:4892")); +process.stdin.resume(); +process.stdin.on('end', () => { + debugLog('stdin closed - parent died. Self-terminating...'); + process.exit(0); +}); +process.stdin.on('error', () => { + process.exit(0); +}); + process.on('uncaughtException', (err) => { debugLog(`CRITICAL UNCAUGHT EXCEPTION: ${err.stack || err.message}`); - if (err.code === 'EPIPE') { + if (err.code === 'EPIPE' || err.code === 'EOF') { debugLog('Pipe to parent closed - parent process gone, exiting'); - process.exit(1); + process.exit(0); } try { sendToTauri('error', { message: err.message }); } catch (e) { } }); @@ -126,6 +135,9 @@ async function start() { const installBuild = async (release) => { const tempZipPath = path.join(APPDATA_DIR, 'download-temp.zip'); + if (fs.existsSync(tempZipPath)) { + try { fs.unlinkSync(tempZipPath); } catch (e) { } + } let attempts = 0; let downloadSuccess = false; @@ -367,17 +379,23 @@ process.on('exit', () => { if (serviceManager) { for (const name of Object.keys(serviceManager.processes)) { const proc = serviceManager.processes[name]; - if (proc && proc.child) { - try { proc.child.kill('SIGKILL'); } catch (e) { } + if (proc && proc.child && proc.child.pid) { + try { + if (process.platform === 'win32') { + require('child_process').spawnSync('taskkill', ['/F', '/T', '/PID', proc.child.pid.toString()], { stdio: 'ignore', windowsHide: true }); + } else { + process.kill(-proc.child.pid, 'SIGKILL'); + } + } catch (e) { } } } } }); -process.on('SIGINT', async () => { - if (expressServer) expressServer.close(); - if (playerExpressServer) playerExpressServer.close(); - if (serviceManager) await serviceManager.stopAll(); +process.on('SIGINT', () => { + process.exit(0); +}); +process.on('SIGTERM', () => { process.exit(0); }); diff --git a/patcher.js b/patcher.js index 834603c..586dc13 100644 --- a/patcher.js +++ b/patcher.js @@ -63,17 +63,24 @@ class Patcher { const fullPath = path.join(this.appDataPath, dir); if (fs.existsSync(fullPath)) { try { - fs.rmSync(fullPath, { recursive: true, force: true }); + const trashPath = path.join(this.appDataPath, `.trash_${dir}_${Date.now()}`); + fs.renameSync(fullPath, trashPath); + fs.rmSync(trashPath, { recursive: true, force: true }); } catch (e) { try { - const trashPath = fullPath + '.trash.' + Date.now(); - fs.renameSync(fullPath, trashPath); - } catch (renameErr) { - console.warn(`Could not remove or rename ${fullPath}. It will be overwritten.`); - } + fs.rmSync(fullPath, { recursive: true, force: true }); + } catch (err2) { } } } } + try { + const files = fs.readdirSync(this.appDataPath); + for (const file of files) { + if (file.startsWith('.trash_')) { + fs.rmSync(path.join(this.appDataPath, file), { recursive: true, force: true }); + } + } + } catch (e) { } } extractZipPayload(zipPath) { diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 65f46b7..85ff0c4 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -50,6 +50,15 @@ fn clean_path(path: &std::path::Path) -> String { } fn kill_child_process(child: &mut Child) { + #[cfg(windows)] + { + use std::os::windows::process::CommandExt; + const CREATE_NO_WINDOW: u32 = 0x08000000; + let _ = Command::new("taskkill") + .args(&["/F", "/T", "/PID", &child.id().to_string()]) + .creation_flags(CREATE_NO_WINDOW) + .output(); + } let _ = child.kill(); let _ = child.wait(); } @@ -482,6 +491,30 @@ fn open_new_window(app: tauri::AppHandle, url: String) -> Result<(), String> { } } +#[tauri::command] +async fn kill_orphans() -> Result<(), String> { + debug_log("[KILL] User requested orphan process kill"); + + #[cfg(windows)] + { + use std::os::windows::process::CommandExt; + const CREATE_NO_WINDOW: u32 = 0x08000000; + let _ = std::process::Command::new("taskkill") + .args(&["/F", "/T", "/IM", "node.exe"]) + .creation_flags(CREATE_NO_WINDOW) + .output(); + } + + #[cfg(not(windows))] + { + let _ = std::process::Command::new("pkill") + .args(&["-9", "-f", "node"]) + .output(); + } + + Ok(()) +} + #[tauri::command] fn get_logo_base64(app: tauri::AppHandle) -> Result { use std::io::Read; @@ -528,7 +561,8 @@ fn main() { win_close, win_drag, open_new_window, - get_logo_base64 + get_logo_base64, + kill_orphans ]) .manage(NodeServices(Mutex::new(None))) .setup(|app| { @@ -566,6 +600,7 @@ fn main() { .current_dir(&root_dir) .env("APPDATA_PATH", &app_data_str) .env("NODE_EXE", &node_bin) + .stdin(Stdio::piped()) .stdout(Stdio::piped()) .stderr(Stdio::piped()); diff --git a/ui/index.html b/ui/index.html index c232391..760354f 100644 --- a/ui/index.html +++ b/ui/index.html @@ -256,24 +256,8 @@ - - -
-
- - - - - - -

Couldn't start Vyla Home

-

- -
-
-