feat: supports cron update profiles
This commit is contained in:
parent
5f7a1fa5cd
commit
4de944b41e
@ -58,38 +58,7 @@ pub async fn update_profile(
|
|||||||
option: Option<PrfOption>,
|
option: Option<PrfOption>,
|
||||||
core: State<'_, Core>,
|
core: State<'_, Core>,
|
||||||
) -> CmdResult {
|
) -> CmdResult {
|
||||||
let (url, opt) = {
|
wrap_err!(Core::update_profile_item(core.inner().clone(), index, option).await)
|
||||||
// must release the lock here
|
|
||||||
let profiles = core.profiles.lock();
|
|
||||||
let item = wrap_err!(profiles.get_item(&index))?;
|
|
||||||
|
|
||||||
// check the profile type
|
|
||||||
if let Some(typ) = item.itype.as_ref() {
|
|
||||||
if *typ != "remote" {
|
|
||||||
ret_err!(format!("could not update the `{typ}` profile"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if item.url.is_none() {
|
|
||||||
ret_err!("failed to get the item url");
|
|
||||||
}
|
|
||||||
|
|
||||||
(item.url.clone().unwrap(), item.option.clone())
|
|
||||||
};
|
|
||||||
|
|
||||||
let fetch_opt = PrfOption::merge(opt, option);
|
|
||||||
let item = wrap_err!(PrfItem::from_url(&url, None, None, fetch_opt).await)?;
|
|
||||||
|
|
||||||
let mut profiles = core.profiles.lock();
|
|
||||||
wrap_err!(profiles.update_item(index.clone(), item))?;
|
|
||||||
|
|
||||||
// reactivate the profile
|
|
||||||
if Some(index) == profiles.get_current() {
|
|
||||||
drop(profiles);
|
|
||||||
log_if_err!(core.activate_enhanced(false));
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// change the current profile
|
/// change the current profile
|
||||||
@ -213,9 +182,7 @@ pub fn patch_clash_config(payload: Mapping, core: State<'_, Core>) -> CmdResult
|
|||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub fn get_verge_config(core: State<'_, Core>) -> CmdResult<Verge> {
|
pub fn get_verge_config(core: State<'_, Core>) -> CmdResult<Verge> {
|
||||||
let verge = core.verge.lock();
|
let verge = core.verge.lock();
|
||||||
let config = verge.clone();
|
Ok(verge.clone())
|
||||||
|
|
||||||
Ok(config)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// patch the verge config
|
/// patch the verge config
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use self::notice::Notice;
|
use self::notice::Notice;
|
||||||
use self::service::Service;
|
use self::service::Service;
|
||||||
use self::sysopt::Sysopt;
|
use self::sysopt::Sysopt;
|
||||||
|
use self::timer::Timer;
|
||||||
use crate::core::enhance::PrfEnhancedResult;
|
use crate::core::enhance::PrfEnhancedResult;
|
||||||
use crate::log_if_err;
|
use crate::log_if_err;
|
||||||
use crate::utils::{dirs, help};
|
use crate::utils::{dirs, help};
|
||||||
@ -39,6 +40,8 @@ pub struct Core {
|
|||||||
|
|
||||||
pub sysopt: Arc<Mutex<Sysopt>>,
|
pub sysopt: Arc<Mutex<Sysopt>>,
|
||||||
|
|
||||||
|
pub timer: Arc<Mutex<Timer>>,
|
||||||
|
|
||||||
pub window: Arc<Mutex<Option<Window>>>,
|
pub window: Arc<Mutex<Option<Window>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -55,6 +58,7 @@ impl Core {
|
|||||||
profiles: Arc::new(Mutex::new(profiles)),
|
profiles: Arc::new(Mutex::new(profiles)),
|
||||||
service: Arc::new(Mutex::new(service)),
|
service: Arc::new(Mutex::new(service)),
|
||||||
sysopt: Arc::new(Mutex::new(Sysopt::new())),
|
sysopt: Arc::new(Mutex::new(Sysopt::new())),
|
||||||
|
timer: Arc::new(Mutex::new(Timer::new())),
|
||||||
window: Arc::new(Mutex::new(None)),
|
window: Arc::new(Mutex::new(None)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -98,6 +102,11 @@ impl Core {
|
|||||||
sleep(Duration::from_secs(2)).await;
|
sleep(Duration::from_secs(2)).await;
|
||||||
log_if_err!(core.activate_enhanced(true));
|
log_if_err!(core.activate_enhanced(true));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// timer initialize
|
||||||
|
let mut timer = self.timer.lock();
|
||||||
|
timer.set_core(self.clone());
|
||||||
|
log_if_err!(timer.refresh());
|
||||||
}
|
}
|
||||||
|
|
||||||
/// save the window instance
|
/// save the window instance
|
||||||
@ -324,3 +333,51 @@ impl Core {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Core {
|
||||||
|
/// Static function
|
||||||
|
/// update profile item
|
||||||
|
pub async fn update_profile_item(
|
||||||
|
core: Core,
|
||||||
|
uid: String,
|
||||||
|
option: Option<PrfOption>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let (url, opt) = {
|
||||||
|
let profiles = core.profiles.lock();
|
||||||
|
let item = profiles.get_item(&uid)?;
|
||||||
|
|
||||||
|
if let Some(typ) = item.itype.as_ref() {
|
||||||
|
// maybe only valid for `local` profile
|
||||||
|
if *typ != "remote" {
|
||||||
|
// reactivate the config
|
||||||
|
if Some(uid) == profiles.get_current() {
|
||||||
|
drop(profiles);
|
||||||
|
return core.activate_enhanced(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if item.url.is_none() {
|
||||||
|
bail!("failed to get the profile item url");
|
||||||
|
}
|
||||||
|
|
||||||
|
(item.url.clone().unwrap(), item.option.clone())
|
||||||
|
};
|
||||||
|
|
||||||
|
let merged_opt = PrfOption::merge(opt, option);
|
||||||
|
let item = PrfItem::from_url(&url, None, None, merged_opt).await?;
|
||||||
|
|
||||||
|
let mut profiles = core.profiles.lock();
|
||||||
|
profiles.update_item(uid.clone(), item)?;
|
||||||
|
|
||||||
|
// reactivate the profile
|
||||||
|
if Some(uid) == profiles.get_current() {
|
||||||
|
drop(profiles);
|
||||||
|
core.activate_enhanced(false)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -102,17 +102,6 @@ impl PrfOption {
|
|||||||
|
|
||||||
return one;
|
return one;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn diff_update_interval(one: Option<&Self>, other: Option<&Self>) -> bool {
|
|
||||||
if one.is_some() && other.is_some() {
|
|
||||||
let one = one.unwrap();
|
|
||||||
let other = other.unwrap();
|
|
||||||
|
|
||||||
return one.update_interval == other.update_interval;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for PrfItem {
|
impl Default for PrfItem {
|
||||||
|
@ -100,6 +100,11 @@ impl Profiles {
|
|||||||
self.valid = valid;
|
self.valid = valid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// get items ref
|
||||||
|
pub fn get_items(&self) -> Option<&Vec<PrfItem>> {
|
||||||
|
self.items.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
/// find the item by the uid
|
/// find the item by the uid
|
||||||
pub fn get_item(&self, uid: &String) -> Result<&PrfItem> {
|
pub fn get_item(&self, uid: &String) -> Result<&PrfItem> {
|
||||||
if self.items.is_some() {
|
if self.items.is_some() {
|
||||||
|
@ -1,12 +1,19 @@
|
|||||||
use delay_timer::prelude::{DelayTimer, DelayTimerBuilder, Task, TaskBuilder};
|
use super::Core;
|
||||||
|
use crate::log_if_err;
|
||||||
|
use anyhow::{bail, Context, Result};
|
||||||
|
use delay_timer::prelude::{DelayTimer, DelayTimerBuilder, TaskBuilder};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
|
type TaskID = u64;
|
||||||
|
|
||||||
pub struct Timer {
|
pub struct Timer {
|
||||||
delay_timer: DelayTimer,
|
delay_timer: DelayTimer,
|
||||||
|
|
||||||
timer_map: HashMap<String, u64>,
|
timer_map: HashMap<String, (TaskID, u64)>,
|
||||||
|
|
||||||
timer_count: u64,
|
timer_count: TaskID,
|
||||||
|
|
||||||
|
core: Option<Core>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Timer {
|
impl Timer {
|
||||||
@ -15,6 +22,122 @@ impl Timer {
|
|||||||
delay_timer: DelayTimerBuilder::default().build(),
|
delay_timer: DelayTimerBuilder::default().build(),
|
||||||
timer_map: HashMap::new(),
|
timer_map: HashMap::new(),
|
||||||
timer_count: 1,
|
timer_count: 1,
|
||||||
|
core: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_core(&mut self, core: Core) {
|
||||||
|
self.core = Some(core);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Correctly update all cron tasks
|
||||||
|
pub fn refresh(&mut self) -> Result<()> {
|
||||||
|
if self.core.is_none() {
|
||||||
|
bail!("unhandle error for core is none");
|
||||||
|
}
|
||||||
|
|
||||||
|
let diff_map = self.gen_diff();
|
||||||
|
|
||||||
|
for (uid, diff) in diff_map.into_iter() {
|
||||||
|
match diff {
|
||||||
|
DiffFlag::Del(tid) => {
|
||||||
|
log_if_err!(self.delay_timer.remove_task(tid));
|
||||||
|
}
|
||||||
|
DiffFlag::Add(tid, val) => {
|
||||||
|
log_if_err!(self.add_task(uid, tid, val));
|
||||||
|
}
|
||||||
|
DiffFlag::Mod(tid, val) => {
|
||||||
|
log_if_err!(self.delay_timer.remove_task(tid));
|
||||||
|
log_if_err!(self.add_task(uid, tid, val));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// generate a uid -> update_interval map
|
||||||
|
fn gen_map(&self) -> HashMap<String, u64> {
|
||||||
|
let profiles = self.core.as_ref().unwrap().profiles.lock();
|
||||||
|
|
||||||
|
let mut new_map = HashMap::new();
|
||||||
|
|
||||||
|
if let Some(items) = profiles.get_items() {
|
||||||
|
for item in items.iter() {
|
||||||
|
if item.option.is_some() {
|
||||||
|
let option = item.option.as_ref().unwrap();
|
||||||
|
let interval = option.update_interval.unwrap_or(0);
|
||||||
|
|
||||||
|
if interval > 0 {
|
||||||
|
new_map.insert(item.uid.clone().unwrap(), interval);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
new_map
|
||||||
|
}
|
||||||
|
|
||||||
|
/// generate the diff map for refresh
|
||||||
|
fn gen_diff(&mut self) -> HashMap<String, DiffFlag> {
|
||||||
|
let mut diff_map = HashMap::new();
|
||||||
|
|
||||||
|
let new_map = self.gen_map();
|
||||||
|
let cur_map = &self.timer_map;
|
||||||
|
|
||||||
|
cur_map.iter().for_each(|(uid, (tid, val))| {
|
||||||
|
let new_val = new_map.get(uid).unwrap_or(&0);
|
||||||
|
|
||||||
|
if *new_val == 0 {
|
||||||
|
diff_map.insert(uid.clone(), DiffFlag::Del(*tid));
|
||||||
|
} else if new_val != val {
|
||||||
|
diff_map.insert(uid.clone(), DiffFlag::Mod(*tid, *new_val));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut count = self.timer_count;
|
||||||
|
|
||||||
|
new_map.iter().for_each(|(uid, val)| {
|
||||||
|
if cur_map.get(uid).is_none() {
|
||||||
|
diff_map.insert(uid.clone(), DiffFlag::Add(count, *val));
|
||||||
|
|
||||||
|
count += 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
self.timer_count = count;
|
||||||
|
|
||||||
|
diff_map
|
||||||
|
}
|
||||||
|
|
||||||
|
/// add a cron task
|
||||||
|
fn add_task(&self, uid: String, tid: TaskID, minutes: u64) -> Result<()> {
|
||||||
|
let core = self.core.clone().unwrap();
|
||||||
|
|
||||||
|
let task = TaskBuilder::default()
|
||||||
|
.set_task_id(tid)
|
||||||
|
.set_frequency_repeated_by_minutes(minutes)
|
||||||
|
// .set_frequency_repeated_by_seconds(minutes) // for test
|
||||||
|
.spawn_async_routine(move || Self::async_task(core.clone(), uid.clone()))
|
||||||
|
.context("failed to create timer task")?;
|
||||||
|
|
||||||
|
self
|
||||||
|
.delay_timer
|
||||||
|
.add_task(task)
|
||||||
|
.context("failed to add timer task")?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// the task runner
|
||||||
|
async fn async_task(core: Core, uid: String) {
|
||||||
|
log::info!("running timer task `{uid}`");
|
||||||
|
log_if_err!(Core::update_profile_item(core, uid, None).await);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum DiffFlag {
|
||||||
|
Del(TaskID),
|
||||||
|
Add(TaskID, u64),
|
||||||
|
Mod(TaskID, u64),
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user