mirror of
https://github.com/Astatin3/unshell.git
synced 2026-06-08 22:38:01 -06:00
Configurable Struct
This commit is contained in:
@@ -67,7 +67,8 @@ impl Config {
|
|||||||
state_lock.trees = Some(response);
|
state_lock.trees = Some(response);
|
||||||
state_lock.is_requesting = false;
|
state_lock.is_requesting = false;
|
||||||
drop(state_lock);
|
drop(state_lock);
|
||||||
});
|
})
|
||||||
|
.unwrap();
|
||||||
} else if tree_list_none && is_requesting {
|
} else if tree_list_none && is_requesting {
|
||||||
ui.spinner();
|
ui.spinner();
|
||||||
}
|
}
|
||||||
@@ -92,7 +93,8 @@ impl Config {
|
|||||||
state_lock.tree_keys = Some(response.unwrap());
|
state_lock.tree_keys = Some(response.unwrap());
|
||||||
state_lock.is_requesting = false;
|
state_lock.is_requesting = false;
|
||||||
},
|
},
|
||||||
);
|
)
|
||||||
|
.unwrap();
|
||||||
} else if key_list_none && is_requesting {
|
} else if key_list_none && is_requesting {
|
||||||
ui.spinner();
|
ui.spinner();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,11 +89,23 @@ impl InterfaceWindow {
|
|||||||
|
|
||||||
let mut state_lock = state_clone.lock().unwrap();
|
let mut state_lock = state_clone.lock().unwrap();
|
||||||
|
|
||||||
let mut branch = (state_lock.branch).as_mut().unwrap();
|
let branch = (state_lock.branch).as_mut().unwrap();
|
||||||
|
|
||||||
let clear = match branch {
|
let clear = match branch {
|
||||||
TreeMessage::InterfaceAndValue(interface_struct, interface_data) => {
|
TreeMessage::InterfaceAndValue(interface_struct, interface_data) => {
|
||||||
render_interface::render(ui, interface_struct, interface_data);
|
render_interface::render(ui, interface_struct, interface_data);
|
||||||
|
|
||||||
|
if ui.button("Save").clicked() {
|
||||||
|
auth.post(
|
||||||
|
&format!("/api/interface{}", self.path.display()),
|
||||||
|
&TreeMessage::State(interface_data.clone()),
|
||||||
|
move |response: Result<TreeMessage>| {
|
||||||
|
crate::log(&format!("{response:?}"));
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
TreeMessage::Folder(items) => {
|
TreeMessage::Folder(items) => {
|
||||||
|
|||||||
@@ -1,5 +1,11 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
use serde_json::{Value, json};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
ModuleError, Result,
|
||||||
|
config::{InterfaceData, InterfaceStruct, TreeMessage},
|
||||||
|
warn,
|
||||||
|
};
|
||||||
|
|
||||||
pub type ConfigStructKeys = Vec<ConfigStructField>;
|
pub type ConfigStructKeys = Vec<ConfigStructField>;
|
||||||
pub type ConfigStructValues = Vec<Value>;
|
pub type ConfigStructValues = Vec<Value>;
|
||||||
@@ -9,6 +15,47 @@ pub struct Config {
|
|||||||
values: ConfigStructValues,
|
values: ConfigStructValues,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub fn new(keys: ConfigStructKeys) -> Self {
|
||||||
|
let values = keys
|
||||||
|
.iter()
|
||||||
|
.map(|key| match key {
|
||||||
|
ConfigStructField::Header(_) => Value::Null,
|
||||||
|
ConfigStructField::Text(_) => Value::Null,
|
||||||
|
ConfigStructField::String { default, .. } => json!(default),
|
||||||
|
ConfigStructField::Integer { default, .. } => json!(default),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Self { keys, values }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get(&mut self, message: TreeMessage) -> Result<TreeMessage> {
|
||||||
|
match message {
|
||||||
|
TreeMessage::State(InterfaceData::ConfigStruct(values)) => {
|
||||||
|
self.values = values;
|
||||||
|
Ok(TreeMessage::Success)
|
||||||
|
}
|
||||||
|
|
||||||
|
TreeMessage::RequestStruct => Ok(TreeMessage::Interface(
|
||||||
|
InterfaceStruct::ConfigStruct(self.keys.clone()),
|
||||||
|
)),
|
||||||
|
TreeMessage::RequestState => Ok(TreeMessage::State(InterfaceData::ConfigStruct(
|
||||||
|
self.values.clone(),
|
||||||
|
))),
|
||||||
|
TreeMessage::RequestStructAndValue => Ok(TreeMessage::InterfaceAndValue(
|
||||||
|
InterfaceStruct::ConfigStruct(self.keys.clone()),
|
||||||
|
InterfaceData::ConfigStruct(self.values.clone()),
|
||||||
|
)),
|
||||||
|
|
||||||
|
_ => {
|
||||||
|
warn!("Tree got invalid message");
|
||||||
|
Err(ModuleError::Error("Invalid Request".into()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Deserialize, Serialize)]
|
#[derive(Debug, Clone, Deserialize, Serialize)]
|
||||||
pub enum ConfigStructField {
|
pub enum ConfigStructField {
|
||||||
Header(String),
|
Header(String),
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::Value;
|
|
||||||
|
|
||||||
use crate::{ModuleError, Result, config::config_struct};
|
use crate::{ModuleError, Result, config::config_struct};
|
||||||
|
|
||||||
@@ -12,13 +11,13 @@ pub trait Tree {
|
|||||||
unimplemented!();
|
unimplemented!();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_child(&self, child: &str, _message: TreeMessage) -> Result<TreeMessage>;
|
fn select_child(&mut self, child: &str, _message: TreeMessage) -> Result<TreeMessage>;
|
||||||
|
|
||||||
fn get_value(&self, _message: TreeMessage) -> TreeMessage {
|
fn get_value(&self, _message: TreeMessage) -> TreeMessage {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_path(&self, elements: &mut Vec<&str>, message: TreeMessage) -> Result<TreeMessage> {
|
fn get_path(&mut self, elements: &mut Vec<&str>, message: TreeMessage) -> Result<TreeMessage> {
|
||||||
if elements.is_empty() {
|
if elements.is_empty() {
|
||||||
return if Self::is_folder() {
|
return if Self::is_folder() {
|
||||||
Ok(TreeMessage::Folder(self.get_children_string()))
|
Ok(TreeMessage::Folder(self.get_children_string()))
|
||||||
@@ -38,7 +37,7 @@ pub trait Tree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get(&self, path: &str, message: TreeMessage) -> Result<TreeMessage> {
|
fn get(&mut self, path: &str, message: TreeMessage) -> Result<TreeMessage> {
|
||||||
let mut path = if path.is_empty() {
|
let mut path = if path.is_empty() {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
} else {
|
} else {
|
||||||
@@ -49,25 +48,28 @@ pub trait Tree {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub enum TreeMessage {
|
pub enum TreeMessage {
|
||||||
RequestState,
|
RequestState,
|
||||||
RequestStruct,
|
RequestStruct,
|
||||||
RequestStructAndValue,
|
RequestStructAndValue,
|
||||||
|
|
||||||
State(Value),
|
State(InterfaceData),
|
||||||
Interface(InterfaceStruct),
|
Interface(InterfaceStruct),
|
||||||
InterfaceAndValue(InterfaceStruct, InterfaceData),
|
InterfaceAndValue(InterfaceStruct, InterfaceData),
|
||||||
|
|
||||||
|
Success,
|
||||||
|
Failure,
|
||||||
|
|
||||||
Folder(Vec<String>),
|
Folder(Vec<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub enum InterfaceStruct {
|
pub enum InterfaceStruct {
|
||||||
ConfigStruct(config_struct::ConfigStructKeys),
|
ConfigStruct(config_struct::ConfigStructKeys),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub enum InterfaceData {
|
pub enum InterfaceData {
|
||||||
ConfigStruct(config_struct::ConfigStructValues),
|
ConfigStruct(config_struct::ConfigStructValues),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
use std::fmt;
|
||||||
|
|
||||||
|
pub type Result<T> = std::result::Result<T, ModuleError>;
|
||||||
|
|
||||||
///Generic error type for module-related operations.
|
///Generic error type for module-related operations.
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum ModuleError {
|
pub enum ModuleError {
|
||||||
@@ -30,3 +34,23 @@ impl From<Box<dyn std::error::Error>> for ModuleError {
|
|||||||
ModuleError::Error(value.to_string())
|
ModuleError::Error(value.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for ModuleError {
|
||||||
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
"description() is deprecated; use Display"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cause(&self) -> Option<&dyn std::error::Error> {
|
||||||
|
Some(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ModuleError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
f.write_str(format!("{:?}", self).as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+1
-24
@@ -5,34 +5,11 @@ mod error;
|
|||||||
pub mod logger;
|
pub mod logger;
|
||||||
|
|
||||||
mod announcement;
|
mod announcement;
|
||||||
use std::fmt::{self, Debug};
|
|
||||||
|
|
||||||
pub use error::ModuleError;
|
pub use error::{ModuleError, Result};
|
||||||
|
|
||||||
pub use announcement::Announcement;
|
pub use announcement::Announcement;
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, ModuleError>;
|
|
||||||
|
|
||||||
impl std::error::Error for ModuleError {
|
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
"description() is deprecated; use Display"
|
|
||||||
}
|
|
||||||
|
|
||||||
fn cause(&self) -> Option<&dyn std::error::Error> {
|
|
||||||
Some(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ModuleError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
f.write_str(format!("{:?}", self).as_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// pub trait Component {
|
// pub trait Component {
|
||||||
// fn name(&self) -> &'static str;
|
// fn name(&self) -> &'static str;
|
||||||
// // fn start_runtime(&self, manager: Arc<Mutex<Manager>>) -> Option<Box<dyn ModuleRuntime>>;
|
// // fn start_runtime(&self, manager: Arc<Mutex<Manager>>) -> Option<Box<dyn ModuleRuntime>>;
|
||||||
|
|||||||
+11
-10
@@ -22,16 +22,16 @@ macro_rules! route_get {
|
|||||||
}};
|
}};
|
||||||
}
|
}
|
||||||
|
|
||||||
// macro_rules! route_post {
|
macro_rules! route_post {
|
||||||
// ($router:expr, $path:expr, $func:expr) => {{
|
($router:expr, $path:expr, $func:expr) => {{
|
||||||
// {
|
{
|
||||||
// $router.route(
|
$router.route(
|
||||||
// $path,
|
$path,
|
||||||
// post($func).layer(middleware::from_fn(auth::authorize)),
|
post($func).layer(middleware::from_fn(auth::authorize)),
|
||||||
// )
|
)
|
||||||
// }
|
}
|
||||||
// }};
|
}};
|
||||||
// }
|
}
|
||||||
|
|
||||||
pub async fn start_api(address: &str, server: Server) {
|
pub async fn start_api(address: &str, server: Server) {
|
||||||
let listener = TcpListener::bind(address)
|
let listener = TcpListener::bind(address)
|
||||||
@@ -51,6 +51,7 @@ pub async fn start_api(address: &str, server: Server) {
|
|||||||
|
|
||||||
router = route_get!(router, "/api/interface/", Server::get_tree2_root);
|
router = route_get!(router, "/api/interface/", Server::get_tree2_root);
|
||||||
router = route_get!(router, "/api/interface/{*path}", Server::get_tree2);
|
router = route_get!(router, "/api/interface/{*path}", Server::get_tree2);
|
||||||
|
router = route_post!(router, "/api/interface/{*path}", Server::post_tree2);
|
||||||
|
|
||||||
// router = route_get_log(router);
|
// router = route_get_log(router);
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use crate::config::ConfigStructField;
|
use unshell_lib::config::config_struct::ConfigStructField;
|
||||||
|
|
||||||
|
// use crate::config::ConfigStructField;
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
|
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
|
||||||
pub struct Blob {
|
pub struct Blob {
|
||||||
|
|||||||
@@ -33,33 +33,6 @@ struct BuildConfig {
|
|||||||
features: HashMap<String, String>,
|
features: HashMap<String, String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
|
|
||||||
pub enum ConfigStructField {
|
|
||||||
Header(String),
|
|
||||||
Text(String),
|
|
||||||
String {
|
|
||||||
// Default value of string edit in struct
|
|
||||||
#[serde(default)]
|
|
||||||
default: String,
|
|
||||||
max_length: Option<usize>,
|
|
||||||
// Display string edit as password
|
|
||||||
#[serde(default)]
|
|
||||||
protected: Option<bool>,
|
|
||||||
},
|
|
||||||
Integer {
|
|
||||||
// Default value of integer in struct
|
|
||||||
#[serde(default)]
|
|
||||||
default: i32,
|
|
||||||
min: Option<i32>,
|
|
||||||
max: Option<i32>,
|
|
||||||
},
|
|
||||||
// Checkbox
|
|
||||||
// Dropdown
|
|
||||||
// Collapsing header
|
|
||||||
// Slider
|
|
||||||
// ...
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct ComponentState {
|
pub struct ComponentState {
|
||||||
metadata: ComponentMetadata,
|
metadata: ComponentMetadata,
|
||||||
|
|||||||
@@ -1,15 +1,15 @@
|
|||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
|
||||||
path::PathBuf,
|
path::PathBuf,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde_json::Value;
|
|
||||||
use unshell_lib::{
|
use unshell_lib::{
|
||||||
ModuleError,
|
ModuleError, Result,
|
||||||
config::{InterfaceData, Tree, TreeMessage, config_struct::ConfigStructField},
|
config::{
|
||||||
|
Tree, TreeMessage,
|
||||||
|
config_struct::{Config, ConfigStructField},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use unshell_lib::{Result, config::InterfaceStruct};
|
|
||||||
use unshell_manager::Manager;
|
use unshell_manager::Manager;
|
||||||
|
|
||||||
mod blobs;
|
mod blobs;
|
||||||
@@ -18,25 +18,41 @@ mod tree2;
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
pub component_configs: Vec<crate::config::ComponentState>,
|
// pub component_configs: Vec<crate::config::ComponentState>,
|
||||||
// pub interface: InterfaceWrapper,
|
// pub interface: InterfaceWrapper,
|
||||||
pub manager: Arc<Mutex<Manager>>,
|
pub manager: Arc<Mutex<Manager>>,
|
||||||
pub db: sled::Db,
|
pub db: sled::Db,
|
||||||
// pub tree: Tree2,
|
// pub tree: Tree2,
|
||||||
|
test_thing: Arc<Mutex<Config>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Server {
|
impl Server {
|
||||||
pub fn new(config_paths: Vec<PathBuf>, database: String) -> Result<Self> {
|
pub fn new(_config_paths: Vec<PathBuf>, database: String) -> Result<Self> {
|
||||||
let mut component_configs: Vec<crate::config::ComponentState> = Vec::new();
|
// let mut component_configs: Vec<crate::config::ComponentState> = Vec::new();
|
||||||
|
|
||||||
for config in &config_paths {
|
// for config in &config_paths {
|
||||||
component_configs.extend(crate::config::load_config(config)?);
|
// component_configs.extend(crate::config::load_config(config)?);
|
||||||
}
|
// }
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
component_configs,
|
// component_configs,
|
||||||
manager: Manager::start(&crate::SERVER_CONFIG, Vec::new()),
|
manager: Manager::start(&crate::SERVER_CONFIG, Vec::new()),
|
||||||
db: sled::open(database).map_err(|e| ModuleError::DatabaseError(e.to_string()))?,
|
db: sled::open(database).map_err(|e| ModuleError::DatabaseError(e.to_string()))?,
|
||||||
|
|
||||||
|
test_thing: Arc::new(Mutex::new(Config::new(vec![
|
||||||
|
ConfigStructField::Header("Test Heading".into()),
|
||||||
|
ConfigStructField::Text("Test Texttttttttttttttt".into()),
|
||||||
|
ConfigStructField::String {
|
||||||
|
default: "Test Texttttttttttttttt".into(),
|
||||||
|
max_length: None,
|
||||||
|
protected: None,
|
||||||
|
},
|
||||||
|
ConfigStructField::String {
|
||||||
|
default: "Test ".into(),
|
||||||
|
max_length: None,
|
||||||
|
protected: None,
|
||||||
|
},
|
||||||
|
]))),
|
||||||
// tree: Tree2::default(),
|
// tree: Tree2::default(),
|
||||||
// interface: get_test_interface(),
|
// interface: get_test_interface(),
|
||||||
})
|
})
|
||||||
@@ -52,18 +68,9 @@ impl Tree for Server {
|
|||||||
vec!["connection_count".into()]
|
vec!["connection_count".into()]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn select_child(&self, child: &str, _message: TreeMessage) -> Result<TreeMessage> {
|
fn select_child(&mut self, child: &str, message: TreeMessage) -> Result<TreeMessage> {
|
||||||
match child {
|
match child {
|
||||||
"connection_count" => {
|
"connection_count" => self.test_thing.lock().unwrap().get(message),
|
||||||
let interface = vec![ConfigStructField::Header(format!("Test Heading!"))];
|
|
||||||
|
|
||||||
let value = vec![Value::Null];
|
|
||||||
|
|
||||||
Ok(TreeMessage::InterfaceAndValue(
|
|
||||||
InterfaceStruct::ConfigStruct(interface),
|
|
||||||
InterfaceData::ConfigStruct(value),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
_ => Err("No such child".into()),
|
_ => Err("No such child".into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ impl Server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_tree2(
|
pub async fn get_tree2(
|
||||||
State(server): State<Server>,
|
State(mut server): State<Server>,
|
||||||
Path(path): Path<String>,
|
Path(path): Path<String>,
|
||||||
Extension(_): Extension<CurrentUser>,
|
Extension(_): Extension<CurrentUser>,
|
||||||
) -> Json<Value> {
|
) -> Json<Value> {
|
||||||
@@ -33,4 +33,19 @@ impl Server {
|
|||||||
|
|
||||||
Json(serde_json::to_value(result).unwrap())
|
Json(serde_json::to_value(result).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn post_tree2(
|
||||||
|
State(mut server): State<Server>,
|
||||||
|
Path(path): Path<String>,
|
||||||
|
Extension(_): Extension<CurrentUser>,
|
||||||
|
Json(tree_message): Json<TreeMessage>,
|
||||||
|
) -> Json<Value> {
|
||||||
|
debug!("POST /api/interface/{}", path);
|
||||||
|
|
||||||
|
let result = server
|
||||||
|
.get(&path, tree_message)
|
||||||
|
.map_err(|e| ModuleError::CryptError(e.to_string()));
|
||||||
|
|
||||||
|
Json(serde_json::to_value(result).unwrap())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user