123 lines
3.5 KiB
Rust
123 lines
3.5 KiB
Rust
use server_framework::Server;
|
|
use types::bounded::CapSlot;
|
|
|
|
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 {
|
|
/// The capability `Kill` is invoked on.
|
|
process: CapSlot,
|
|
}
|
|
|
|
pub struct SessionServer {
|
|
apps: [Option<AppEntry>; MAX_APPS],
|
|
app_count: usize,
|
|
running: [Option<RunningApp>; MAX_APPS],
|
|
active: Option<AppId>,
|
|
/// Lets the server create processes; without one, Launch fails.
|
|
create_cap: Option<CapSlot>,
|
|
}
|
|
|
|
impl SessionServer {
|
|
pub fn new(create_cap: Option<CapSlot>) -> Self {
|
|
Self {
|
|
apps: [const { None }; MAX_APPS],
|
|
app_count: 0,
|
|
running: [const { None }; MAX_APPS],
|
|
active: None,
|
|
create_cap,
|
|
}
|
|
}
|
|
|
|
/// Adds an app to the menu; `None` once the table is full.
|
|
pub fn register_app(&mut self, name: &'static str, path: &'static str) -> Option<AppId> {
|
|
let slot = self.apps.get_mut(self.app_count)?;
|
|
*slot = Some(AppEntry {
|
|
name,
|
|
path,
|
|
registered: true,
|
|
});
|
|
let id = AppId::new(self.app_count as u16);
|
|
self.app_count += 1;
|
|
Some(id)
|
|
}
|
|
|
|
pub fn app_count(&self) -> usize {
|
|
self.app_count
|
|
}
|
|
|
|
pub fn active_app(&self) -> Option<AppId> {
|
|
self.active
|
|
}
|
|
|
|
/// The running-table entry for `app`; `None` for ids past the table,
|
|
/// which come straight from clients.
|
|
fn running_mut(&mut self, app: AppId) -> Option<&mut Option<RunningApp>> {
|
|
self.running.get_mut(app.raw() as usize)
|
|
}
|
|
|
|
fn launch_app(&mut self, app: AppId) -> SessionResponse {
|
|
let idx = app.raw() as usize;
|
|
if idx >= self.app_count {
|
|
return SessionResponse::NotFound;
|
|
}
|
|
|
|
if self.apps.get(idx).is_none_or(Option::is_none) {
|
|
return SessionResponse::NotFound;
|
|
}
|
|
if self.running_mut(app).is_none_or(|r| r.is_some()) {
|
|
return SessionResponse::Error;
|
|
}
|
|
let Some(process) = self.create_cap.and_then(libkos::syscall::create_process) else {
|
|
return SessionResponse::Error;
|
|
};
|
|
if let Some(r) = self.running_mut(app) {
|
|
*r = Some(RunningApp { process });
|
|
}
|
|
self.active = Some(app);
|
|
|
|
SessionResponse::Launched { app }
|
|
}
|
|
|
|
fn kill_app(&mut self, app: AppId) -> SessionResponse {
|
|
match self.running_mut(app).and_then(Option::take) {
|
|
Some(running) => {
|
|
let _ = libkos::syscall::kill(running.process);
|
|
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,
|
|
},
|
|
}
|
|
}
|
|
}
|