created singleton config manager using once pattern.
This commit is contained in:
parent
31d67889ff
commit
4bfaf1a813
|
|
@ -10,6 +10,7 @@ use toml::Value;
|
|||
|
||||
use crate::{
|
||||
config_manager::{
|
||||
get_args,
|
||||
messages::{
|
||||
ConfigManagerDataMessage, ConfigManagerDataResponse,
|
||||
ConfigManagerOutput,
|
||||
|
|
@ -23,10 +24,10 @@ static mut SHARED: Option<Addr<ConfigManager>> = None;
|
|||
static INIT: Once = Once::new();
|
||||
|
||||
pub(crate) struct ConfigManager {
|
||||
_file: Option<File>,
|
||||
_stored: ConfigValue,
|
||||
file: File,
|
||||
stored: ConfigValue,
|
||||
root: ConfigValue,
|
||||
_subscribers: Vec<Recipient<ObservableMessage<ConfigManagerOutput>>>,
|
||||
subscribers: Vec<Recipient<ObservableMessage<ConfigManagerOutput>>>,
|
||||
}
|
||||
|
||||
impl ConfigManager {
|
||||
|
|
@ -34,112 +35,83 @@ impl ConfigManager {
|
|||
INIT.call_once(|| {
|
||||
// Since this access is inside a call_once, before any other accesses, it is safe
|
||||
unsafe {
|
||||
// todo: add proper error handling
|
||||
let file = OpenOptions::new()
|
||||
.write(true)
|
||||
.read(true)
|
||||
.open(file.unwrap_or("./config_file.toml".into()))
|
||||
.ok();
|
||||
let mut file = Self::get_file();
|
||||
let shared = Self::new(file);
|
||||
|
||||
let mut output = String::new();
|
||||
file.as_ref().map(|mut v| {
|
||||
v.read_to_string(&mut output)
|
||||
.expect("failed to read from file")
|
||||
});
|
||||
|
||||
let stored = output
|
||||
.parse::<Value>()
|
||||
.map(|v| v.into())
|
||||
.ok()
|
||||
.unwrap_or_else(|| ConfigValue::Dict(BTreeMap::new()));
|
||||
|
||||
let root = stored.clone();
|
||||
|
||||
let shared = Self {
|
||||
_file: file,
|
||||
root,
|
||||
_stored: stored,
|
||||
_subscribers: Vec::default(),
|
||||
}
|
||||
.start();
|
||||
SHARED = Some(shared);
|
||||
}
|
||||
});
|
||||
unsafe { SHARED.clone().unwrap() }
|
||||
}
|
||||
|
||||
fn new(mut file: File) -> Addr<Self> {
|
||||
let mut output = String::new();
|
||||
file.read_to_string(&mut output)
|
||||
.expect("failed to read from file");
|
||||
|
||||
let stored = output
|
||||
.parse::<Value>()
|
||||
.map(|v| v.into())
|
||||
.ok()
|
||||
.unwrap_or_else(|| ConfigValue::Dict(BTreeMap::new()));
|
||||
|
||||
let root = stored.clone();
|
||||
|
||||
Self {
|
||||
file,
|
||||
root,
|
||||
stored,
|
||||
subscribers: Vec::default(),
|
||||
}
|
||||
.start()
|
||||
}
|
||||
|
||||
fn get_file() -> File {
|
||||
let default = "./config_file.toml".to_owned();
|
||||
|
||||
let args = get_args();
|
||||
let file_path =
|
||||
args.get_one::<String>("config file").unwrap_or(&default);
|
||||
|
||||
OpenOptions::new()
|
||||
.write(true)
|
||||
.read(true)
|
||||
.open(file_path)
|
||||
.ok()
|
||||
.unwrap()
|
||||
}
|
||||
}
|
||||
|
||||
impl ConfigManager {
|
||||
pub fn get_value(
|
||||
&self,
|
||||
val_path: String,
|
||||
) -> Result<ConfigValue, &'static str> {
|
||||
use ConfigValue::{Array, Dict};
|
||||
pub fn get_value(&self, key: String) -> Result<ConfigValue, &'static str> {
|
||||
use ConfigValue::Dict;
|
||||
|
||||
let path: Vec<String> = val_path.split('.').map(|v| v.into()).collect();
|
||||
let mut current_node: &ConfigValue = &self.root;
|
||||
|
||||
for i in path {
|
||||
match current_node {
|
||||
Dict(v) => match v.get(&i) {
|
||||
Some(v) => current_node = v,
|
||||
None => return Err("path does not exist"),
|
||||
},
|
||||
Array(v) => {
|
||||
if let Ok(index) = i.parse::<usize>() {
|
||||
current_node = &v[index];
|
||||
}
|
||||
}
|
||||
_ => return Err("invalid path"),
|
||||
}
|
||||
if let Dict(dict) = &self.root {
|
||||
let opt_value = dict.get(&key);
|
||||
return if let Some(value) = opt_value {
|
||||
Ok(value.clone())
|
||||
} else {
|
||||
Err("[ConfigManager] get_value: Value does not exist")
|
||||
};
|
||||
}
|
||||
Ok(current_node.clone())
|
||||
Err("[ConfigManager] get_value: Key does not exist")
|
||||
}
|
||||
|
||||
// this doesn't work for now
|
||||
pub fn set_value(&self, val_path: String) -> Result<(), &'static str> {
|
||||
use ConfigValue::{Array, Dict};
|
||||
pub fn set_value(
|
||||
&mut self,
|
||||
key: String,
|
||||
value: ConfigValue,
|
||||
) -> Result<ConfigManagerDataResponse, &'static str> {
|
||||
use ConfigManagerDataResponse::SetValue;
|
||||
use ConfigValue::Dict;
|
||||
|
||||
let path: Vec<String> = val_path.split('.').map(|v| v.into()).collect();
|
||||
let mut current_node: &ConfigValue = &self.root;
|
||||
let mut next_node: Option<&ConfigValue> = None;
|
||||
|
||||
// check that the current
|
||||
for i in path {
|
||||
match current_node {
|
||||
Dict(v) => {
|
||||
if v.contains_key(&i) {
|
||||
next_node = v.get(&i);
|
||||
} else {
|
||||
return Err("invalid path");
|
||||
}
|
||||
}
|
||||
Array(v) => {
|
||||
if let Ok(index) = i.parse::<usize>() {
|
||||
if v.len() > index {
|
||||
next_node = v.get(index)
|
||||
} else {
|
||||
return Err("invalid path");
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => return Err("invalid path"),
|
||||
}
|
||||
|
||||
match next_node {
|
||||
Some(a @ Dict(_) | a @ Array(_)) => {
|
||||
current_node = a;
|
||||
continue;
|
||||
}
|
||||
_ => return Err("invalid path"),
|
||||
}
|
||||
if let Dict(dict) = &mut self.root {
|
||||
dict.insert(key, value);
|
||||
Ok(SetValue)
|
||||
} else {
|
||||
Err("[ConfigManager] set_value: What the hell did ou do wrong")
|
||||
}
|
||||
|
||||
if let Dict(v) = current_node {
|
||||
} else if let Dict(v) = current_node {
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -175,7 +147,9 @@ impl Handler<ConfigManagerDataMessage> for ConfigManager {
|
|||
ConfigManagerDataMessage::GetValue(val) => {
|
||||
Ok(GotValue(self.get_value(val)?))
|
||||
}
|
||||
ConfigManagerDataMessage::SetValue(_, _) => Ok(SetValue),
|
||||
ConfigManagerDataMessage::SetValue(key, value) => {
|
||||
self.set_value(key, value)
|
||||
}
|
||||
ConfigManagerDataMessage::SoftSetValue(_, _) => Ok(SetValue),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,15 @@
|
|||
mod config_manager;
|
||||
mod types;
|
||||
mod messages;
|
||||
//! # config_manager
|
||||
//! This module contains all the code that deals with server configuration.
|
||||
//! It tries to implement a singleton actor, that will be fetchable globaly.
|
||||
|
||||
pub(crate) use messages::{ConfigManagerDataResponse, ConfigManagerDataMessage, ConfigManagerOutput};
|
||||
mod arg_fetcher;
|
||||
mod config_manager;
|
||||
mod messages;
|
||||
mod types;
|
||||
|
||||
pub(crate) use arg_fetcher::get_args;
|
||||
pub(crate) use config_manager::ConfigManager;
|
||||
pub(crate) use types::ConfigValue;
|
||||
pub(crate) use messages::{
|
||||
ConfigManagerDataMessage, ConfigManagerDataResponse, ConfigManagerOutput,
|
||||
};
|
||||
pub(crate) use types::ConfigValue;
|
||||
|
|
|
|||
Loading…
Reference in New Issue