use crate::{IResult, JsonV, JsonVExentd};
use std::fs::File;
use std::io::Read;
use serde_json::json;
use std::ops::{Deref, DerefMut};
use std::path::Path;
use std::sync::RwLock;
pub type JsonMap = serde_json::Map<String, JsonV>;
pub static _CONFIG: once_cell::sync::Lazy<RwLock<JsonMap>> = once_cell::sync::Lazy::new(|| RwLock::new(JsonMap::new()));
#[allow(dead_code)]
pub(crate) fn get_config_all() -> JsonV {
_CONFIG.read().map(|v| serde_json::json!(v.deref().clone())).unwrap_or_else(|e| {
eprintln!("CONFIG.read: {:?}", e);
JsonV::Null
})
}
#[allow(dead_code)]
pub(crate) fn get_config_keys(keys: &str) -> JsonV {
get_config(keys.split(".").collect::<Vec<&str>>())
}
pub fn get_config(keys: Vec<&str>) -> JsonV {
_CONFIG
.read()
.map(|v| {
let v = v.deref();
let mut r = JsonV::Null;
for i in 0..keys.len() {
let k = keys[i];
if i == 0 {
r = serde_json::json!(v)[k].clone();
} else {
r = serde_json::json!(r)[k].to_owned();
}
}
r
})
.unwrap_or_else(|e| {
eprintln!("CONFIG.read: {:?}", e);
JsonV::Null
})
}
pub fn run_watch(toml_file_path_str: &str, map: &mut Option<JsonMap>) -> IResult<crossbeam::channel::Receiver<String>> {
load_file(toml_file_path_str)?;
let (send, rev) = crossbeam::channel::bounded(10);
let toml_file_path = toml_file_path_str.to_string();
{
let file_name = get_file_name(toml_file_path_str)?;
let write_data = |map: &mut JsonMap| {
let k = "_watch_mode".to_owned();
if let Some(JsonV::String(v)) = map.get_mut(&k) {
v.push_str(&format!("{},", file_name));
} else {
map.insert(k, json!(file_name));
}
};
if let Some(v) = map{
write_data(v);
}else if let Ok(lock) = _CONFIG.write().as_deref_mut() {
write_data(lock);
}
}
Ok(rev)
}
#[test]
fn test_read_file() {
let mut b = vec![];
File::open(file!()).unwrap().read_to_end(&mut b).unwrap();
let s = String::from_utf8(b).unwrap();
println!("{}", s);
}
fn read_file(toml_file_path: &str) -> IResult<String> {
let mut file_temp = match File::open(&toml_file_path) {
Ok(v) => v,
Err(e) => {
let msg = format!("打开[{}]文件失败: {:?}", &toml_file_path, e);
Err(msg)?
}
};
let mut b = vec![];
let _size = match file_temp.read_to_end(&mut b) {
Err(e) => {
let msg = format!("read_to_string[{}]文件失败: {:?}", &toml_file_path, e);
Err(msg)?
}
Ok(_v) => _v,
};
let toml_str = match String::from_utf8(b) {
Err(e) => {
let msg = format!("解析toml文件失败: {:?}", e);
Err(msg)?
}
Ok(v) => v,
};
Ok(toml_str)
}
pub fn get_file_name(path: &str) -> IResult<String> {
let r = Path::new(path)
.file_name()
.and_then(|v| v.to_str().map(|v| v.to_string()))
.ok_or_else(|| format!("[{}]路径中不存在配置文件名", path))?
.trim_end_matches(".toml")
.trim_end_matches("config")
.trim_end_matches('_')
.trim_start_matches("config")
.trim_start_matches("_")
.to_string();
Ok(r)
}
pub fn load_file(path: &str) -> IResult<()> {
let file_name = get_file_name(path)?;
let str_v = read_file(path)?;
load_str(file_name, str_v)
}
pub fn load_str(file_name: String, toml_str: String) -> IResult<()> {
let value: toml::Value = toml::from_str(&toml_str).map_err(|e| format!("解析toml字符串失败: {:?}", e))?;
let data = serde_json::json!(value).as_object2().ok_or_else(|| "配置文件格式不是一个键值对对象")?;
if let Ok(mut lock) = _CONFIG.write() {
if lock.deref().get("mode").is_none() {
let mode = data
.get("mode")
.map(|v| v.clone().as_string2())
.ok_or_else(|| "读取的第一个配置文件中没有定义mode属性")?
.ok_or_else(|| "读取的第一个配置文件中定义的mode属性不是一个字符串")?;
lock.deref_mut().insert("mode".to_owned(), JsonV::String(mode));
}
if lock.deref().get("_default_name").is_none() {
lock.deref_mut().insert("_default_name".to_owned(), JsonV::String(file_name.clone()));
}
lock.deref_mut().insert(file_name, JsonV::Object(data));
debug!("config: {}", serde_json::json!(lock.deref()).to_string());
}
Ok(())
}
#[macro_export]
macro_rules! load_tomls {
($($file:expr), + $(,)?) => {{
$(
let file_name = $crate::toml_read::get_file_name($file).unwrap();
let s = include_str!(concat!(env!("CARGO_MANIFEST_DIR"), "/", $file));
$crate::toml_read::load_str(file_name, s.to_string()).map_err(|e| e.to_string()).unwrap();
)*
}};
($mode:expr; $($file:expr), + $(,)?) => {{
$crate::toml_read::_CONFIG
.write()
.unwrap()
.insert("mode".to_owned(), JsonV::String($mode.to_string()));
load_tomls! ($($file),*)
}};
}