NOSHP_Client/
client_config.rs1use std::{fs, path::Path};
2
3use serde::{Deserialize, Serialize};
4use toml::Table;
5
6use crate::client_types::types::{DeviceCapabilityStatus, DeviceCapabilityType};
7
8#[derive(Serialize, Deserialize)]
9pub struct ClientConfig {
10 pub server_ip: Option<String>,
11 pub device_name: String,
12 pub capability: Table,
13}
14
15#[derive(Clone)]
16pub struct ParsedConfig {
17 pub server_ip: Option<String>,
18 pub device_name: String,
19 pub capabilities: Vec<DeviceCapabilityStatus>,
20}
21
22impl ClientConfig {
23 pub fn load_config(path: &str) -> anyhow::Result<ParsedConfig> {
24 let config_path = Path::new(path);
25
26 if config_path.exists() {
27 let content = fs::read_to_string(config_path)?;
28 let config: ClientConfig = toml::from_str(&content)?;
29
30 let capabilities = config.capability.into_iter().map(|(name, value)|{
31 let value = match value {
32 toml::Value::Table(v) => v,
33 _ => {
34 println!("capability {name} in config file has invalid fields, expected a table as contents");
35 Table::new()
36 }
37 };
38
39 let available = match value.get("available") {
40 Some(v) => v.clone(),
41 None => toml::Value::Boolean(false)
42 };
43
44 let available = match available {
45 toml::Value::Boolean(v) => v,
46 _ => {
47 eprintln!("Capability {name} in config file has invalid fields, expected a boolean for available field");
48 false
49 }
50 };
51
52 let capa_type = match value.get("type") {
53 Some(v) => v.clone(),
54 None => {
55 eprintln!("Capability {name} in config file is missing a type, defaulting to button");
56 toml::Value::Boolean(false)
57 }
58 };
59
60 let capa_type = match capa_type {
61 toml::Value::String(v) => v,
62 _ => String::from("button")
63 };
64
65 let capa_type = match &*capa_type {
66 "button" => DeviceCapabilityType::Button,
67 "slider" => DeviceCapabilityType::Slider,
68 _ => {
69 eprintln!("Unrecognized capability type for capability {name}, defaulting to button");
70 DeviceCapabilityType::Button
71 }
72 };
73
74 DeviceCapabilityStatus {
75 capability: name,
76 available,
77 r#type: capa_type as i32,
78 value: None
79 }
80 }).collect();
81
82 return Ok(ParsedConfig {
83 server_ip: config.server_ip,
84 device_name: config.device_name,
85 capabilities,
86 });
87 }
88
89 println!("No config found, generating a default config");
90 let config = ClientConfig::default();
91 let toml = toml::to_string(&config)?;
92
93 fs::write(config_path, toml)?;
94 return Ok(ParsedConfig {
95 server_ip: None,
96 device_name: config.device_name,
97 capabilities: Vec::new(),
98 });
99 }
100}
101
102impl Default for ClientConfig {
103 fn default() -> Self {
104 Self {
105 server_ip: Some(String::from(
106 "Your server IP here, or nothing if you want to set it programmatically",
107 )),
108 device_name: String::from("Unnamed Device"),
109 capability: Table::new(),
110 }
111 }
112}
113
114impl Default for ParsedConfig {
115 fn default() -> Self {
116 Self {
117 server_ip: None,
118 device_name: String::from("Unnamed Device"),
119 capabilities: Vec::new(),
120 }
121 }
122}