From 6ca105b7114488245f4ed4bde9396e618b5b4f8a Mon Sep 17 00:00:00 2001 From: Evgenii Vilkov Date: Fri, 4 Oct 2024 23:52:18 +0200 Subject: [PATCH] rebase config --- src/config.rs | 38 ++++++++++++++++++++++++++------- src/keyboard.rs | 4 ++-- src/main.rs | 6 +++--- src/providers/layout/linux.rs | 6 ++---- src/providers/layout/macos.rs | 6 ++---- src/providers/layout/windows.rs | 6 ++---- 6 files changed, 41 insertions(+), 25 deletions(-) diff --git a/src/config.rs b/src/config.rs index 2da1404..affeb6b 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,24 +1,38 @@ -use std::path::PathBuf; +use std::{path::PathBuf, sync::OnceLock}; #[derive(serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct Config { pub devices: Vec, pub layouts: Vec, + #[serde(skip_serializing_if = "Option::is_none")] pub reconnect_delay: Option, } #[derive(serde::Deserialize, serde::Serialize)] #[serde(rename_all = "camelCase")] pub struct Device { + #[serde(skip_serializing_if = "Option::is_none")] pub name: Option, - #[serde(deserialize_with = "string_to_hex")] + #[serde(serialize_with = "hex_to_string", deserialize_with = "string_to_hex")] pub product_id: u16, + #[serde(skip_serializing_if = "Option::is_none")] pub usage: Option, + #[serde(skip_serializing_if = "Option::is_none")] pub usage_page: Option, } -pub fn get_config(maybe_path: Option) -> Config { +static CONFIG: OnceLock = OnceLock::new(); + +pub fn get_config() -> &'static Config { + CONFIG.get().unwrap() +} + +pub fn load_config(path: PathBuf) -> &'static Config { + if let Some(config) = CONFIG.get() { + return config; + } + let default_config = Config { devices: vec![Device { name: None, @@ -30,19 +44,20 @@ pub fn get_config(maybe_path: Option) -> Config { reconnect_delay: None, }; - let path = maybe_path.unwrap_or("./qmk-hid-host.json".into()); - if let Ok(file) = std::fs::read_to_string(&path) { - return serde_json::from_str::(&file) + let config = serde_json::from_str::(&file) .map_err(|e| tracing::error!("Incorrect config file: {}", e)) .unwrap(); + return CONFIG.get_or_init(|| config); } let file_content = serde_json::to_string_pretty(&default_config).unwrap(); - std::fs::write(&path, &file_content).unwrap(); + std::fs::write(&path, &file_content) + .map_err(|e| tracing::error!("Error while saving config file to {:?}: {}", path, e)) + .unwrap(); tracing::info!("New config file created at {:?}", path); - return default_config; + CONFIG.get_or_init(|| default_config) } fn string_to_hex<'de, D>(deserializer: D) -> Result @@ -53,3 +68,10 @@ where let hex = value.trim_start_matches("0x"); return u16::from_str_radix(hex, 16).map_err(serde::de::Error::custom); } + +fn hex_to_string(value: &u16, serializer: S) -> Result +where + S: serde::Serializer, +{ + serializer.serialize_str(&format!("0x{:04x}", value)) +} diff --git a/src/keyboard.rs b/src/keyboard.rs index 4886b2a..7c6611d 100644 --- a/src/keyboard.rs +++ b/src/keyboard.rs @@ -12,9 +12,9 @@ pub struct Keyboard { } impl Keyboard { - pub fn new(device: Device, reconnect_delay: u64) -> Self { + pub fn new(device: &Device, reconnect_delay: u64) -> Self { return Self { - name: device.name.unwrap_or("keyboard".to_string()), + name: device.name.clone().unwrap_or("keyboard".to_string()), product_id: device.product_id, usage: device.usage.unwrap_or(0x61), usage_page: device.usage_page.unwrap_or(0xff60), diff --git a/src/main.rs b/src/main.rs index 83c377f..522c7a2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,7 +8,7 @@ mod data_type; mod keyboard; mod providers; -use config::get_config; +use config::load_config; use keyboard::Keyboard; use providers::{_base::Provider, layout::LayoutProvider, time::TimeProvider, volume::VolumeProvider}; use std::thread; @@ -37,12 +37,12 @@ fn main() { let _ = tracing::subscriber::set_global_default(tracing_subscriber); let args = Args::parse(); - let config = get_config(args.config); + let config = load_config(args.config.unwrap_or("./qmk-hid-host.json".into())); let (data_sender, _) = broadcast::channel::>(1); let (is_connected_sender, is_connected_receiver) = mpsc::channel::(1); - for device in config.devices { + for device in &config.devices { let data_sender = data_sender.clone(); let is_connected_sender = is_connected_sender.clone(); let reconnect_delay = config.reconnect_delay.unwrap_or(5000); diff --git a/src/providers/layout/linux.rs b/src/providers/layout/linux.rs index dd4b003..b9251a7 100644 --- a/src/providers/layout/linux.rs +++ b/src/providers/layout/linux.rs @@ -38,7 +38,6 @@ fn send_data(value: &String, layouts: &Vec, data_sender: &broadcast::Sen pub struct LayoutProvider { data_sender: broadcast::Sender>, - layouts: Vec, is_started: Arc, } @@ -46,7 +45,6 @@ impl LayoutProvider { pub fn new(data_sender: broadcast::Sender>) -> Box { let provider = LayoutProvider { data_sender, - layouts: get_config().layouts, is_started: Arc::new(AtomicBool::new(false)), }; return Box::new(provider); @@ -57,8 +55,8 @@ impl Provider for LayoutProvider { fn start(&self) { tracing::info!("Layout Provider started"); self.is_started.store(true, Relaxed); + let layouts = &get_config().layouts; let data_sender = self.data_sender.clone(); - let layouts = self.layouts.clone(); let is_started = self.is_started.clone(); std::thread::spawn(move || { let mut synced_layout = 0; @@ -77,7 +75,7 @@ impl Provider for LayoutProvider { synced_layout = layout; let layout_symbol = symbol_list.get(layout + 1).map(|x| x.to_string()).unwrap_or_default(); let layout_name = layout_symbol.split([':', '(']).next().unwrap_or_default().to_string(); - send_data(&layout_name, &layouts, &data_sender); + send_data(&layout_name, layouts, &data_sender); } std::thread::sleep(std::time::Duration::from_millis(100)); diff --git a/src/providers/layout/macos.rs b/src/providers/layout/macos.rs index 7e294a4..8656a7d 100644 --- a/src/providers/layout/macos.rs +++ b/src/providers/layout/macos.rs @@ -53,7 +53,6 @@ fn send_data(value: &String, layouts: &Vec, data_sender: &broadcast::Sen pub struct LayoutProvider { data_sender: broadcast::Sender>, - layouts: Vec, is_started: Arc, } @@ -61,7 +60,6 @@ impl LayoutProvider { pub fn new(data_sender: broadcast::Sender>) -> Box { let provider = LayoutProvider { data_sender, - layouts: get_config().layouts, is_started: Arc::new(AtomicBool::new(false)), }; Box::new(provider) @@ -72,8 +70,8 @@ impl Provider for LayoutProvider { fn start(&self) { tracing::info!("Layout Provider started"); self.is_started.store(true, Relaxed); + let layouts = &get_config().layouts; let data_sender = self.data_sender.clone(); - let layouts = self.layouts.clone(); let is_started = self.is_started.clone(); let mut synced_layout = "".to_string(); @@ -86,7 +84,7 @@ impl Provider for LayoutProvider { let lang = layout.split('.').last().unwrap().to_string(); if synced_layout != lang { synced_layout = lang; - send_data(&synced_layout, &layouts, &data_sender); + send_data(&synced_layout, layouts, &data_sender); } } std::thread::sleep(std::time::Duration::from_millis(100)); diff --git a/src/providers/layout/windows.rs b/src/providers/layout/windows.rs index ee80878..9156620 100644 --- a/src/providers/layout/windows.rs +++ b/src/providers/layout/windows.rs @@ -38,7 +38,6 @@ fn send_data(value: &String, layouts: &Vec, data_sender: &broadcast::Sen pub struct LayoutProvider { data_sender: broadcast::Sender>, - layouts: Vec, is_started: Arc, } @@ -46,7 +45,6 @@ impl LayoutProvider { pub fn new(data_sender: broadcast::Sender>) -> Box { let provider = LayoutProvider { data_sender, - layouts: get_config().layouts, is_started: Arc::new(AtomicBool::new(false)), }; return Box::new(provider); @@ -57,8 +55,8 @@ impl Provider for LayoutProvider { fn start(&self) { tracing::info!("Layout Provider started"); self.is_started.store(true, Relaxed); + let layouts = &get_config().layouts; let data_sender = self.data_sender.clone(); - let layouts = self.layouts.clone(); let is_started = self.is_started.clone(); std::thread::spawn(move || { let mut synced_layout = "".to_string(); @@ -70,7 +68,7 @@ impl Provider for LayoutProvider { if let Some(layout) = unsafe { get_layout() } { if synced_layout != layout { synced_layout = layout; - send_data(&synced_layout, &layouts, &data_sender); + send_data(&synced_layout, layouts, &data_sender); } }