refactor: adjust all path methods and reduce unwrap

This commit is contained in:
GyDi 2022-11-18 09:35:05 +08:00
parent be81cd72af
commit 34daffbc96
No known key found for this signature in database
GPG Key ID: 9C3AD40F1F99880A
11 changed files with 204 additions and 181 deletions

View File

@ -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<VecDeque<String>> {
#[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))
}

View File

@ -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"),
)

View File

@ -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,
}

View File

@ -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::<Self>(&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::<Self>(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

View File

@ -85,13 +85,36 @@ pub struct IVergeTheme {
impl IVerge {
pub fn new() -> Self {
config::read_yaml::<IVerge>(dirs::verge_path())
match dirs::verge_path().and_then(|path| config::read_yaml::<IVerge>(&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::<IVerge>(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::<IVerge>(&path)) {
Ok(config) => config.app_singleton_port.unwrap_or(SERVER_PORT),
Err(_) => SERVER_PORT, // 这里就不log错误了
}
}
}

View File

@ -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();

View File

@ -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"))?;
// 检查配置是否正常

View File

@ -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<T: DeserializeOwned + Default>(path: PathBuf) -> T {
pub fn read_yaml<T: DeserializeOwned>(path: &PathBuf) -> Result<T> {
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::<T>(&yaml_str) {
Ok(val) => val,
Err(_) => {
log::error!(target: "app", "failed to read yaml file \"{}\"", path.display());
T::default()
}
}
serde_yaml::from_str::<T>(&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<Mapping> {
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::<Value>(&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

View File

@ -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<PathBuf> = None;
@ -21,7 +20,7 @@ static mut RESOURCE_DIR: Option<PathBuf> = 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<PathBuf> {
#[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<PathBuf> {
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<PathBuf> {
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<PathBuf> {
Ok(app_home_dir()?.join("logs"))
}
pub fn clash_path() -> PathBuf {
app_home_dir().join(CLASH_CONFIG)
pub fn clash_path() -> Result<PathBuf> {
Ok(app_home_dir()?.join(CLASH_CONFIG))
}
pub fn verge_path() -> PathBuf {
app_home_dir().join(VERGE_CONFIG)
pub fn verge_path() -> Result<PathBuf> {
Ok(app_home_dir()?.join(VERGE_CONFIG))
}
pub fn profiles_path() -> PathBuf {
app_home_dir().join(PROFILE_YAML)
pub fn profiles_path() -> Result<PathBuf> {
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<PathBuf> {
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<PathBuf> {
Ok(temp_dir().join("clash-verge-check.yaml"))
}
pub fn app_res_dir() -> Result<PathBuf> {
unsafe {
Ok(RESOURCE_DIR
.clone()
.ok_or(anyhow::anyhow!("failed to get the resource dir"))?)
}
}
pub fn clash_pid_path() -> Result<PathBuf> {
unsafe { Ok(RESOURCE_DIR.clone().unwrap().join("clash.pid")) }
}
#[cfg(windows)]

View File

@ -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(())
}

View File

@ -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