feat(process): shared child with stop command

This commit is contained in:
DecDuck
2024-12-30 15:37:29 +11:00
parent f737c73213
commit 65a7150bd3
6 changed files with 51 additions and 18 deletions
+4 -3
View File
@@ -57,6 +57,7 @@ const emit = defineEmits<{
(e: "launch"): void; (e: "launch"): void;
(e: "queue"): void; (e: "queue"): void;
(e: "uninstall"): void; (e: "uninstall"): void;
(e: "kill"): void;
}>(); }>();
const showDropdown = computed(() => props.status.type === GameStatusEnum.Installed || props.status.type === GameStatusEnum.SetupRequired); const showDropdown = computed(() => props.status.type === GameStatusEnum.Installed || props.status.type === GameStatusEnum.SetupRequired);
@@ -69,7 +70,7 @@ const styles: { [key in GameStatusEnum]: string } = {
[GameStatusEnum.Installed]: "bg-green-600 text-white hover:bg-green-500 focus-visible:outline-green-600", [GameStatusEnum.Installed]: "bg-green-600 text-white hover:bg-green-500 focus-visible:outline-green-600",
[GameStatusEnum.Updating]: "bg-zinc-800 text-white hover:bg-zinc-700 focus-visible:outline-zinc-700", [GameStatusEnum.Updating]: "bg-zinc-800 text-white hover:bg-zinc-700 focus-visible:outline-zinc-700",
[GameStatusEnum.Uninstalling]: "bg-zinc-800 text-white hover:bg-zinc-700 focus-visible:outline-zinc-700", [GameStatusEnum.Uninstalling]: "bg-zinc-800 text-white hover:bg-zinc-700 focus-visible:outline-zinc-700",
[GameStatusEnum.Running]: "bg-zinc-800 text-white hover:bg-zinc-700 focus-visible:outline-zinc-700" [GameStatusEnum.Running]: "bg-zinc-800 text-white focus-visible:outline-zinc-700"
}; };
const buttonNames: { [key in GameStatusEnum]: string } = { const buttonNames: { [key in GameStatusEnum]: string } = {
@@ -80,7 +81,7 @@ const buttonNames: { [key in GameStatusEnum]: string } = {
[GameStatusEnum.Installed]: "Play", [GameStatusEnum.Installed]: "Play",
[GameStatusEnum.Updating]: "Updating", [GameStatusEnum.Updating]: "Updating",
[GameStatusEnum.Uninstalling]: "Uninstalling", [GameStatusEnum.Uninstalling]: "Uninstalling",
[GameStatusEnum.Running]: "Running" [GameStatusEnum.Running]: "Stop"
}; };
const buttonIcons: { [key in GameStatusEnum]: Component } = { const buttonIcons: { [key in GameStatusEnum]: Component } = {
@@ -102,6 +103,6 @@ const buttonActions: { [key in GameStatusEnum]: () => void } = {
[GameStatusEnum.Installed]: () => emit("launch"), [GameStatusEnum.Installed]: () => emit("launch"),
[GameStatusEnum.Updating]: () => emit("queue"), [GameStatusEnum.Updating]: () => emit("queue"),
[GameStatusEnum.Uninstalling]: () => { }, [GameStatusEnum.Uninstalling]: () => { },
[GameStatusEnum.Running]: () => { } [GameStatusEnum.Running]: () => emit("kill")
}; };
</script> </script>
+20 -2
View File
@@ -23,6 +23,7 @@
@launch="() => launch()" @launch="() => launch()"
@queue="() => queue()" @queue="() => queue()"
@uninstall="() => uninstall()" @uninstall="() => uninstall()"
@kill="() => kill()"
:status="status" :status="status"
/> />
<a <a
@@ -235,7 +236,7 @@
</template> </template>
<template #buttons> <template #buttons>
<LoadingButton <LoadingButton
@click="() => install()" @click="() => install()"
:disabled=" :disabled="
!(versionOptions && versionOptions.length > 0 && !installDir) !(versionOptions && versionOptions.length > 0 && !installDir)
" "
@@ -299,7 +300,7 @@ const installDirs = ref<undefined | Array<string>>();
async function installFlow() { async function installFlow() {
installFlowOpen.value = true; installFlowOpen.value = true;
versionOptions.value = undefined; versionOptions.value = undefined;
installDirs.value = undefined installDirs.value = undefined;
try { try {
versionOptions.value = await invoke("fetch_game_verion_options", { versionOptions.value = await invoke("fetch_game_verion_options", {
@@ -357,4 +358,21 @@ async function queue() {
async function uninstall() { async function uninstall() {
await invoke("uninstall_game", { gameId: game.value.id }); await invoke("uninstall_game", { gameId: game.value.id });
} }
async function kill() {
try {
await invoke("kill_game", { gameId: game.value.id });
} catch (e) {
createModal(
ModalType.Notification,
{
title: `Couldn't stop "${game.value.mName}"`,
description: `Drop failed to stop "${game.value.mName}": ${e}`,
buttonText: "Close",
},
(e, c) => c()
);
console.error(e);
}
}
</script> </script>
+1
View File
@@ -987,6 +987,7 @@ dependencies = [
"serde", "serde",
"serde-binary", "serde-binary",
"serde_json", "serde_json",
"shared_child",
"tauri", "tauri",
"tauri-build", "tauri-build",
"tauri-plugin-deep-link", "tauri-plugin-deep-link",
+1
View File
@@ -44,6 +44,7 @@ chrono = "0.4.38"
tauri-plugin-os = "2" tauri-plugin-os = "2"
boxcar = "0.2.7" boxcar = "0.2.7"
umu-wrapper-lib = "0.1.0" umu-wrapper-lib = "0.1.0"
shared_child = "1.0.1"
[dependencies.tauri] [dependencies.tauri]
version = "2.1.1" version = "2.1.1"
@@ -25,5 +25,5 @@ pub fn kill_game(
) -> Result<(), String> { ) -> Result<(), String> {
let state_lock = state.lock().unwrap(); let state_lock = state.lock().unwrap();
let mut process_manager_lock = state_lock.process_manager.lock().unwrap(); let mut process_manager_lock = state_lock.process_manager.lock().unwrap();
process_manager_lock.terminate_child(game_id).map_err(|x| x.to_string()) process_manager_lock.kill_game(game_id).map_err(|x| x.to_string())
} }
@@ -1,9 +1,16 @@
use std::{ use std::{
collections::HashMap, fs::{File, OpenOptions}, io, path::{Path, PathBuf}, process::{Child, Command, ExitStatus}, sync::{Arc, Mutex}, thread::spawn collections::HashMap,
fs::{File, OpenOptions},
io,
path::{Path, PathBuf},
process::{Child, Command, ExitStatus},
sync::{Arc, Mutex},
thread::spawn,
}; };
use log::{info, warn}; use log::{info, warn};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use shared_child::SharedChild;
use tauri::{AppHandle, Manager}; use tauri::{AppHandle, Manager};
use umu_wrapper_lib::command_builder::UmuCommandBuilder; use umu_wrapper_lib::command_builder::UmuCommandBuilder;
@@ -17,7 +24,7 @@ use crate::{
pub struct ProcessManager<'a> { pub struct ProcessManager<'a> {
current_platform: Platform, current_platform: Platform,
log_output_dir: PathBuf, log_output_dir: PathBuf,
processes: HashMap<String, Arc<Mutex<Child>>>, processes: HashMap<String, Arc<SharedChild>>,
app_handle: AppHandle, app_handle: AppHandle,
game_launchers: HashMap<(Platform, Platform), &'a (dyn ProcessHandler + Sync + Send + 'static)>, game_launchers: HashMap<(Platform, Platform), &'a (dyn ProcessHandler + Sync + Send + 'static)>,
} }
@@ -75,14 +82,18 @@ impl ProcessManager<'_> {
*/ */
(absolute_exe, Vec::new()) (absolute_exe, Vec::new())
} }
pub fn terminate_child(&mut self, game_id: String) -> Result<(), io::Error> { pub fn kill_game(&mut self, game_id: String) -> Result<(), io::Error> {
return match self.processes.get(&game_id) { return match self.processes.get(&game_id) {
Some(child) => { Some(child) => {
let mut lock = child.lock().unwrap(); child.kill()?;
lock.kill() child.wait()?;
Ok(())
}, },
None => Err(io::Error::new(io::ErrorKind::NotFound, "Game ID not running")), None => Err(io::Error::new(
} io::ErrorKind::NotFound,
"Game ID not running",
)),
};
} }
fn on_process_finish(&mut self, game_id: String, result: Result<ExitStatus, std::io::Error>) { fn on_process_finish(&mut self, game_id: String, result: Result<ExitStatus, std::io::Error>) {
@@ -123,6 +134,8 @@ impl ProcessManager<'_> {
let status = GameStatusManager::fetch_state(&game_id); let status = GameStatusManager::fetch_state(&game_id);
push_game_update(&self.app_handle, game_id.clone(), status); push_game_update(&self.app_handle, game_id.clone(), status);
// TODO better management
} }
pub fn valid_platform(&self, platform: &Platform) -> Result<bool, String> { pub fn valid_platform(&self, platform: &Platform) -> Result<bool, String> {
@@ -235,7 +248,8 @@ impl ProcessManager<'_> {
error_file, error_file,
)?; )?;
let launch_process_handle = Arc::new(Mutex::new(launch_process)); let launch_process_handle =
Arc::new(SharedChild::new(launch_process).map_err(|e| e.to_string())?);
db_lock db_lock
.games .games
@@ -253,8 +267,7 @@ impl ProcessManager<'_> {
let wait_thread_game_id = game_id.clone(); let wait_thread_game_id = game_id.clone();
spawn(move || { spawn(move || {
let mut child_handle = wait_thread_handle.lock().unwrap(); let result: Result<ExitStatus, std::io::Error> = launch_process_handle.wait();
let result: Result<ExitStatus, std::io::Error> = child_handle.wait();
let app_state = wait_thread_apphandle.state::<Mutex<AppState>>(); let app_state = wait_thread_apphandle.state::<Mutex<AppState>>();
let app_state_handle = app_state.lock().unwrap(); let app_state_handle = app_state.lock().unwrap();
@@ -266,10 +279,9 @@ impl ProcessManager<'_> {
// But just to explicit about it // But just to explicit about it
drop(process_manager_handle); drop(process_manager_handle);
drop(app_state_handle); drop(app_state_handle);
drop(child_handle);
}); });
self.processes.insert(game_id, launch_process_handle); self.processes.insert(game_id, wait_thread_handle);
info!("finished spawning process"); info!("finished spawning process");