refactor: done

This commit is contained in:
GyDi 2022-11-18 18:18:41 +08:00
parent 34daffbc96
commit 2667ed13f1
No known key found for this signature in database
GPG Key ID: 9C3AD40F1F99880A
24 changed files with 343 additions and 341 deletions

View File

@ -5,7 +5,7 @@ use crate::{
utils::{dirs, help},
};
use crate::{ret_err, wrap_err};
use anyhow::Result;
use anyhow::{Context, Result};
use serde_yaml::Mapping;
use std::collections::{HashMap, VecDeque};
use sysproxy::Sysproxy;
@ -19,7 +19,9 @@ pub fn get_profiles() -> CmdResult<IProfiles> {
#[tauri::command]
pub async fn enhance_profiles() -> CmdResult {
wrap_err!(feat::handle_activate().await)
wrap_err!(CoreManager::global().update_config().await)?;
handle::Handle::refresh_clash();
Ok(())
}
#[deprecated]
@ -40,75 +42,41 @@ pub async fn update_profile(index: String, option: Option<PrfOption>) -> CmdResu
wrap_err!(feat::update_profile(index, option).await)
}
#[tauri::command]
pub async fn select_profile(index: String) -> CmdResult {
wrap_err!({ Config::profiles().draft().put_current(index) })?;
match feat::handle_activate().await {
Ok(_) => {
Config::profiles().apply();
wrap_err!(Config::profiles().data().save_file())?;
Ok(())
}
Err(err) => {
Config::profiles().discard();
log::error!(target: "app", "{err}");
Err(format!("{err}"))
}
}
}
/// change the profile chain
#[tauri::command]
pub async fn change_profile_chain(chain: Option<Vec<String>>) -> CmdResult {
wrap_err!({ Config::profiles().draft().put_chain(chain) })?;
match feat::handle_activate().await {
Ok(_) => {
Config::profiles().apply();
wrap_err!(Config::profiles().data().save_file())?;
Ok(())
}
Err(err) => {
Config::profiles().discard();
log::error!(target: "app", "{err}");
Err(format!("{err}"))
}
}
}
#[tauri::command]
pub async fn change_profile_valid(valid: Option<Vec<String>>) -> CmdResult {
wrap_err!({ Config::profiles().draft().put_valid(valid) })?;
match feat::handle_activate().await {
Ok(_) => {
Config::profiles().apply();
wrap_err!(Config::profiles().data().save_file())?;
Ok(())
}
Err(err) => {
Config::profiles().discard();
log::error!(target: "app", "{err}");
Err(format!("{err}"))
}
}
}
#[tauri::command]
pub async fn delete_profile(index: String) -> CmdResult {
let should_update = wrap_err!({ Config::profiles().data().delete_item(index) })?;
if should_update {
wrap_err!(feat::handle_activate().await)?;
wrap_err!(CoreManager::global().update_config().await)?;
handle::Handle::refresh_clash();
}
Ok(())
}
/// 修改profiles的
#[tauri::command]
pub async fn patch_profiles_config(profiles: IProfiles) -> CmdResult {
wrap_err!({ Config::profiles().draft().patch_config(profiles) })?;
match CoreManager::global().update_config().await {
Ok(_) => {
handle::Handle::refresh_clash();
Config::profiles().apply();
wrap_err!(Config::profiles().data().save_file())?;
Ok(())
}
Err(err) => {
Config::profiles().discard();
log::error!(target: "app", "{err}");
Err(format!("{err}"))
}
}
}
/// 修改某个profile item的
#[tauri::command]
pub fn patch_profile(index: String, profile: PrfItem) -> CmdResult {
wrap_err!(Config::profiles().data().patch_item(index, profile))?;
wrap_err!(timer::Timer::global().refresh())
}
@ -157,34 +125,29 @@ pub fn get_clash_info() -> CmdResult<ClashInfoN> {
#[tauri::command]
pub fn get_runtime_config() -> CmdResult<Option<Mapping>> {
Ok(CoreManager::global().runtime_config.lock().config.clone())
Ok(Config::runtime().latest().config.clone())
}
#[tauri::command]
pub fn get_runtime_yaml() -> CmdResult<Option<String>> {
Ok(CoreManager::global()
.runtime_config
.lock()
.config_yaml
.clone())
pub fn get_runtime_yaml() -> CmdResult<String> {
let runtime = Config::runtime();
let runtime = runtime.latest();
let config = runtime.config.as_ref();
wrap_err!(config
.ok_or(anyhow::anyhow!("failed to parse config to yaml file"))
.and_then(
|config| serde_yaml::to_string(config).context("failed to convert config to yaml")
))
}
#[tauri::command]
pub fn get_runtime_exists() -> CmdResult<Vec<String>> {
Ok(CoreManager::global()
.runtime_config
.lock()
.exists_keys
.clone())
Ok(Config::runtime().latest().exists_keys.clone())
}
#[tauri::command]
pub fn get_runtime_logs() -> CmdResult<HashMap<String, Vec<(String, String)>>> {
Ok(CoreManager::global()
.runtime_config
.lock()
.chain_logs
.clone())
Ok(Config::runtime().latest().chain_logs.clone())
}
#[tauri::command]

View File

@ -1,4 +1,4 @@
use crate::utils::{config, dirs};
use crate::utils::{dirs, help};
use anyhow::Result;
use serde::{Deserialize, Serialize};
use serde_yaml::{Mapping, Value};
@ -8,7 +8,7 @@ pub struct IClashTemp(pub Mapping);
impl IClashTemp {
pub fn new() -> Self {
match dirs::clash_path().and_then(|path| config::read_merge_mapping(&path)) {
match dirs::clash_path().and_then(|path| help::read_merge_mapping(&path)) {
Ok(map) => Self(map),
Err(err) => {
log::error!(target: "app", "{err}");
@ -20,7 +20,7 @@ impl IClashTemp {
pub fn template() -> Self {
let mut map = Mapping::new();
map.insert("mixed-port".into(), 7892.into());
map.insert("mixed-port".into(), 7890.into());
map.insert("log-level".into(), "info".into());
map.insert("allow-lan".into(), false.into());
map.insert("mode".into(), "rule".into());
@ -37,10 +37,10 @@ impl IClashTemp {
}
pub fn save_config(&self) -> Result<()> {
config::save_yaml(
dirs::clash_path()?,
help::save_yaml(
&dirs::clash_path()?,
&self.0,
Some("# Default Config For ClashN Core\n\n"),
Some("# Generated by Clash Verge"),
)
}

View File

@ -1,10 +1,20 @@
use super::{Draft, IClashTemp, IProfiles, IVerge};
use super::{Draft, IClashTemp, IProfiles, IRuntime, IVerge};
use crate::{
enhance,
utils::{dirs, help},
};
use anyhow::{anyhow, Result};
use once_cell::sync::OnceCell;
use std::{env::temp_dir, path::PathBuf};
pub const RUNTIME_CONFIG: &str = "clash-verge.yaml";
pub const CHECK_CONFIG: &str = "clash-verge-check.yaml";
pub struct Config {
clash_config: Draft<IClashTemp>,
verge_config: Draft<IVerge>,
profiles_config: Draft<IProfiles>,
runtime_config: Draft<IRuntime>,
}
impl Config {
@ -15,6 +25,7 @@ impl Config {
clash_config: Draft::from(IClashTemp::new()),
verge_config: Draft::from(IVerge::new()),
profiles_config: Draft::from(IProfiles::new()),
runtime_config: Draft::from(IRuntime::new()),
})
}
@ -29,4 +40,72 @@ impl Config {
pub fn profiles() -> Draft<IProfiles> {
Self::global().profiles_config.clone()
}
pub fn runtime() -> Draft<IRuntime> {
Self::global().runtime_config.clone()
}
/// 初始化配置
pub fn init_config() -> Result<()> {
crate::log_err!(Self::generate());
if let Err(err) = Self::generate_file(ConfigType::Run) {
log::error!(target: "app", "{err}");
let runtime_path = dirs::app_home_dir()?.join(RUNTIME_CONFIG);
// 如果不存在就将默认的clash文件拿过来
if !runtime_path.exists() {
help::save_yaml(
&runtime_path,
&Config::clash().latest().0,
Some("# Clash Verge Runtime"),
)?;
}
}
Ok(())
}
/// 将配置丢到对应的文件中
pub fn generate_file(typ: ConfigType) -> Result<PathBuf> {
let path = match typ {
ConfigType::Run => dirs::app_home_dir()?.join(RUNTIME_CONFIG),
ConfigType::Check => temp_dir().join(CHECK_CONFIG),
};
let runtime = Config::runtime();
let runtime = runtime.latest();
let config = runtime
.config
.as_ref()
.ok_or(anyhow!("failed to get runtime config"))?;
help::save_yaml(&path, &config, Some("# Generated by Clash Verge"))?;
Ok(path)
}
/// 生成配置存好
pub fn generate() -> Result<()> {
let clash_config = { Config::clash().latest().clone() };
let tun_mode = { Config::verge().latest().enable_tun_mode.clone() };
let tun_mode = tun_mode.unwrap_or(false);
let pa = { Config::profiles().latest().gen_activate()? };
let (config, exists_keys, logs) =
enhance::enhance_config(clash_config.0, pa.current, pa.chain, pa.valid, tun_mode);
*Config::runtime().draft() = IRuntime {
config: Some(config),
exists_keys,
chain_logs: logs,
};
Ok(())
}
}
#[derive(Debug)]
pub enum ConfigType {
Run,
Check,
}

View File

@ -1,4 +1,4 @@
use super::{IClashTemp, IProfiles, IVerge};
use super::{IClashTemp, IProfiles, IRuntime, IVerge};
use parking_lot::{MappedMutexGuard, Mutex, MutexGuard};
use std::sync::Arc;
@ -10,6 +10,7 @@ pub struct Draft<T: Clone + ToOwned> {
macro_rules! draft_define {
($id: ident) => {
impl Draft<$id> {
#[allow(unused)]
pub fn data(&self) -> MappedMutexGuard<$id> {
MutexGuard::map(self.inner.lock(), |guard| &mut guard.0)
}
@ -65,9 +66,9 @@ macro_rules! draft_define {
// draft_define!(IClash);
draft_define!(IClashTemp);
draft_define!(IVerge);
// draft_define!(Mapping);
draft_define!(IProfiles);
draft_define!(IRuntime);
draft_define!(IVerge);
#[test]
fn test_draft() {

View File

@ -3,6 +3,7 @@ mod config;
mod draft;
mod prfitem;
mod profiles;
mod runtime;
mod verge;
pub use self::clash::*;
@ -10,4 +11,5 @@ pub use self::config::*;
pub use self::draft::*;
pub use self::prfitem::*;
pub use self::profiles::*;
pub use self::runtime::*;
pub use self::verge::*;

View File

@ -1,4 +1,4 @@
use crate::utils::{config, dirs, help, tmpl};
use crate::utils::{dirs, help, tmpl};
use anyhow::{bail, Context, Result};
use reqwest::StatusCode;
use serde::{Deserialize, Serialize};
@ -388,7 +388,7 @@ impl PrfItem {
}),
"merge" => Some(ChainItem {
uid,
data: ChainType::Merge(config::read_merge_mapping(&path).ok()?),
data: ChainType::Merge(help::read_merge_mapping(&path).ok()?),
}),
_ => None,
}

View File

@ -1,9 +1,8 @@
use super::{prfitem::PrfItem, ChainItem};
use crate::utils::{config, dirs, help};
use crate::utils::{dirs, help};
use anyhow::{bail, Context, Result};
use serde::{Deserialize, Serialize};
use serde_yaml::Mapping;
use std::collections::HashMap;
use std::{fs, io::Write};
/// Define the `profiles.yaml` schema
@ -32,7 +31,7 @@ macro_rules! patch {
impl IProfiles {
pub fn new() -> Self {
match dirs::profiles_path().and_then(|path| config::read_yaml::<Self>(&path)) {
match dirs::profiles_path().and_then(|path| help::read_yaml::<Self>(&path)) {
Ok(mut profiles) => {
if profiles.items.is_none() {
profiles.items = Some(vec![]);
@ -62,21 +61,45 @@ impl IProfiles {
}
}
/// save the config to the file
pub fn save_file(&self) -> Result<()> {
config::save_yaml(
dirs::profiles_path()?,
help::save_yaml(
&dirs::profiles_path()?,
self,
Some("# Profiles Config for Clash Verge\n\n"),
Some("# Profiles Config for Clash Verge"),
)
}
/// get the current uid
/// 只修改currentvalid和chain
pub fn patch_config(&mut self, patch: IProfiles) -> Result<()> {
if self.items.is_none() {
self.items = Some(vec![]);
}
if let Some(current) = patch.current {
let items = self.items.as_ref().unwrap();
let some_uid = Some(current);
if items.iter().any(|e| e.uid == some_uid) {
self.current = some_uid;
}
}
if let Some(chain) = patch.chain {
self.chain = Some(chain);
}
if let Some(valid) = patch.valid {
self.valid = Some(valid);
}
Ok(())
}
pub fn get_current(&self) -> Option<String> {
self.current.clone()
}
/// only change the main to the target id
#[deprecated]
pub fn put_current(&mut self, uid: String) -> Result<()> {
if self.items.is_none() {
self.items = Some(vec![]);
@ -93,13 +116,13 @@ impl IProfiles {
bail!("invalid uid \"{uid}\"");
}
/// just change the `chain`
#[deprecated]
pub fn put_chain(&mut self, chain: Option<Vec<String>>) -> Result<()> {
self.chain = chain;
self.save_file()
}
/// just change the `field`
#[deprecated]
pub fn put_valid(&mut self, valid: Option<Vec<String>>) -> Result<()> {
self.valid = valid;
self.save_file()
@ -283,7 +306,7 @@ impl IProfiles {
None => bail!("failed to get the file field"),
};
return Ok(config::read_merge_mapping(&file_path)?);
return Ok(help::read_merge_mapping(&file_path)?);
}
}
bail!("failed to find the current profile \"uid:{current}\"");
@ -316,13 +339,3 @@ pub struct PrfActivate {
pub chain: Vec<ChainItem>,
pub valid: Vec<String>,
}
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct RuntimeResult {
pub config: Option<Mapping>,
pub config_yaml: Option<String>,
// 记录在配置中包括merge和script生成的出现过的keys
// 这些keys不一定都生效
pub exists_keys: Vec<String>,
pub chain_logs: HashMap<String, Vec<(String, String)>>,
}

View File

@ -0,0 +1,18 @@
use serde::{Deserialize, Serialize};
use serde_yaml::Mapping;
use std::collections::HashMap;
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
pub struct IRuntime {
pub config: Option<Mapping>,
// 记录在配置中包括merge和script生成的出现过的keys
// 这些keys不一定都生效
pub exists_keys: Vec<String>,
pub chain_logs: HashMap<String, Vec<(String, String)>>,
}
impl IRuntime {
pub fn new() -> Self {
Self::default()
}
}

View File

@ -1,4 +1,4 @@
use crate::utils::{config, dirs};
use crate::utils::{dirs, help};
use anyhow::Result;
use serde::{Deserialize, Serialize};
@ -85,7 +85,7 @@ pub struct IVergeTheme {
impl IVerge {
pub fn new() -> Self {
match dirs::verge_path().and_then(|path| config::read_yaml::<IVerge>(&path)) {
match dirs::verge_path().and_then(|path| help::read_yaml::<IVerge>(&path)) {
Ok(config) => config,
Err(err) => {
log::error!(target: "app", "{err}");
@ -113,11 +113,7 @@ impl IVerge {
/// Save IVerge App Config
pub fn save_file(&self) -> Result<()> {
config::save_yaml(
dirs::verge_path()?,
&self,
Some("# The Config for Clash IVerge App\n\n"),
)
help::save_yaml(&dirs::verge_path()?, &self, Some("# Clash Verge Config"))
}
/// patch verge config
@ -161,7 +157,7 @@ impl IVerge {
#[cfg(feature = "verge-dev")]
const SERVER_PORT: u16 = 11233;
match dirs::verge_path().and_then(|path| config::read_yaml::<IVerge>(&path)) {
match dirs::verge_path().and_then(|path| help::read_yaml::<IVerge>(&path)) {
Ok(config) => config.app_singleton_port.unwrap_or(SERVER_PORT),
Err(_) => SERVER_PORT, // 这里就不log错误了
}

View File

@ -1,19 +1,17 @@
use crate::{config::Config, utils::dirs};
use crate::config::Config;
use anyhow::{bail, Result};
use reqwest::header::HeaderMap;
use serde_yaml::Mapping;
use std::collections::HashMap;
/// PUT /configs
pub async fn put_configs() -> Result<()> {
/// path 是绝对路径
pub async fn put_configs(path: &str) -> Result<()> {
let (url, headers) = clash_client_info()?;
let url = format!("{url}/configs");
let runtime_yaml = dirs::clash_runtime_yaml()?;
let runtime_yaml = dirs::path_to_str(&runtime_yaml)?;
let mut data = HashMap::new();
data.insert("path", runtime_yaml);
data.insert("path", path);
let client = reqwest::ClientBuilder::new().no_proxy().build()?;
let builder = client.put(&url).headers(headers).json(&data);

View File

@ -1,9 +1,6 @@
use super::{clash_api, logger::Logger};
use crate::{
config::*,
enhance, log_err,
utils::{self, dirs},
};
use crate::log_err;
use crate::{config::*, utils::dirs};
use anyhow::{bail, Context, Result};
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
@ -18,8 +15,6 @@ pub struct CoreManager {
#[allow(unused)]
use_service_mode: Arc<Mutex<bool>>,
pub runtime_config: Arc<Mutex<RuntimeResult>>,
}
impl CoreManager {
@ -28,7 +23,6 @@ impl CoreManager {
CORE_MANAGER.get_or_init(|| CoreManager {
sidecar: Arc::new(Mutex::new(None)),
runtime_config: Arc::new(Mutex::new(RuntimeResult::default())),
use_service_mode: Arc::new(Mutex::new(false)),
})
}
@ -50,11 +44,7 @@ impl CoreManager {
tauri::async_runtime::spawn(async {
// 启动clash
if Self::global().run_core().await.is_ok() {
// 更新配置
sleep(Duration::from_millis(100)).await;
crate::log_err!(Self::global().activate_config().await);
}
log_err!(Self::global().run_core().await);
});
Ok(())
@ -62,7 +52,7 @@ impl CoreManager {
/// 检查配置是否正确
pub fn check_config(&self) -> Result<()> {
let config_path = dirs::clash_runtime_yaml()?;
let config_path = Config::generate_file(ConfigType::Check)?;
let config_path = dirs::path_to_str(&config_path)?;
let clash_core = { Config::verge().latest().clash_core.clone() };
@ -82,6 +72,8 @@ impl CoreManager {
/// 启动核心
pub async fn run_core(&self) -> Result<()> {
let config_path = Config::generate_file(ConfigType::Run)?;
#[cfg(target_os = "windows")]
{
use super::win_service;
@ -123,10 +115,12 @@ impl CoreManager {
let clash_core = { Config::verge().latest().clash_core.clone() };
let clash_core = clash_core.unwrap_or("clash".into());
let config_path = dirs::path_to_str(&config_path)?;
// fix #212
let args = match clash_core.as_str() {
"clash-meta" => vec!["-m", "-d", app_dir],
_ => vec!["-d", app_dir],
"clash-meta" => vec!["-m", "-d", app_dir, "-f", config_path],
_ => vec!["-d", app_dir, "-f", config_path],
};
let cmd = Command::new_sidecar(clash_core)?;
@ -199,53 +193,42 @@ impl CoreManager {
bail!("invalid clash core name \"{clash_core}\"");
}
Config::verge().draft().clash_core = Some(clash_core);
// 清掉旧日志
Logger::global().clear_log();
{
Config::verge().draft().clash_core = Some(clash_core);
}
match self.run_core().await {
Ok(_) => {
log_err!({
Config::verge().apply();
Config::verge().latest().save_file()
});
sleep(Duration::from_millis(100)).await; // 等一会儿再更新配置
self.activate_config().await?;
Config::verge().apply();
Config::runtime().apply();
log_err!(Config::verge().latest().save_file());
Ok(())
}
Err(err) => {
Config::verge().discard();
Config::runtime().discard();
Err(err)
}
}
}
/// 激活一个配置
pub async fn activate_config(&self) -> Result<()> {
let clash_config = { Config::clash().latest().clone() };
let tun_mode = { Config::verge().latest().enable_tun_mode.clone() };
let tun_mode = tun_mode.unwrap_or(false);
let pa = { Config::profiles().latest().gen_activate()? };
let (config, exists_keys, logs) =
enhance::enhance_config(clash_config.0, pa.current, pa.chain, pa.valid, tun_mode);
// 保存到文件中
let runtime_path = dirs::clash_runtime_yaml()?;
utils::config::save_yaml(runtime_path, &config, Some("# Clash Verge Runtime Config"))?;
/// 更新proxies那些
/// 如果涉及端口和外部控制则需要重启
pub async fn update_config(&self) -> Result<()> {
// 更新配置
Config::generate()?;
// 检查配置是否正常
self.check_config()?;
// 更新运行时配置
let path = Config::generate_file(ConfigType::Run)?;
let path = dirs::path_to_str(&path)?;
// 发送请求 发送5次
for i in 0..5 {
match clash_api::put_configs().await {
match clash_api::put_configs(path).await {
Ok(_) => break,
Err(err) => {
if i < 4 {
@ -258,16 +241,6 @@ impl CoreManager {
sleep(Duration::from_millis(250)).await;
}
// 保存结果
let mut runtime = self.runtime_config.lock();
let config_yaml = Some(serde_yaml::to_string(&config).unwrap_or("".into()));
*runtime = RuntimeResult {
config: Some(config),
config_yaml,
exists_keys,
chain_logs: logs,
};
Ok(())
}
}

View File

@ -43,9 +43,6 @@ impl Timer {
Config::profiles().latest().get_items().map(|items| {
items
.iter()
// .filter_map(|item| {
// item.uid.is_some() && item.updated.is_some() && item.option.is_some()
// })
.filter_map(|item| {
// mins to seconds
let interval = ((item.option.as_ref()?.update_interval?) as i64) * 60;

View File

@ -1,3 +1,9 @@
//
//! feat mod 里的函数主要用于
//! - hotkey 快捷键
//! - timer 定时器
//! - cmds 页面调用
//!
use crate::config::*;
use crate::core::*;
use crate::log_err;
@ -8,8 +14,14 @@ use serde_yaml::{Mapping, Value};
pub fn restart_clash_core() {
tauri::async_runtime::spawn(async {
match CoreManager::global().run_core().await {
Ok(_) => log_err!(handle_activate().await),
Err(err) => log::error!(target: "app", "{err}"),
Ok(_) => {
handle::Handle::refresh_clash();
handle::Handle::notice_message("set_config::ok", "ok");
}
Err(err) => {
handle::Handle::notice_message("set_config::error", format!("{err}"));
log::error!(target:"app", "{err}");
}
}
});
}
@ -157,7 +169,7 @@ pub async fn patch_clash(patch: Mapping) -> Result<()> {
|| patch.get("secret").is_some()
|| patch.get("external-controller").is_some()
{
handle_activate().await?;
CoreManager::global().run_core().await?;
}
// 更新系统代理
@ -196,10 +208,12 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> {
match {
#[cfg(target_os = "windows")]
{}
{
todo!()
}
if tun_mode.is_some() {
handle_activate().await?;
update_core_config().await?;
}
if auto_launch.is_some() {
@ -238,21 +252,6 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> {
}
}
/// 激活配置
pub async fn handle_activate() -> Result<()> {
match CoreManager::global().activate_config().await {
Ok(_) => {
handle::Handle::refresh_clash();
handle::Handle::notice_message("set_config::ok", "ok");
Ok(())
}
Err(err) => {
handle::Handle::notice_message("set_config::error", format!("{err}"));
Err(err)
}
}
}
/// 更新某个profile
/// 如果更新当前配置就激活配置
pub async fn update_profile(uid: String, option: Option<PrfOption>) -> Result<()> {
@ -286,8 +285,23 @@ pub async fn update_profile(uid: String, option: Option<PrfOption>) -> Result<()
};
if should_update {
handle_activate().await?;
update_core_config().await?;
}
Ok(())
}
/// 更新配置
async fn update_core_config() -> Result<()> {
match CoreManager::global().update_config().await {
Ok(_) => {
handle::Handle::refresh_clash();
handle::Handle::notice_message("set_config::ok", "ok");
Ok(())
}
Err(err) => {
handle::Handle::notice_message("set_config::error", format!("{err}"));
Err(err)
}
}
}

View File

@ -49,17 +49,15 @@ fn main() -> std::io::Result<()> {
cmds::patch_verge_config,
// cmds::update_hotkeys,
// profile
cmds::get_profiles,
cmds::enhance_profiles,
cmds::patch_profiles_config,
cmds::view_profile,
cmds::patch_profile,
cmds::create_profile,
cmds::import_profile,
cmds::update_profile,
cmds::delete_profile,
cmds::select_profile,
cmds::get_profiles,
cmds::enhance_profiles,
cmds::change_profile_chain,
cmds::change_profile_valid,
cmds::read_profile_file,
cmds::save_profile_file,
// service mode
@ -92,13 +90,6 @@ fn main() -> std::io::Result<()> {
.build(tauri::generate_context!())
.expect("error while running tauri application");
// let app_handle = app.app_handle();
// ctrlc::set_handler(move || {
// resolve::resolve_reset();
// app_handle.exit(0);
// })
// .expect("error while exiting.");
app.run(|app_handle, e| match e {
tauri::RunEvent::ExitRequested { api, .. } => {
api.prevent_exit();

View File

@ -1,48 +0,0 @@
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>(path: &PathBuf) -> Result<T> {
if !path.exists() {
bail!("file not found \"{}\"", path.display());
}
let yaml_str = fs::read_to_string(&path)
.context(format!("failed to read the file \"{}\"", path.display()))?;
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) -> Result<Mapping> {
let mut val: Value = read_yaml(path)?;
val.apply_merge()
.context(format!("failed to apply merge \"{}\"", path.display()))?;
Ok(val
.as_mapping()
.ok_or(anyhow!(
"failed to transform to yaml mapping \"{}\"",
path.display()
))?
.to_owned())
}
/// save the data to the file
/// can set `prefix` string to add some comments
pub fn save_yaml<T: Serialize>(path: PathBuf, data: &T, prefix: Option<&str>) -> Result<()> {
let data_str = serde_yaml::to_string(data)?;
let yaml_str = match prefix {
Some(prefix) => format!("{prefix}\n{data_str}"),
None => data_str,
};
let path_str = path.as_os_str().to_string_lossy().to_string();
fs::write(path, yaml_str.as_bytes()).context(format!("failed to save file \"{path_str}\""))
}

View File

@ -1,5 +1,5 @@
use anyhow::Result;
use std::{env::temp_dir, path::PathBuf};
use std::path::PathBuf;
use tauri::{
api::path::{home_dir, resource_dir},
Env, PackageInfo,
@ -107,14 +107,6 @@ pub fn profiles_path() -> Result<PathBuf> {
Ok(app_home_dir()?.join(PROFILE_YAML))
}
pub fn clash_runtime_yaml() -> Result<PathBuf> {
Ok(app_home_dir()?.join("clash-verge-runtime.yaml"))
}
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

View File

@ -1,8 +1,52 @@
use anyhow::Result;
use anyhow::{anyhow, bail, Context, Result};
use nanoid::nanoid;
use std::path::PathBuf;
use std::process::Command;
use std::str::FromStr;
use serde::{de::DeserializeOwned, Serialize};
use serde_yaml::{Mapping, Value};
use std::{fs, path::PathBuf, process::Command, str::FromStr};
/// read data from yaml as struct T
pub fn read_yaml<T: DeserializeOwned>(path: &PathBuf) -> Result<T> {
if !path.exists() {
bail!("file not found \"{}\"", path.display());
}
let yaml_str = fs::read_to_string(&path)
.context(format!("failed to read the file \"{}\"", path.display()))?;
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) -> Result<Mapping> {
let mut val: Value = read_yaml(path)?;
val.apply_merge()
.context(format!("failed to apply merge \"{}\"", path.display()))?;
Ok(val
.as_mapping()
.ok_or(anyhow!(
"failed to transform to yaml mapping \"{}\"",
path.display()
))?
.to_owned())
}
/// save the data to the file
/// can set `prefix` string to add some comments
pub fn save_yaml<T: Serialize>(path: &PathBuf, data: &T, prefix: Option<&str>) -> Result<()> {
let data_str = serde_yaml::to_string(data)?;
let yaml_str = match prefix {
Some(prefix) => format!("{prefix}\n\n{data_str}"),
None => data_str,
};
let path_str = path.as_os_str().to_string_lossy().to_string();
fs::write(path, yaml_str.as_bytes()).context(format!("failed to save file \"{path_str}\""))
}
const ALPHABET: [char; 62] = [
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i',
@ -68,16 +112,6 @@ macro_rules! error {
};
}
#[deprecated]
#[macro_export]
macro_rules! log_if_err {
($result: expr) => {
if let Err(err) = $result {
log::error!(target: "app", "{err}");
}
};
}
#[macro_export]
macro_rules! log_err {
($result: expr) => {

View File

@ -1,4 +1,4 @@
use crate::utils::{dirs, tmpl};
use crate::utils::dirs;
use anyhow::Result;
use chrono::Local;
use log::LevelFilter;
@ -7,7 +7,6 @@ use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Config, Logger, Root};
use log4rs::encode::pattern::PatternEncoder;
use std::fs;
use std::io::Write;
use tauri::PackageInfo;
/// initialize this instance's log file
@ -21,13 +20,20 @@ fn init_log() -> Result<()> {
let log_file = format!("{}.log", local_time);
let log_file = log_dir.join(log_file);
#[cfg(feature = "verge-dev")]
let time_format = "{d(%Y-%m-%d %H:%M:%S)} {l} - {M} {m}{n}";
#[cfg(not(feature = "verge-dev"))]
let time_format = "{d(%Y-%m-%d %H:%M:%S)} {l} - {m}{n}";
let stdout = ConsoleAppender::builder()
.encoder(Box::new(PatternEncoder::new(time_format)))
.build();
let tofile = FileAppender::builder()
.encoder(Box::new(PatternEncoder::new(time_format)))
.build(log_file)?;
let encode = Box::new(PatternEncoder::new(time_format));
let stdout = ConsoleAppender::builder().encoder(encode.clone()).build();
let tofile = FileAppender::builder().encoder(encode).build(log_file)?;
#[cfg(feature = "verge-dev")]
let level = LevelFilter::Debug;
#[cfg(not(feature = "verge-dev"))]
let level = LevelFilter::Info;
let config = Config::builder()
.appender(Appender::builder().build("stdout", Box::new(stdout)))
@ -36,9 +42,9 @@ fn init_log() -> Result<()> {
Logger::builder()
.appenders(["file", "stdout"])
.additive(false)
.build("app", LevelFilter::Info),
.build("app", level),
)
.build(Root::builder().appender("stdout").build(LevelFilter::Info))?;
.build(Root::builder().appender("stdout").build(level))?;
log4rs::init_config(config)?;
@ -58,21 +64,6 @@ pub fn init_config() -> Result<()> {
if !app_dir.exists() {
let _ = fs::create_dir_all(&app_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");
// 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| {

View File

@ -1,4 +1,3 @@
pub mod config;
pub mod dirs;
pub mod help;
pub mod init;

View File

@ -10,9 +10,10 @@ pub fn resolve_setup(app: &mut App) {
handle::Handle::global().init(app.app_handle());
init::init_resources(app.package_info());
log_err!(init::init_resources(app.package_info()));
// 启动核心
log_err!(Config::init_config());
log_err!(CoreManager::global().init());
// setup a simple http server for singleton

View File

@ -7,7 +7,7 @@ import {
getProfiles,
deleteProfile,
enhanceProfiles,
changeProfileChain,
patchProfilesConfig,
getRuntimeLogs,
} from "@/services/cmds";
import ProfileMore from "./profile-more";
@ -43,7 +43,7 @@ const EnhancedMode = (props: Props) => {
if (chain.includes(uid)) return;
const newChain = [...chain, uid];
await changeProfileChain(newChain);
await patchProfilesConfig({ chain: newChain });
mutateProfiles((conf = {}) => ({ ...conf, chain: newChain }), true);
mutateLogs();
});
@ -52,7 +52,7 @@ const EnhancedMode = (props: Props) => {
if (!chain.includes(uid)) return;
const newChain = chain.filter((i) => i !== uid);
await changeProfileChain(newChain);
await patchProfilesConfig({ chain: newChain });
mutateProfiles((conf = {}) => ({ ...conf, chain: newChain }), true);
mutateLogs();
});
@ -72,7 +72,7 @@ const EnhancedMode = (props: Props) => {
if (!chain.includes(uid)) return;
const newChain = [uid].concat(chain.filter((i) => i !== uid));
await changeProfileChain(newChain);
await patchProfilesConfig({ chain: newChain });
mutateProfiles((conf = {}) => ({ ...conf, chain: newChain }), true);
mutateLogs();
});
@ -81,7 +81,7 @@ const EnhancedMode = (props: Props) => {
if (!chain.includes(uid)) return;
const newChain = chain.filter((i) => i !== uid).concat([uid]);
await changeProfileChain(newChain);
await patchProfilesConfig({ chain: newChain });
mutateProfiles((conf = {}) => ({ ...conf, chain: newChain }), true);
mutateLogs();
});

View File

@ -15,9 +15,9 @@ import {
} from "@mui/material";
import { InfoRounded } from "@mui/icons-material";
import {
changeProfileValid,
getProfiles,
getRuntimeExists,
patchProfilesConfig,
} from "@/services/cmds";
import { ModalHandler } from "@/hooks/use-modal-handler";
import {
@ -91,7 +91,7 @@ const ClashFieldViewer = ({ handler }: Props) => {
if (curSet.size === oldSet.size && curSet.size === joinSet.size) return;
try {
await changeProfileValid([...curSet]);
await patchProfilesConfig({ valid: [...curSet] });
mutateProfile();
// Notice.success("Refresh clash config", 1000);
} catch (err: any) {

View File

@ -7,7 +7,7 @@ import { useTranslation } from "react-i18next";
import {
getProfiles,
patchProfile,
selectProfile,
patchProfilesConfig,
importProfile,
} from "@/services/cmds";
import { getProxies, updateProxy } from "@/services/api";
@ -113,7 +113,7 @@ const ProfilePage = () => {
if (!newProfiles.current && remoteItem) {
const current = remoteItem.uid;
selectProfile(current);
patchProfilesConfig({ current });
mutate("getProfiles", { ...newProfiles, current }, true);
mutate("getRuntimeLogs");
}
@ -125,13 +125,13 @@ const ProfilePage = () => {
}
};
const onSelect = useLockFn(async (uid: string, force: boolean) => {
if (!force && uid === profiles.current) return;
const onSelect = useLockFn(async (current: string, force: boolean) => {
if (!force && current === profiles.current) return;
try {
await selectProfile(uid);
setCurrentProfile(uid);
mutate("getProfiles", { ...profiles, current: uid }, true);
await patchProfilesConfig({ current });
setCurrentProfile(current);
mutate("getProfiles", { ...profiles, current: current }, true);
mutate("getRuntimeLogs");
// if (force) Notice.success("Refresh clash config", 1000);
} catch (err: any) {

View File

@ -32,6 +32,10 @@ export async function enhanceProfiles() {
return invoke<void>("enhance_profiles");
}
export async function patchProfilesConfig(profiles: CmdType.ProfilesConfig) {
return invoke<void>("patch_profiles_config");
}
export async function createProfile(
item: Partial<CmdType.ProfileItem>,
fileData?: string | null
@ -76,18 +80,6 @@ export async function patchProfile(
return invoke<void>("patch_profile", { index, profile });
}
export async function selectProfile(index: string) {
return invoke<void>("select_profile", { index });
}
export async function changeProfileChain(chain?: string[]) {
return invoke<void>("change_profile_chain", { chain });
}
export async function changeProfileValid(valid?: string[]) {
return invoke<void>("change_profile_valid", { valid });
}
export async function getClashInfo() {
return invoke<CmdType.ClashInfo | null>("get_clash_info");
}
@ -136,10 +128,6 @@ export async function restartSidecar() {
return invoke<void>("restart_sidecar");
}
// export async function killSidecar() {
// return invoke<any>("kill_sidecar");
// }
export async function openAppDir() {
return invoke<void>("open_app_dir").catch((err) =>
Notice.error(err?.message || err.toString(), 1500)