use std::{ fs, path::Path, }; use rust_util::{ XResult, new_box_ioerror, util_msg::*, }; use chrono::{ Utc, }; pub const ETC_OSS_BACKUPD_CONFIG: &str = "/etc/oss-backupd/config.json"; pub const OSS_BACKUPD_CONFIG: &str = "oss-backupd-config.json"; pub const DOT_OSS_BACKUPD_CONFIG: &str = ".oss-backupd-config.json"; /* { "oss_config": { "endpoint": "", "access_key_id": "", "access_key_secret": "", "bucket": "", "path": "" }, "host": "", "encrypt_pubkey_file": "", "items": [ { "oss_config": null, "target": "", "file_name": "", "encrypt_pubkey_file": null } ] } */ #[derive(Debug, Clone)] pub struct OSSConfig { pub endpoint: Option, pub access_key_id: Option, pub access_key_secret: Option, pub bucket: Option, pub path: Option, } #[derive(Debug)] pub struct OSSBackupdConfigItem { pub target: Option, pub file_name: Option, pub oss_config: Option, pub encrypt_pubkey_file: Option, } #[derive(Debug)] pub struct OSSBackupdConfig { pub oss_config: Option, pub prefix: Option, pub host: Option, pub items: Vec, } pub fn make_oss_key(oss_backupd_config: &OSSBackupdConfig, oss_backupd_config_item: &OSSBackupdConfigItem, suffix: &str) -> String { let mut key = String::with_capacity(1024); key.push_str(&(if oss_backupd_config.prefix.is_some() { remove_start_end_slash(&oss_backupd_config.prefix.as_ref().unwrap().as_str()) } else { "default_oss_backupd".to_string() })); key.push_str("/"); key.push_str(&(if oss_backupd_config.host.is_some() { remove_start_end_slash(&oss_backupd_config.host.as_ref().unwrap().as_str()) } else { "default_host".to_string() })); key.push_str("/"); key.push_str(if oss_backupd_config_item.file_name.is_some() { oss_backupd_config_item.file_name.as_ref().unwrap().as_str() } else { "default_file_name" }); key.push_str("_"); let ymdhms = Utc::now().format("%Y%m%d_%H%M%S").to_string(); key.push_str(&ymdhms); if suffix != "" { key.push_str(&format!(".{}", suffix)); } key } pub fn remove_start_end_slash(s: &str) -> String { let mut ss = s; while ss.starts_with("/") { ss = &ss[1..] } while ss.ends_with("/") { ss = &ss[0..(ss.len() - 1)]; } ss.to_string() } pub fn parse_config(config_json: &json::JsonValue) -> OSSBackupdConfig { let root_oss_config_object = parse_sub_oss_config(config_json); let encrypt_pubkey_file = get_string_value(config_json, "encrypt_pubkey_file"); let prefix = get_string_value(config_json, "prefix"); let host = get_string_value(config_json, "host"); let items = &config_json["items"]; let mut items_objects: Vec = vec![]; if items.is_array() { for i in 0..items.len() { items_objects.push(parse_oss_backupd_config_item(&items[i], &root_oss_config_object, &encrypt_pubkey_file)); } } OSSBackupdConfig { oss_config: root_oss_config_object, prefix: prefix, host: host, items: items_objects, } } fn parse_oss_backupd_config_item(item: &json::JsonValue, root_oss_config_object: &Option, root_encrypt_pubkey_file: &Option) -> OSSBackupdConfigItem { let target = get_string_value(item, "target"); let file_name = get_string_value(item, "file_name"); let mut encrypt_pubkey_file = get_string_value(item, "encrypt_pubkey_file"); let mut oss_config = parse_sub_oss_config(item); if root_oss_config_object.is_some() { if oss_config.is_some() { let mut oc = oss_config.unwrap(); let root_oc = root_oss_config_object.as_ref().unwrap(); if oc.endpoint.is_none() && root_oc.endpoint.is_some() { oc.endpoint = root_oc.endpoint.clone() } if oc.access_key_id.is_none() && root_oc.access_key_id.is_some() { oc.access_key_id = root_oc.access_key_id.clone() } if oc.access_key_secret.is_none() && root_oc.access_key_secret.is_some() { oc.access_key_secret = root_oc.access_key_secret.clone(); } if oc.bucket.is_none() && root_oc.bucket.is_some() { oc.bucket = root_oc.bucket.clone(); } if oc.path.is_none() && root_oc.path.is_some() { oc.path = root_oc.path.clone(); } oss_config = Some(oc); } else { oss_config = root_oss_config_object.clone(); } } if encrypt_pubkey_file.is_none() && root_encrypt_pubkey_file.is_some() { encrypt_pubkey_file = root_encrypt_pubkey_file.clone(); } OSSBackupdConfigItem { target: target, file_name: file_name, oss_config: oss_config, encrypt_pubkey_file: encrypt_pubkey_file, } } fn parse_sub_oss_config(json: &json::JsonValue) -> Option { let root_oss_config = &json["oss_config"]; let root_oss_config_object: Option = match root_oss_config.is_null() { true => None, false => Some(parse_oss_config(root_oss_config)), }; root_oss_config_object } fn parse_oss_config(oss_config: &json::JsonValue) -> OSSConfig { OSSConfig { endpoint: get_string_value(oss_config, "endpoint"), access_key_id: get_string_value(oss_config, "access_key_id"), access_key_secret: get_string_value(oss_config, "access_key_secret"), bucket: get_string_value(oss_config, "bucket"), path: get_string_value(oss_config, "path"), } } fn get_string_value(json: &json::JsonValue, key: &str) -> Option { let value = &json[key]; match value.is_string() { true => Some(value.as_str().unwrap().to_string()), false => None, } } pub fn get_config_json(custom_oss_backupd_config: Option<&str>, verbose: bool) -> Option { let config_content = get_config_content(custom_oss_backupd_config, verbose)?; match json::parse(&config_content) { Err(e) => { print_message(MessageType::ERROR, &format!("Parse config json failed: {}", e)); None }, Ok(o) => Some(o), } } fn get_config_content(custom_oss_backupd_config: Option<&str>, verbose: bool) -> Option { if custom_oss_backupd_config.is_some() { let custom_oss_backupd_config_unrwaped = custom_oss_backupd_config.unwrap(); if verbose { print_message(MessageType::DEBUG, &format!("Read config from: {}", custom_oss_backupd_config_unrwaped)); } let custom_oss_backupd_config_path = Path::new(custom_oss_backupd_config_unrwaped); if custom_oss_backupd_config_path.exists() { match fs::read_to_string(custom_oss_backupd_config_path) { Err(e) => { print_message(MessageType::ERROR, &format!("Read config file {} error: {}", custom_oss_backupd_config_unrwaped, e)); return None; }, Ok(o) => return Some(o), }; } else { print_message(MessageType::ERROR, &format!("Custom config file not found: {}", custom_oss_backupd_config_unrwaped)); return None; } } // is not assigned by -c or --conifg FILE let oss_backupd_config_path = Path::new(OSS_BACKUPD_CONFIG); if oss_backupd_config_path.exists() { if verbose { print_message(MessageType::DEBUG, &format!("Read config from: {}", OSS_BACKUPD_CONFIG)); } match fs::read_to_string(oss_backupd_config_path) { Err(e) => { print_message(MessageType::ERROR, &format!("Read config file {} error: {}", OSS_BACKUPD_CONFIG, e)); return None; }, Ok(o) => return Some(o), }; } let home_dot_oss_backupd_config = & match get_user_home_dir(DOT_OSS_BACKUPD_CONFIG) { Err(e) => { print_message(MessageType::WARN, &format!("Get user home error: {}", e)); String::new() }, Ok(o) => o, }; if home_dot_oss_backupd_config != "" { let home_dot_oss_backupd_config_path = Path::new(home_dot_oss_backupd_config); if home_dot_oss_backupd_config_path.exists() { if verbose { print_message(MessageType::DEBUG, &format!("Read config from: {}", home_dot_oss_backupd_config)); } match fs::read_to_string(home_dot_oss_backupd_config_path) { Err(e) => { print_message(MessageType::ERROR, &format!("Read config file {} error: {}", home_dot_oss_backupd_config, e)); return None; }, Ok(o) => return Some(o), }; } } let etc_oss_backupd_config_path = Path::new(ETC_OSS_BACKUPD_CONFIG); if etc_oss_backupd_config_path.exists() { if verbose { print_message(MessageType::DEBUG, &format!("Read config from: {}", ETC_OSS_BACKUPD_CONFIG)); } match fs::read_to_string(etc_oss_backupd_config_path) { Err(e) => { print_message(MessageType::ERROR, &format!("Read config file {} error: {}", ETC_OSS_BACKUPD_CONFIG, e)); return None; }, Ok(o) => return Some(o), }; } print_message(MessageType::ERROR, "Cannot find config file"); None } fn get_user_home() -> XResult { match dirs::home_dir() { None => Err(new_box_ioerror("Home dir not found!")), Some(home_dir_o) => match home_dir_o.to_str() { None => Err(new_box_ioerror("Home dir not found!")), Some(home_dir_str) => Ok(home_dir_str.to_string()), }, } } fn get_user_home_dir(dir: &str) -> XResult { Ok(format!("{}/{}", get_user_home()?, dir)) }