120 lines
3.2 KiB
Rust
120 lines
3.2 KiB
Rust
use super::client::{Client, get_env};
|
|
use crate::nodes::{Node, root::ClientState, spatial::Spatial};
|
|
use glam::Mat4;
|
|
use parking_lot::Mutex;
|
|
use rustc_hash::FxHashMap;
|
|
use serde::{Deserialize, Serialize};
|
|
use std::{
|
|
path::{Path, PathBuf},
|
|
process::Command,
|
|
sync::Arc,
|
|
};
|
|
|
|
lazy_static::lazy_static! {
|
|
pub static ref CLIENT_STATES: Mutex<FxHashMap<String, Arc<ClientStateParsed>>> = Default::default();
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
pub struct LaunchInfo {
|
|
pub cmdline: Vec<String>,
|
|
pub cwd: PathBuf,
|
|
pub env: FxHashMap<String, String>,
|
|
}
|
|
impl LaunchInfo {
|
|
fn from_client(client: &Client) -> Option<Self> {
|
|
Some(LaunchInfo {
|
|
cmdline: client.get_cmdline()?,
|
|
cwd: client.get_cwd()?,
|
|
env: get_env(client.pid?).ok()?,
|
|
})
|
|
}
|
|
}
|
|
|
|
#[derive(Debug, Serialize, Deserialize)]
|
|
pub struct ClientStateParsed {
|
|
pub launch_info: Option<LaunchInfo>,
|
|
pub data: Vec<u8>,
|
|
pub root: Mat4,
|
|
pub spatial_anchors: FxHashMap<String, Mat4>,
|
|
}
|
|
impl ClientStateParsed {
|
|
pub fn from_deserialized(client: &Client, state: ClientState) -> Self {
|
|
ClientStateParsed {
|
|
launch_info: LaunchInfo::from_client(client),
|
|
data: state.data.unwrap_or_default(),
|
|
root: Self::spatial_transform(client, state.root).unwrap_or_default(),
|
|
spatial_anchors: state
|
|
.spatial_anchors
|
|
.into_iter()
|
|
.filter_map(|(k, v)| Some((k, Self::spatial_transform(client, v)?)))
|
|
.collect(),
|
|
}
|
|
}
|
|
fn spatial_transform(client: &Client, id: u64) -> Option<Mat4> {
|
|
let node = client.scenegraph.get_node(id)?;
|
|
let spatial = node.get_aspect::<Spatial>().ok()?;
|
|
Some(spatial.global_transform())
|
|
}
|
|
|
|
pub fn token(self) -> String {
|
|
let token = nanoid::nanoid!();
|
|
CLIENT_STATES.lock().insert(token.clone(), Arc::new(self));
|
|
token
|
|
}
|
|
pub fn from_file(file: &Path) -> Option<Self> {
|
|
let file_string = std::fs::read_to_string(file).ok()?;
|
|
toml::from_str(&file_string).ok()
|
|
}
|
|
pub fn to_file(&self, directory: &Path) {
|
|
let app_name = self
|
|
.launch_info
|
|
.as_ref()
|
|
.map(|l| l.cmdline.first().unwrap().split('/').next_back().unwrap())
|
|
.unwrap_or("unknown");
|
|
let state_file_path = directory
|
|
.join(format!("{app_name}-{}", nanoid::nanoid!()))
|
|
.with_extension("toml");
|
|
|
|
std::fs::write(state_file_path, toml::to_string(&self).unwrap()).unwrap();
|
|
}
|
|
|
|
pub fn apply_to(&self, client: &Arc<Client>) -> ClientState {
|
|
if let Some(root) = client.root.get() {
|
|
root.set_transform(self.root)
|
|
}
|
|
ClientState {
|
|
data: Some(self.data.clone()),
|
|
root: 0,
|
|
spatial_anchors: self
|
|
.spatial_anchors
|
|
.iter()
|
|
.map(|(k, v)| {
|
|
let node = Node::generate(client, true).add_to_scenegraph().unwrap();
|
|
Spatial::add_to(&node, None, *v, false);
|
|
(k.clone(), node.get_id())
|
|
})
|
|
.collect(),
|
|
}
|
|
}
|
|
pub fn launch_command(self) -> Option<Command> {
|
|
let launch_info = self.launch_info.as_ref()?;
|
|
let mut cmdline = launch_info.cmdline.iter();
|
|
let mut command = Command::new(cmdline.next()?);
|
|
command.args(cmdline);
|
|
command.current_dir(&launch_info.cwd);
|
|
command.envs(launch_info.env.iter());
|
|
command.env("STARDUST_STARTUP_TOKEN", self.token());
|
|
Some(command)
|
|
}
|
|
}
|
|
impl Default for ClientStateParsed {
|
|
fn default() -> Self {
|
|
Self {
|
|
launch_info: None,
|
|
data: Default::default(),
|
|
root: Mat4::IDENTITY,
|
|
spatial_anchors: Default::default(),
|
|
}
|
|
}
|
|
}
|