From 34daffbc966755568153130052c7d3219847e770 Mon Sep 17 00:00:00 2001 From: GyDi Date: Fri, 18 Nov 2022 09:35:05 +0800 Subject: [PATCH] refactor: adjust all path methods and reduce unwrap --- src-tauri/src/cmds.rs | 6 +-- src-tauri/src/config/clash.rs | 23 +++++++++- src-tauri/src/config/prfitem.rs | 10 ++--- src-tauri/src/config/profiles.rs | 72 +++++++++++++++++-------------- src-tauri/src/config/verge.rs | 34 ++++++++++++--- src-tauri/src/core/clash_api.rs | 2 +- src-tauri/src/core/core.rs | 17 ++++---- src-tauri/src/utils/config.rs | 51 +++++++++------------- src-tauri/src/utils/dirs.rs | 73 ++++++++++++++++++++------------ src-tauri/src/utils/init.rs | 60 +++++++++++++------------- src-tauri/src/utils/tmpl.rs | 37 ---------------- 11 files changed, 204 insertions(+), 181 deletions(-) diff --git a/src-tauri/src/cmds.rs b/src-tauri/src/cmds.rs index 2dbb5e4..c96e90e 100644 --- a/src-tauri/src/cmds.rs +++ b/src-tauri/src/cmds.rs @@ -121,7 +121,7 @@ pub fn view_profile(index: String) -> CmdResult { .ok_or("the file field is null") }?; - let path = dirs::app_profiles_dir().join(file); + let path = wrap_err!(dirs::app_profiles_dir())?.join(file); if !path.exists() { ret_err!("the file not found"); } @@ -236,13 +236,13 @@ pub fn get_clash_logs() -> CmdResult> { #[tauri::command] pub fn open_app_dir() -> CmdResult<()> { - let app_dir = dirs::app_home_dir(); + let app_dir = wrap_err!(dirs::app_home_dir())?; wrap_err!(open::that(app_dir)) } #[tauri::command] pub fn open_logs_dir() -> CmdResult<()> { - let log_dir = dirs::app_logs_dir(); + let log_dir = wrap_err!(dirs::app_logs_dir())?; wrap_err!(open::that(log_dir)) } diff --git a/src-tauri/src/config/clash.rs b/src-tauri/src/config/clash.rs index d590383..e864d48 100644 --- a/src-tauri/src/config/clash.rs +++ b/src-tauri/src/config/clash.rs @@ -8,7 +8,26 @@ pub struct IClashTemp(pub Mapping); impl IClashTemp { pub fn new() -> Self { - Self(config::read_merge_mapping(dirs::clash_path())) + match dirs::clash_path().and_then(|path| config::read_merge_mapping(&path)) { + Ok(map) => Self(map), + Err(err) => { + log::error!(target: "app", "{err}"); + Self::template() + } + } + } + + pub fn template() -> Self { + let mut map = Mapping::new(); + + map.insert("mixed-port".into(), 7892.into()); + map.insert("log-level".into(), "info".into()); + map.insert("allow-lan".into(), false.into()); + map.insert("mode".into(), "rule".into()); + map.insert("external-controller".into(), "127.0.0.1:9090".into()); + map.insert("secret".into(), "".into()); + + Self(map) } pub fn patch_config(&mut self, patch: Mapping) { @@ -19,7 +38,7 @@ impl IClashTemp { pub fn save_config(&self) -> Result<()> { config::save_yaml( - dirs::clash_path(), + dirs::clash_path()?, &self.0, Some("# Default Config For ClashN Core\n\n"), ) diff --git a/src-tauri/src/config/prfitem.rs b/src-tauri/src/config/prfitem.rs index cb81212..b2e6444 100644 --- a/src-tauri/src/config/prfitem.rs +++ b/src-tauri/src/config/prfitem.rs @@ -355,7 +355,7 @@ impl PrfItem { } let file = self.file.clone().unwrap(); - let path = dirs::app_profiles_dir().join(file); + let path = dirs::app_profiles_dir()?.join(file); fs::read_to_string(path).context("failed to read the file") } @@ -366,7 +366,7 @@ impl PrfItem { } let file = self.file.clone().unwrap(); - let path = dirs::app_profiles_dir().join(file); + let path = dirs::app_profiles_dir()?.join(file); fs::write(path, data.as_bytes()).context("failed to save the file") } @@ -375,7 +375,7 @@ impl PrfItem { let itype = self.itype.as_ref()?.as_str(); let file = self.file.clone()?; let uid = self.uid.clone().unwrap_or("".into()); - let path = dirs::app_profiles_dir().join(file); + let path = dirs::app_profiles_dir().ok()?.join(file); if !path.exists() { return None; @@ -384,11 +384,11 @@ impl PrfItem { match itype { "script" => Some(ChainItem { uid, - data: ChainType::Script(fs::read_to_string(path).unwrap_or("".into())), + data: ChainType::Script(fs::read_to_string(path).ok()?), }), "merge" => Some(ChainItem { uid, - data: ChainType::Merge(config::read_merge_mapping(path)), + data: ChainType::Merge(config::read_merge_mapping(&path).ok()?), }), _ => None, } diff --git a/src-tauri/src/config/profiles.rs b/src-tauri/src/config/profiles.rs index 27f9067..847e233 100644 --- a/src-tauri/src/config/profiles.rs +++ b/src-tauri/src/config/profiles.rs @@ -32,30 +32,40 @@ macro_rules! patch { impl IProfiles { pub fn new() -> Self { - Self::read_file() + match dirs::profiles_path().and_then(|path| config::read_yaml::(&path)) { + Ok(mut profiles) => { + if profiles.items.is_none() { + profiles.items = Some(vec![]); + } + // compatible with the old old old version + profiles.items.as_mut().map(|items| { + for mut item in items.iter_mut() { + if item.uid.is_none() { + item.uid = Some(help::get_uid("d")); + } + } + }); + profiles + } + Err(err) => { + log::error!(target: "app", "{err}"); + Self::template() + } + } } - /// read the config from the file - pub fn read_file() -> Self { - let mut profiles = config::read_yaml::(dirs::profiles_path()); - if profiles.items.is_none() { - profiles.items = Some(vec![]); + pub fn template() -> Self { + Self { + valid: Some(vec!["dns".into()]), + items: Some(vec![]), + ..Self::default() } - // compatible with the old old old version - profiles.items.as_mut().map(|items| { - for mut item in items.iter_mut() { - if item.uid.is_none() { - item.uid = Some(help::get_uid("d")); - } - } - }); - profiles } /// save the config to the file pub fn save_file(&self) -> Result<()> { config::save_yaml( - dirs::profiles_path(), + dirs::profiles_path()?, self, Some("# Profiles Config for Clash Verge\n\n"), ) @@ -131,7 +141,7 @@ impl IProfiles { } let file = item.file.clone().unwrap(); - let path = dirs::app_profiles_dir().join(&file); + let path = dirs::app_profiles_dir()?.join(&file); fs::File::create(path) .context(format!("failed to create file \"{}\"", file))? @@ -200,7 +210,7 @@ impl IProfiles { // the file must exists each.file = Some(file.clone()); - let path = dirs::app_profiles_dir().join(&file); + let path = dirs::app_profiles_dir()?.join(&file); fs::File::create(path) .context(format!("failed to create file \"{}\"", file))? @@ -235,10 +245,12 @@ impl IProfiles { if let Some(index) = index { items.remove(index).file.map(|file| { - let path = dirs::app_profiles_dir().join(file); - if path.exists() { - let _ = fs::remove_file(path); - } + let _ = dirs::app_profiles_dir().map(|path| { + let path = path.join(file); + if path.exists() { + let _ = fs::remove_file(path); + } + }); }); } @@ -263,22 +275,18 @@ impl IProfiles { return Ok(config); } - let current = self.current.clone().unwrap(); + let current = self.current.as_ref().unwrap(); for item in self.items.as_ref().unwrap().iter() { - if item.uid == Some(current.clone()) { - let file_path = match item.file.clone() { - Some(file) => dirs::app_profiles_dir().join(file), + if item.uid.as_ref() == Some(current) { + let file_path = match item.file.as_ref() { + Some(file) => dirs::app_profiles_dir()?.join(file), None => bail!("failed to get the file field"), }; - if !file_path.exists() { - bail!("failed to read the file \"{}\"", file_path.display()); - } - - return Ok(config::read_merge_mapping(file_path.clone())); + return Ok(config::read_merge_mapping(&file_path)?); } } - bail!("failed to find current profile \"uid:{current}\""); + bail!("failed to find the current profile \"uid:{current}\""); } /// generate the data for activate clash config diff --git a/src-tauri/src/config/verge.rs b/src-tauri/src/config/verge.rs index c5986a9..8c21cfe 100644 --- a/src-tauri/src/config/verge.rs +++ b/src-tauri/src/config/verge.rs @@ -85,13 +85,36 @@ pub struct IVergeTheme { impl IVerge { pub fn new() -> Self { - config::read_yaml::(dirs::verge_path()) + match dirs::verge_path().and_then(|path| config::read_yaml::(&path)) { + Ok(config) => config, + Err(err) => { + log::error!(target: "app", "{err}"); + Self::template() + } + } + } + + pub fn template() -> Self { + Self { + clash_core: Some("clash".into()), + language: Some("en".into()), + theme_mode: Some("system".into()), + theme_blur: Some(false), + traffic_graph: Some(true), + enable_auto_launch: Some(false), + enable_silent_start: Some(false), + enable_system_proxy: Some(false), + enable_proxy_guard: Some(false), + proxy_guard_duration: Some(30), + auto_close_connection: Some(true), + ..Self::default() + } } /// Save IVerge App Config pub fn save_file(&self) -> Result<()> { config::save_yaml( - dirs::verge_path(), + dirs::verge_path()?, &self, Some("# The Config for Clash IVerge App\n\n"), ) @@ -133,13 +156,14 @@ impl IVerge { /// 在初始化前尝试拿到单例端口的值 pub fn get_singleton_port() -> u16 { - let config = config::read_yaml::(dirs::verge_path()); - #[cfg(not(feature = "verge-dev"))] const SERVER_PORT: u16 = 33331; #[cfg(feature = "verge-dev")] const SERVER_PORT: u16 = 11233; - config.app_singleton_port.unwrap_or(SERVER_PORT) + match dirs::verge_path().and_then(|path| config::read_yaml::(&path)) { + Ok(config) => config.app_singleton_port.unwrap_or(SERVER_PORT), + Err(_) => SERVER_PORT, // 这里就不log错误了 + } } } diff --git a/src-tauri/src/core/clash_api.rs b/src-tauri/src/core/clash_api.rs index 3dd796c..35e55d2 100644 --- a/src-tauri/src/core/clash_api.rs +++ b/src-tauri/src/core/clash_api.rs @@ -9,7 +9,7 @@ pub async fn put_configs() -> Result<()> { let (url, headers) = clash_client_info()?; let url = format!("{url}/configs"); - let runtime_yaml = dirs::clash_runtime_yaml(); + let runtime_yaml = dirs::clash_runtime_yaml()?; let runtime_yaml = dirs::path_to_str(&runtime_yaml)?; let mut data = HashMap::new(); diff --git a/src-tauri/src/core/core.rs b/src-tauri/src/core/core.rs index f9dee69..4011902 100644 --- a/src-tauri/src/core/core.rs +++ b/src-tauri/src/core/core.rs @@ -35,8 +35,10 @@ impl CoreManager { pub fn init(&self) -> Result<()> { // kill old clash process - if let Ok(pid) = fs::read(dirs::clash_pid_path()) { - if let Ok(pid) = String::from_utf8_lossy(&pid).parse() { + let _ = dirs::clash_pid_path() + .and_then(|path| fs::read(path).map(|p| p.to_vec()).context("")) + .and_then(|pid| String::from_utf8_lossy(&pid).parse().context("")) + .map(|pid| { let mut system = System::new(); system.refresh_all(); system.process(Pid::from_u32(pid)).map(|proc| { @@ -44,8 +46,7 @@ impl CoreManager { proc.kill(); } }); - } - } + }); tauri::async_runtime::spawn(async { // 启动clash @@ -61,7 +62,7 @@ impl CoreManager { /// 检查配置是否正确 pub fn check_config(&self) -> Result<()> { - let config_path = dirs::clash_runtime_yaml(); + let config_path = dirs::clash_runtime_yaml()?; let config_path = dirs::path_to_str(&config_path)?; let clash_core = { Config::verge().latest().clash_core.clone() }; @@ -116,7 +117,7 @@ impl CoreManager { let _ = child.kill(); } - let app_dir = dirs::app_home_dir(); + let app_dir = dirs::app_home_dir()?; let app_dir = dirs::path_to_str(&app_dir)?; let clash_core = { Config::verge().latest().clash_core.clone() }; @@ -134,7 +135,7 @@ impl CoreManager { // 将pid写入文件中 crate::log_err!({ let pid = cmd_child.pid(); - let path = dirs::clash_pid_path(); + let path = dirs::clash_pid_path()?; fs::File::create(path) .context("failed to create the pid file")? .write(format!("{pid}").as_bytes()) @@ -236,7 +237,7 @@ impl CoreManager { enhance::enhance_config(clash_config.0, pa.current, pa.chain, pa.valid, tun_mode); // 保存到文件中 - let runtime_path = dirs::clash_runtime_yaml(); + let runtime_path = dirs::clash_runtime_yaml()?; utils::config::save_yaml(runtime_path, &config, Some("# Clash Verge Runtime Config"))?; // 检查配置是否正常 diff --git a/src-tauri/src/utils/config.rs b/src-tauri/src/utils/config.rs index bcb99f6..c1c563a 100644 --- a/src-tauri/src/utils/config.rs +++ b/src-tauri/src/utils/config.rs @@ -1,47 +1,36 @@ -use anyhow::{Context, Result}; +use anyhow::{anyhow, bail, Context, Result}; use serde::{de::DeserializeOwned, Serialize}; use serde_yaml::{Mapping, Value}; use std::{fs, path::PathBuf}; /// read data from yaml as struct T -pub fn read_yaml(path: PathBuf) -> T { +pub fn read_yaml(path: &PathBuf) -> Result { if !path.exists() { - log::error!(target: "app", "file not found \"{}\"", path.display()); - return T::default(); + bail!("file not found \"{}\"", path.display()); } - let yaml_str = fs::read_to_string(&path).unwrap_or("".into()); + let yaml_str = fs::read_to_string(&path) + .context(format!("failed to read the file \"{}\"", path.display()))?; - match serde_yaml::from_str::(&yaml_str) { - Ok(val) => val, - Err(_) => { - log::error!(target: "app", "failed to read yaml file \"{}\"", path.display()); - T::default() - } - } + serde_yaml::from_str::(&yaml_str).context(format!( + "failed to read the file with yaml format \"{}\"", + path.display() + )) } /// read mapping from yaml fix #165 -pub fn read_merge_mapping(path: PathBuf) -> Mapping { - let map = Mapping::new(); +pub fn read_merge_mapping(path: &PathBuf) -> Result { + let mut val: Value = read_yaml(path)?; + val.apply_merge() + .context(format!("failed to apply merge \"{}\"", path.display()))?; - if !path.exists() { - log::error!(target: "app", "file not found \"{}\"", path.display()); - return map; - } - - let yaml_str = fs::read_to_string(&path).unwrap_or("".into()); - - match serde_yaml::from_str::(&yaml_str) { - Ok(mut val) => { - crate::log_err!(val.apply_merge()); - val.as_mapping().unwrap_or(&map).to_owned() - } - Err(_) => { - log::error!(target: "app", "failed to read yaml file \"{}\"", path.display()); - map - } - } + Ok(val + .as_mapping() + .ok_or(anyhow!( + "failed to transform to yaml mapping \"{}\"", + path.display() + ))? + .to_owned()) } /// save the data to the file diff --git a/src-tauri/src/utils/dirs.rs b/src-tauri/src/utils/dirs.rs index 4eb56c5..8c32125 100644 --- a/src-tauri/src/utils/dirs.rs +++ b/src-tauri/src/utils/dirs.rs @@ -1,5 +1,5 @@ use anyhow::Result; -use std::path::PathBuf; +use std::{env::temp_dir, path::PathBuf}; use tauri::{ api::path::{home_dir, resource_dir}, Env, PackageInfo, @@ -13,7 +13,6 @@ static APP_DIR: &str = "clash-verge-dev"; static CLASH_CONFIG: &str = "config.yaml"; static VERGE_CONFIG: &str = "verge.yaml"; static PROFILE_YAML: &str = "profiles.yaml"; -static CLASH_RUNTIME_YAML: &str = "clash-verge-runtime.yaml"; static mut RESOURCE_DIR: Option = None; @@ -21,7 +20,7 @@ static mut RESOURCE_DIR: Option = None; #[allow(unused)] static mut PORTABLE_FLAG: bool = false; -pub static mut APP_VERSION: &str = "v1.1.1"; +pub static mut APP_VERSION: &str = "v1.1.2"; /// initialize portable flag #[cfg(target_os = "windows")] @@ -42,29 +41,37 @@ pub unsafe fn init_portable_flag() -> Result<()> { } /// get the verge app home dir -pub fn app_home_dir() -> PathBuf { +pub fn app_home_dir() -> Result { #[cfg(target_os = "windows")] unsafe { use tauri::utils::platform::current_exe; if !PORTABLE_FLAG { - home_dir().unwrap().join(".config").join(APP_DIR) + Ok(home_dir() + .ok_or(anyhow::anyhow!("failed to get app home dir"))? + .join(".config") + .join(APP_DIR)) } else { - let app_exe = current_exe().unwrap(); - let app_exe = dunce::canonicalize(app_exe).unwrap(); - let app_dir = app_exe.parent().unwrap(); - PathBuf::from(app_dir).join(".config").join(APP_DIR) + let app_exe = current_exe()?; + let app_exe = dunce::canonicalize(app_exe)?; + let app_dir = app_exe + .parent() + .ok_or(anyhow::anyhow!("failed to get the portable app dir"))?; + Ok(PathBuf::from(app_dir).join(".config").join(APP_DIR)) } } #[cfg(not(target_os = "windows"))] - home_dir().unwrap().join(".config").join(APP_DIR) + Ok(home_dir() + .ok_or(anyhow::anyhow!("failed to get the app home dir"))? + .join(".config") + .join(APP_DIR)) } /// get the resources dir -pub fn app_resources_dir(package_info: &PackageInfo) -> PathBuf { +pub fn app_resources_dir(package_info: &PackageInfo) -> Result { let res_dir = resource_dir(package_info, &Env::default()) - .unwrap() + .ok_or(anyhow::anyhow!("failed to get the resource dir"))? .join("resources"); unsafe { @@ -75,37 +82,49 @@ pub fn app_resources_dir(package_info: &PackageInfo) -> PathBuf { APP_VERSION = Box::leak(Box::new(ver_str)); } - res_dir + Ok(res_dir) } /// profiles dir -pub fn app_profiles_dir() -> PathBuf { - app_home_dir().join("profiles") +pub fn app_profiles_dir() -> Result { + Ok(app_home_dir()?.join("profiles")) } /// logs dir -pub fn app_logs_dir() -> PathBuf { - app_home_dir().join("logs") +pub fn app_logs_dir() -> Result { + Ok(app_home_dir()?.join("logs")) } -pub fn clash_path() -> PathBuf { - app_home_dir().join(CLASH_CONFIG) +pub fn clash_path() -> Result { + Ok(app_home_dir()?.join(CLASH_CONFIG)) } -pub fn verge_path() -> PathBuf { - app_home_dir().join(VERGE_CONFIG) +pub fn verge_path() -> Result { + Ok(app_home_dir()?.join(VERGE_CONFIG)) } -pub fn profiles_path() -> PathBuf { - app_home_dir().join(PROFILE_YAML) +pub fn profiles_path() -> Result { + Ok(app_home_dir()?.join(PROFILE_YAML)) } -pub fn clash_runtime_yaml() -> PathBuf { - app_home_dir().join(CLASH_RUNTIME_YAML) +pub fn clash_runtime_yaml() -> Result { + Ok(app_home_dir()?.join("clash-verge-runtime.yaml")) } -pub fn clash_pid_path() -> PathBuf { - unsafe { RESOURCE_DIR.clone().unwrap().join("clash.pid") } +pub fn clash_check_yaml() -> Result { + Ok(temp_dir().join("clash-verge-check.yaml")) +} + +pub fn app_res_dir() -> Result { + unsafe { + Ok(RESOURCE_DIR + .clone() + .ok_or(anyhow::anyhow!("failed to get the resource dir"))?) + } +} + +pub fn clash_pid_path() -> Result { + unsafe { Ok(RESOURCE_DIR.clone().unwrap().join("clash.pid")) } } #[cfg(windows)] diff --git a/src-tauri/src/utils/init.rs b/src-tauri/src/utils/init.rs index 7f6c74a..5f8d2a6 100644 --- a/src-tauri/src/utils/init.rs +++ b/src-tauri/src/utils/init.rs @@ -12,7 +12,7 @@ use tauri::PackageInfo; /// initialize this instance's log file fn init_log() -> Result<()> { - let log_dir = dirs::app_logs_dir(); + let log_dir = dirs::app_logs_dir()?; if !log_dir.exists() { let _ = fs::create_dir_all(&log_dir); } @@ -54,42 +54,40 @@ pub fn init_config() -> Result<()> { let _ = init_log(); - let app_dir = dirs::app_home_dir(); - let profiles_dir = dirs::app_profiles_dir(); + let _ = dirs::app_home_dir().map(|app_dir| { + if !app_dir.exists() { + let _ = fs::create_dir_all(&app_dir); + } - if !app_dir.exists() { - let _ = fs::create_dir_all(&app_dir); - } - if !profiles_dir.exists() { - let _ = fs::create_dir_all(&profiles_dir); - } + // // target path + // let clash_path = app_dir.join("config.yaml"); + // let verge_path = app_dir.join("verge.yaml"); + // let profile_path = app_dir.join("profiles.yaml"); - // target path - let clash_path = app_dir.join("config.yaml"); - let verge_path = app_dir.join("verge.yaml"); - let profile_path = app_dir.join("profiles.yaml"); + // if !clash_path.exists() { + // fs::File::create(clash_path)?.write(tmpl::CLASH_CONFIG)?; + // } + // if !verge_path.exists() { + // fs::File::create(verge_path)?.write(tmpl::VERGE_CONFIG)?; + // } + // if !profile_path.exists() { + // fs::File::create(profile_path)?.write(tmpl::PROFILES_CONFIG)?; + // } + }); + + let _ = dirs::app_profiles_dir().map(|profiles_dir| { + if !profiles_dir.exists() { + let _ = fs::create_dir_all(&profiles_dir); + } + }); - if !clash_path.exists() { - fs::File::create(clash_path)?.write(tmpl::CLASH_CONFIG)?; - } - if !verge_path.exists() { - fs::File::create(verge_path)?.write(tmpl::VERGE_CONFIG)?; - } - if !profile_path.exists() { - fs::File::create(profile_path)?.write(tmpl::PROFILES_CONFIG)?; - } Ok(()) } /// initialize app -pub fn init_resources(package_info: &PackageInfo) { - // create app dir - let app_dir = dirs::app_home_dir(); - let res_dir = dirs::app_resources_dir(package_info); - - if !app_dir.exists() { - let _ = fs::create_dir_all(&app_dir); - } +pub fn init_resources(package_info: &PackageInfo) -> Result<()> { + let app_dir = dirs::app_home_dir()?; + let res_dir = dirs::app_resources_dir(package_info)?; // copy the resource file for file in ["Country.mmdb", "geoip.dat", "geosite.dat", "wintun.dll"].iter() { @@ -99,4 +97,6 @@ pub fn init_resources(package_info: &PackageInfo) { let _ = fs::copy(src_path, target_path); } } + + Ok(()) } diff --git a/src-tauri/src/utils/tmpl.rs b/src-tauri/src/utils/tmpl.rs index 69aa805..ec17c33 100644 --- a/src-tauri/src/utils/tmpl.rs +++ b/src-tauri/src/utils/tmpl.rs @@ -1,42 +1,5 @@ ///! Some config file template -/// template for clash core `config.yaml` -pub const CLASH_CONFIG: &[u8] = br#"# Default Config For Clash Core - -mixed-port: 7890 -log-level: info -allow-lan: false -external-controller: 127.0.0.1:9090 -mode: rule -secret: "" -"#; - -/// template for `profiles.yaml` -pub const PROFILES_CONFIG: &[u8] = b"# Profiles Config for Clash Verge - -current: ~ -chain: ~ -valid: - - dns -items: ~ -"; - -/// template for `verge.yaml` -pub const VERGE_CONFIG: &[u8] = b"# Default Config For Clash Verge - -clash_core: clash -language: en -theme_mode: system -theme_blur: false -traffic_graph: true -enable_auto_launch: false -enable_silent_start: false -enable_system_proxy: false -enable_proxy_guard: false -proxy_guard_duration: 10 -auto_close_connection: true -"; - /// template for new a profile item pub const ITEM_LOCAL: &str = "# Profile Template for clash verge