From c74d091b8ece69abc31c04f50c694342accdf2d8 Mon Sep 17 00:00:00 2001 From: LynithDev <61880709+LynithDev@users.noreply.github.com> Date: Sun, 22 Dec 2024 12:28:37 +0100 Subject: [PATCH] LAUNCHER-12 fix: frontend not reacting to game close --- .../src/ui/hooks/useNotifications.tsx | 9 ++- .../src/ui/pages/cluster/ClusterGame.tsx | 7 ++ apps/frontend/src/utils/index.ts | 9 +++ packages/core/src/store/processor.rs | 74 +++++++++++-------- 4 files changed, 66 insertions(+), 33 deletions(-) diff --git a/apps/frontend/src/ui/hooks/useNotifications.tsx b/apps/frontend/src/ui/hooks/useNotifications.tsx index a874084a..70b79e4f 100644 --- a/apps/frontend/src/ui/hooks/useNotifications.tsx +++ b/apps/frontend/src/ui/hooks/useNotifications.tsx @@ -1,6 +1,7 @@ import type { UnlistenFn } from '@tauri-apps/api/event'; import type { NotificationData } from '~ui/components/overlay/notifications/NotificationComponent'; import { events } from '@onelauncher/client/bindings'; +import { randomString } from '~utils'; import { type Accessor, type Context, createContext, createSignal, onCleanup, onMount, type ParentProps, type Signal, useContext } from 'solid-js'; type Notifications = Record; @@ -8,6 +9,7 @@ type Notifications = Record; interface HookReturn { list: Accessor; set: (id: string, data: NotificationData) => void; + create: (data: NotificationData) => void; clear: () => void; } @@ -44,11 +46,14 @@ export function NotificationProvider(props: ParentProps) { function useNotifications(): HookReturn { const [notifications, setNotifications] = useContext(NotificationContext); - return { + const ctx = { list: notifications, set: (id, data) => setNotifications(notifications => ({ ...notifications, [id]: data })), + create: data => ctx.set(randomString(6), data), clear: () => setNotifications({}), - }; + } satisfies HookReturn; + + return ctx; } export default useNotifications; diff --git a/apps/frontend/src/ui/pages/cluster/ClusterGame.tsx b/apps/frontend/src/ui/pages/cluster/ClusterGame.tsx index 740df6ec..7bc9d9f9 100644 --- a/apps/frontend/src/ui/pages/cluster/ClusterGame.tsx +++ b/apps/frontend/src/ui/pages/cluster/ClusterGame.tsx @@ -11,6 +11,7 @@ import Modal, { createModal } from '~ui/components/overlay/Modal'; import Sidebar from '~ui/components/Sidebar'; import useClusterContext from '~ui/hooks/useCluster'; import useCommand from '~ui/hooks/useCommand'; +import useNotifications from '~ui/hooks/useNotifications'; import { createSignal, onCleanup, onMount } from 'solid-js'; import { render } from 'solid-js/web'; @@ -26,6 +27,7 @@ function ClusterGame() { const [params] = useSearchParams(); const [log] = useCommand(() => bridge.commands.getClusterLog(cluster()!.uuid, 'latest.log')); const [isRunning, setIsRunning] = createSignal(true); + const notifications = useNotifications(); const [unlisten, setUnlisten] = createSignal(); let codeRef!: HTMLElement; @@ -39,6 +41,11 @@ function ClusterGame() { render(() => , codeRef); else if (event.payload.event === 'finished') setIsRunning(false); + else if (event.payload.event === 'modified') + notifications.create({ + title: 'Process Status', + message: event.payload.message, + }); }); setUnlisten(() => unlisten); diff --git a/apps/frontend/src/utils/index.ts b/apps/frontend/src/utils/index.ts index f1775136..fb49a83f 100644 --- a/apps/frontend/src/utils/index.ts +++ b/apps/frontend/src/utils/index.ts @@ -54,6 +54,15 @@ export function int32ToBigInt([high, low]: [number, number]): bigint { return (BigInt(high | 0) << 32n) | BigInt(low >>> 0); } +export function randomString(len: number = 6, charSet: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789') { + let randomString = ''; + for (let i = 0; i < len; i++) { + const randomPos = Math.floor(Math.random() * charSet.length); + randomString += charSet.substring(randomPos, randomPos + 1); + } + return randomString; +} + export function abbreviateNumber(n: number | bigint, locale: string = 'en-US'): string { return new Intl.NumberFormat(locale, { notation: 'compact', diff --git a/packages/core/src/store/processor.rs b/packages/core/src/store/processor.rs index a70a59f9..c4e38fb2 100644 --- a/packages/core/src/store/processor.rs +++ b/packages/core/src/store/processor.rs @@ -13,7 +13,7 @@ use uuid::Uuid; use crate::api::cluster; use crate::constants::PROCESSOR_FILE; -use crate::proxy::send::send_process; +use crate::proxy::send::{send_ingress, send_message, send_process}; use crate::proxy::ProcessPayloadType; use crate::utils::http::read_json; use crate::State; @@ -427,7 +427,7 @@ impl Processor { #[cfg(target_os = "linux")] { - if enable_gamemode.is_some_and(|x| x == true) { + if enable_gamemode.is_some_and(|x| x) { if let Err(err) = onelauncher_gamemode::request_start_for_wrapper(pid) { tracing::warn!("failed to enable gamemode, continuing: {}", err); }; @@ -654,8 +654,8 @@ impl Processor { }); tokio::spawn(async { - let state = State::get(); - let state = match state.await { + let state = State::get().await; + let state = match state { Ok(state) => state, Err(err) => { tracing::warn!("failed to get state: {}", err); @@ -689,47 +689,59 @@ impl Processor { } let post = if let Some(hook) = post { - let mut cmd = hook.split(' '); - if let Some(c) = cmd.next() { - let mut c = Command::new(c); - c.args(cmd).current_dir(cluster_path.full_path().await?); - Some(c) - } else { + if hook.is_empty() { None + } else { + let mut cmd = hook.split(' '); + if let Some(c) = cmd.next() { + let mut c = Command::new(c); + c.args(cmd).current_dir(cluster_path.full_path().await?); + Some(c) + } else { + None + } } } else { None }; if let Some(mut m_c) = post { - { - let mut current_child: tokio::sync::RwLockWriteGuard<'_, ChildType> = - current_child.write().await; - let new_child = m_c.spawn().map_err(IOError::from)?; - current_pid = new_child - .id() - .ok_or_else(|| anyhow::anyhow!("process failed, couldnt get pid"))?; - *current_child = ChildType::ChildProcess(new_child); - } + let result = { + { + let mut current_child: tokio::sync::RwLockWriteGuard<'_, ChildType> = + current_child.write().await; - send_process( - uuid, - current_pid, - ProcessPayloadType::Modified, - "running post hook", - ) - .await?; + let new_child = m_c.spawn().map_err(IOError::from)?; + + current_pid = new_child + .id() + .ok_or_else(|| anyhow::anyhow!("process failed, couldnt get pid"))?; + + *current_child = ChildType::ChildProcess(new_child); + }; + + send_process( + uuid, + current_pid, + ProcessPayloadType::Modified, + "running post hook", + ) + .await?; - loop { let value = current_child.write().await.try_wait(); - if let Some(stat) = value? { + + if let Ok(Some(stat)) = value { exit_status = stat; - break; } - tokio::time::sleep(tokio::time::Duration::from_millis(10)).await; + Ok::<(), crate::Error>(()) + }; + + if let Err(err) = result { + tracing::error!("failed to run post hook: {err}"); + let _ = send_message(format!("failed to run post hook: {err}").as_str()).await; } - } + }; send_process( uuid,