From 125c2d48d8ff9a702d379cc6fb5781ffe7ffcc6a Mon Sep 17 00:00:00 2001 From: Samuel Lorch Date: Wed, 25 Oct 2023 18:06:07 +0200 Subject: [PATCH] Make Config Manager Thread Safe and Cloneable --- src/config_manager.rs | 50 +++++++++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 18 deletions(-) diff --git a/src/config_manager.rs b/src/config_manager.rs index 6e1cbc9..590576e 100644 --- a/src/config_manager.rs +++ b/src/config_manager.rs @@ -3,69 +3,83 @@ use validator::Validate; use super::definitions::config::Config; use std::error::Error; use std::fs; +use std::sync::{Arc, Mutex, MutexGuard}; const CURRENT_CONFIG_PATH: &str = "config.json"; const PENDING_CONFIG_PATH: &str = "pending.json"; +#[derive(Clone)] pub struct ConfigManager { + shared_data: Arc>, +} + +struct SharedData { current_config: Config, pending_config: Config, } +// Note, using unwarp on a mutex lock is ok since that only errors with mutex poisoning + impl ConfigManager { + pub fn new() -> Result> { + Ok(Self { + shared_data: Arc::new(Mutex::new(SharedData { + current_config: read_file_to_config(CURRENT_CONFIG_PATH)?, + pending_config: read_file_to_config(PENDING_CONFIG_PATH)?, + })), + }) + } + pub fn get_current_config(&self) -> Config { - self.current_config.clone() + self.shared_data.lock().unwrap().current_config.clone() } pub fn get_pending_config(&self) -> Config { - self.pending_config.clone() + self.shared_data.lock().unwrap().pending_config.clone() } pub fn apply_pending_changes(&mut self) -> Result<(), Box> { + let mut data = self.shared_data.lock().unwrap(); // TODO run Apply functions, revert on failure - write_config_to_file(CURRENT_CONFIG_PATH, self.pending_config.clone())?; + write_config_to_file(CURRENT_CONFIG_PATH, data.pending_config.clone())?; // Also revert if config save fails - self.current_config = self.pending_config.clone(); + data.current_config = data.pending_config.clone(); Ok(()) } pub fn discard_pending_changes(&mut self) -> Result<(), Box> { - self.pending_config = self.current_config.clone(); + let mut data = self.shared_data.lock().unwrap(); + + data.pending_config = data.current_config.clone(); Ok(()) } pub fn start_transaction(&mut self) -> Result> { + let data = self.shared_data.lock().unwrap(); + Ok(ConfigTransaction { finished: false, - //guard: guard, - changes: self.pending_config.clone(), - config_manager: self, + changes: data.pending_config.clone(), + shared_data: data, }) } } pub struct ConfigTransaction<'a> { finished: bool, - config_manager: &'a mut ConfigManager, + shared_data: MutexGuard<'a, SharedData>, pub changes: Config, } impl<'a> ConfigTransaction<'a> { - pub fn commit(&mut self) -> Result<(), Box> { + pub fn commit(mut self) -> Result<(), Box> { let ch = self.changes.clone(); ch.validate()?; - self.config_manager.pending_config = ch.clone(); + self.shared_data.pending_config = ch.clone(); Ok(()) } } -pub fn new_config_manager() -> Result> { - Ok(ConfigManager { - current_config: read_file_to_config(CURRENT_CONFIG_PATH)?, - pending_config: read_file_to_config(PENDING_CONFIG_PATH)?, - }) -} - fn read_file_to_config(path: &str) -> Result> { let data = fs::read_to_string(path)?; let conf: Config = serde_json::from_str(&data)?;