diff --git a/unshell-gui/src/payload_config/mod.rs b/unshell-gui/src/payload_config/mod.rs index fcee4b2..96282ee 100644 --- a/unshell-gui/src/payload_config/mod.rs +++ b/unshell-gui/src/payload_config/mod.rs @@ -13,6 +13,9 @@ pub struct PayloadConfig { impl PayloadConfig { pub fn update(&mut self, ui: &mut egui::Ui) { + if ui.button("export").clicked() { + crate::log(&self.config_struct.export()); + } // ui.heading("Test"); self.config_struct.update(ui); } diff --git a/unshell-gui/src/payload_config/structs.rs b/unshell-gui/src/payload_config/structs.rs index de7d633..f20663d 100644 --- a/unshell-gui/src/payload_config/structs.rs +++ b/unshell-gui/src/payload_config/structs.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use egui::TextEdit; +use serde_json::Value; #[derive(serde::Deserialize, serde::Serialize)] enum ConfigStructField { @@ -13,27 +14,20 @@ enum ConfigStructField { }, Integer { default: i32, - min: Option, - max: Option, + min: Option, + max: Option, }, + // Checkbox + // Dropdown + // Collapsing header + // Slider + // ... } -#[derive(serde::Deserialize, serde::Serialize)] -enum ConfigStructValue { - String(String), - Integer(i32), -} - -// #[derive(serde::Deserialize, serde::Serialize)] -// struct ConfigStruct { -// id: String, -// field: ConfigStructField, -// } - #[derive(serde::Deserialize, serde::Serialize)] pub struct Config { config: Vec<(String, ConfigStructField)>, - state: HashMap, + state: HashMap, } impl Config { @@ -58,20 +52,19 @@ impl Config { max_length, protected, } => { - let value = - if let Some(ConfigStructValue::String(value)) = self.state.get_mut(id) { + let value = if let Some(Value::String(value)) = self.state.get_mut(id) { + value + } else { + self.state.insert( + id.clone(), + Value::String(default.clone().unwrap_or(String::new())), + ); + if let Some(Value::String(value)) = self.state.get_mut(id) { value } else { - self.state.insert( - id.clone(), - ConfigStructValue::String(default.clone().unwrap_or(String::new())), - ); - if let Some(ConfigStructValue::String(value)) = self.state.get_mut(id) { - value - } else { - unreachable!() - } - }; + unreachable!() + } + }; let mut widget = TextEdit::singleline(value).password(*protected); @@ -100,6 +93,10 @@ impl Config { // ConfigStructField::Integer { default, min, max } => todo!(), // } } + + pub fn export(&self) -> String { + serde_json::to_string(&self.config).unwrap() + } } pub fn default_configurable() -> Config { diff --git a/unshell-server/Cargo.lock b/unshell-server/Cargo.lock index 5540962..95ecd2c 100644 --- a/unshell-server/Cargo.lock +++ b/unshell-server/Cargo.lock @@ -496,6 +496,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92773504d58c093f6de2459af4af33faa518c13451eb8f2b5698ed3d36e7c813" +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + [[package]] name = "find-msvc-tools" version = "0.1.5" @@ -602,6 +608,12 @@ dependencies = [ "wasip2", ] +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + [[package]] name = "headers" version = "0.4.1" @@ -759,6 +771,16 @@ dependencies = [ "cc", ] +[[package]] +name = "indexmap" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +dependencies = [ + "equivalent", + "hashbrown", +] + [[package]] name = "inout" version = "0.1.4" @@ -1205,6 +1227,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "serde_spanned" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +dependencies = [ + "serde_core", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -1454,6 +1485,45 @@ dependencies = [ "syn 2.0.111", ] +[[package]] +name = "toml" +version = "0.9.9+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb5238e643fc34a1d5d7e753e1532a91912d74b63b92b3ea51fde8d1b7bc79dd" +dependencies = [ + "indexmap", + "serde_core", + "serde_spanned", + "toml_datetime", + "toml_parser", + "toml_writer", + "winnow", +] + +[[package]] +name = "toml_datetime" +version = "0.7.4+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe3cea6b2aa3b910092f6abd4053ea464fab5f9c170ba5e9a6aead16ec4af2b6" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_parser" +version = "1.0.5+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c03bee5ce3696f31250db0bbaff18bc43301ce0e8db2ed1f07cbb2acf89984c" +dependencies = [ + "winnow", +] + +[[package]] +name = "toml_writer" +version = "1.0.5+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9cd6190959dce0994aa8970cd32ab116d1851ead27e866039acaf2524ce44fa" + [[package]] name = "tower" version = "0.5.2" @@ -1570,6 +1640,7 @@ dependencies = [ "sled", "static_init", "tokio", + "toml", "unshell-lib", "unshell-obfuscate", ] @@ -1828,6 +1899,12 @@ version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" + [[package]] name = "wit-bindgen" version = "0.46.0" diff --git a/unshell-server/Cargo.toml b/unshell-server/Cargo.toml index dc579da..6167182 100644 --- a/unshell-server/Cargo.toml +++ b/unshell-server/Cargo.toml @@ -22,3 +22,4 @@ chrono = "0.4.42" static_init = "1.0.4" clap = {version = "4.5.53", features = ["derive"]} sled = "0.34.7" +toml = "0.9.9" diff --git a/unshell-server/src/config/mod.rs b/unshell-server/src/config/mod.rs index 8b13789..2029800 100644 --- a/unshell-server/src/config/mod.rs +++ b/unshell-server/src/config/mod.rs @@ -1 +1,97 @@ +use std::{ + collections::HashMap, + error::Error, + fs, + path::{Path, PathBuf}, +}; +use unshell_lib::debug; + +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +pub struct ComponentMetadata { + name: String, + description: Option, + version: Option, + authors: Option>, + + // Struct to contain build information + build_config: BuildConfig, + + // Other components that can be pointed to by this component + #[serde(default)] + child_components: Vec, + // config: Option>, +} + +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +struct BuildConfig { + // Cargo feature list of a component + // (Name, Description) + #[serde(default)] + features: HashMap, +} + +#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)] +enum ConfigStructField { + Header(String), + Text(String), + String { + // Default value of string edit in struct + #[serde(default)] + default: String, + max_length: Option, + // Display string edit as password + #[serde(default)] + protected: Option, + }, + Integer { + // Default value of integer in struct + #[serde(default)] + default: i32, + min: Option, + max: Option, + }, + // Checkbox + // Dropdown + // Collapsing header + // Slider + // ... +} + +pub fn load_config(path: &PathBuf) -> Result, Box> { + let path_absolute = fs::canonicalize(path.clone())?; + debug!("Loading data from path: `{}`", path_absolute); + + // Read string as path + let config_str = fs::read_to_string(path.clone())?; + + // Load config from String + let config = toml::from_str::(&config_str)?; + + if config.child_components.is_empty() { + Ok(vec![config]) + } else { + let parent_path = path_absolute.parent().expect("Path must have parent"); + + let mut config_vec = vec![]; + + // Load each child component + for component_path in &config.child_components { + let path = Path::join(parent_path, component_path); + let mut config = load_config(&path)?; + config_vec.append(&mut config); + } + + config_vec.insert(0, config); + + Ok(config_vec) + } +} + +// pub fn parse_toml() -> ComponentMetadata { +// let data = include_str!("../../test.toml"); + +// let config = toml::from_str(data).unwrap(); + +// config +// } diff --git a/unshell-server/src/main.rs b/unshell-server/src/main.rs index 3560361..765781c 100644 --- a/unshell-server/src/main.rs +++ b/unshell-server/src/main.rs @@ -19,6 +19,10 @@ pub struct Args { /// Name of database folder #[clap(short, long, default_value_t = DATABASE_NAME.clone())] database_name: String, + + /// Load config from path + #[clap(short, long, value_parser)] + pub config: Option>, } #[tokio::main] diff --git a/unshell-server/src/server/mod.rs b/unshell-server/src/server/mod.rs index e5f0a2a..90f10e2 100644 --- a/unshell-server/src/server/mod.rs +++ b/unshell-server/src/server/mod.rs @@ -1,22 +1,18 @@ mod database; mod manager; -use std::sync::{Arc, Mutex}; - -use unshell_lib::module::Manager; - -use crate::SERVER_CONFIG; - #[derive(Clone)] pub struct Server { - pub manager: Arc>, + pub config: Vec, + // pub manager: Arc>, pub db: sled::Db, } impl Server { pub fn new(database: String) -> Self { Self { - manager: Manager::start(&SERVER_CONFIG, Vec::new()), + config: Vec::new(), + // manager: Manager::start(&SERVER_CONFIG, Vec::new()), db: sled::open(database).expect("Failed to open database"), } } @@ -25,6 +21,6 @@ impl Server { impl Drop for Server { fn drop(&mut self) { self.db.flush().expect("Failed to flush database on drop"); - Manager::join(self.manager.clone()); + // Manager::join(self.manager.clone()); } }