possibly fixed the auto updater, and fixed the node processes closing

This commit is contained in:
2026-09-01 19:39:27 -07:00
parent 414ef73e1d
commit 769c0dadcd
5 changed files with 90 additions and 37 deletions

34
main.js
View File

@@ -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);
});

View File

@@ -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) {

View File

@@ -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<String, String> {
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());

View File

@@ -256,24 +256,8 @@
</div>
</div>
</div>
</div>
</div>
<div id="view-error" class="view-state">
<div class="container">
<svg class="icon icon-error" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
<circle cx="12" cy="12" r="10" />
<line x1="12" y1="7" x2="12" y2="13" />
<circle cx="12" cy="17" r="1" />
</svg>
<h1>Couldn't start Vyla Home</h1>
<p id="error-msg"></p>
<div class="buttons">
<button class="primary" onclick="location.reload()">Try Again</button>
</div>
</div>
</div>
<script type="module">
@@ -581,15 +565,23 @@ void main() {
});
eventApi.listen("error", (e) => {
const data = e.payload || e;
if (data && data.message) {
setStatus(`Error: ${data.message}`, "#ef4444");
}
setStatus("Cleaning up background processes...", "#fca5a5");
try {
const core = window.__TAURI__?.core;
if (core) {
core.invoke("kill_orphans").finally(() => {
setTimeout(() => {
core.invoke("win_close").catch(() => {});
}, 500);
});
}
} catch (err) { }
});
}
btnYes.addEventListener("click", () => {
if (actionsEl) actionsEl.style.display = "none";
if (actionsEl) actionsEl.style.display = "none";
setStatus("Starting update installation...");
fetch("http://127.0.0.1:4891/update/yes", { method: "POST" }).catch(() => { });
});

View File

@@ -228,7 +228,8 @@ class UpdateClient {
}
async checkForUpdates() {
const releases = await this.fetchJson(RELEASES_API);
const cacheBuster = `?cb=${Date.now()}`;
const releases = await this.fetchJson(RELEASES_API + cacheBuster);
if (!releases || releases.length === 0) {
return null;
}