use server_framework::Server; use types::bounded::CapSlot; use types::id::ProcessId; use crate::protocol::{AppId, SessionRequest, SessionResponse}; const MAX_APPS: usize = 16; #[derive(Clone, Copy)] pub struct AppEntry { pub name: &'static str, pub path: &'static str, pub registered: bool, } #[derive(Clone, Copy)] struct RunningApp { app: AppId, pid: ProcessId, } pub struct SessionServer { apps: [Option; MAX_APPS], app_count: usize, running: [Option; MAX_APPS], active: Option, create_cap: CapSlot, } impl SessionServer { pub fn new(create_cap: CapSlot) -> Self { Self { apps: [const { None }; MAX_APPS], app_count: 0, running: [const { None }; MAX_APPS], active: None, create_cap, } } pub fn register_app(&mut self, name: &'static str, path: &'static str) -> AppId { let id = AppId::new(self.app_count as u16); self.apps[self.app_count] = Some(AppEntry { name, path, registered: true }); self.app_count += 1; id } pub fn app_count(&self) -> usize { self.app_count } pub fn active_app(&self) -> Option { self.active } fn is_running(&self, app: AppId) -> bool { self.running[app.raw() as usize].is_some() } fn launch_app(&mut self, app: AppId) -> SessionResponse { let idx = app.raw() as usize; if idx >= self.app_count { return SessionResponse::NotFound; } if self.is_running(app) { return SessionResponse::Error; } let _app_entry = match &self.apps[idx] { Some(entry) => entry, None => return SessionResponse::NotFound, }; let process_cap = match userspace::syscall::create_process(self.create_cap) { Some(cap) => cap, None => return SessionResponse::Error, }; let pid = ProcessId::from_raw(process_cap.value() as u16); self.running[idx] = Some(RunningApp { app, pid }); self.active = Some(app); SessionResponse::Launched { app } } fn kill_app(&mut self, app: AppId) -> SessionResponse { let idx = app.raw() as usize; match self.running[idx].take() { Some(_running) => { if self.active == Some(app) { self.active = None; } SessionResponse::Killed } None => SessionResponse::NotFound, } } } impl Server for SessionServer { type Request = SessionRequest; type Response = SessionResponse; fn handle(&mut self, request: SessionRequest) -> SessionResponse { match request { SessionRequest::Launch { app } => self.launch_app(app), SessionRequest::Kill { app } => self.kill_app(app), SessionRequest::ListApps => SessionResponse::AppList { count: self.app_count }, SessionRequest::ActiveApp => match self.active { Some(app) => SessionResponse::Active { app }, None => SessionResponse::NotFound, }, } } }