use crate::firmware::firmware_state::{AppCrashesStep, FirmwareState, HubHomeStep}; use crate::firmware::prometeu_context::PrometeuContext; use prometeu_hal::log::LogSource; use prometeu_system::process::ProcessKind; use prometeu_system::task::{TaskId, TaskState}; use prometeu_system::{CrashReport, SystemProfileAction}; #[derive(Debug, Clone)] pub struct ShellRunningStep { pub task_id: TaskId, } impl ShellRunningStep { pub fn new(task_id: TaskId) -> Self { Self { task_id } } pub fn on_enter(&mut self, ctx: &mut PrometeuContext) { ctx.os.info(LogSource::Hub, "Entering ShellRunning".to_string()); } pub fn on_update(&mut self, ctx: &mut PrometeuContext) -> Option { let Some(task_state) = ctx.os.lifecycle().task_state(self.task_id) else { let report = CrashReport::VmPanic { message: format!("ShellRunningStep has no task for {:?}", self.task_id), pc: None, }; return Some(FirmwareState::AppCrashes(AppCrashesStep { report })); }; match task_state { TaskState::Foreground => { // Continue below. } TaskState::Closed => { return Some(FirmwareState::HubHome(HubHomeStep)); } TaskState::Crashed => { let report = CrashReport::VmPanic { message: format!("Shell task {:?} is already crashed", self.task_id), pc: None, }; return Some(FirmwareState::AppCrashes(AppCrashesStep { report })); } TaskState::Suspended | TaskState::Background => { let report = CrashReport::VmPanic { message: format!( "ShellRunningStep expected foreground task {:?}, got {:?}", self.task_id, task_state, ), pc: None, }; return Some(FirmwareState::AppCrashes(AppCrashesStep { report })); } } let process_kind = match ctx.os.lifecycle().process_kind_for_task(self.task_id) { Ok(process_kind) => process_kind, Err(error) => { let report = CrashReport::VmPanic { message: format!( "ShellRunningStep cannot resolve process for {:?}: {:?}", self.task_id, error, ), pc: None, }; return Some(FirmwareState::AppCrashes(AppCrashesStep { report })); } }; let outcome = match process_kind { ProcessKind::VmShell => { ctx.hub.update_shell_profile(ctx.os, ctx.vm, ctx.signals, ctx.platform) } ProcessKind::NativeShell => ctx.hub.update_native_shell_profile(ctx.os, ctx.platform), ProcessKind::VmGame => { let report = CrashReport::VmPanic { message: format!( "ShellRunningStep expected shell process for {:?}, got VmGame", self.task_id, ), pc: None, }; return Some(FirmwareState::AppCrashes(AppCrashesStep { report })); } }; if let Some(report) = outcome.crash { let _ = ctx.os.lifecycle().crash_task(self.task_id, Some(&report)); return Some(FirmwareState::AppCrashes(AppCrashesStep { report })); } if outcome.action == Some(SystemProfileAction::CloseShell) { self.close_current_shell(ctx); return Some(FirmwareState::HubHome(HubHomeStep)); } if !ctx.os.windows().focused_window_belongs_to_task(self.task_id) { ctx.os.info( LogSource::Hub, format!( "Closing shell task {:?}: focused window does not belong to task", self.task_id, ), ); self.close_current_shell(ctx); return Some(FirmwareState::HubHome(HubHomeStep)); } None } fn close_current_shell(&mut self, ctx: &mut PrometeuContext) { if let Err(error) = ctx.os.lifecycle().close_task(self.task_id) { ctx.os.error( LogSource::Hub, format!("Failed to close shell task {:?}: {:?}", self.task_id, error), ); } } pub fn on_exit(&mut self, ctx: &mut PrometeuContext) { ctx.os.info(LogSource::Hub, "Exiting ShellRunning".to_string()); } }