Files
clash-proxy/src-tauri/src/core/timer.rs

216 lines
6.7 KiB
Rust
Raw Normal View History

use crate::{config::Config, core::CoreManager, feat};
2022-09-11 20:58:55 +08:00
use anyhow::{Context, Result};
2022-04-20 20:37:16 +08:00
use delay_timer::prelude::{DelayTimer, DelayTimerBuilder, TaskBuilder};
2022-11-14 01:26:33 +08:00
use once_cell::sync::OnceCell;
use parking_lot::Mutex;
use std::{collections::HashMap, sync::Arc};
2022-04-19 01:41:20 +08:00
2022-04-20 20:37:16 +08:00
type TaskID = u64;
2022-04-19 01:41:20 +08:00
pub struct Timer {
2022-11-12 11:37:23 +08:00
/// cron manager
2022-11-14 01:26:33 +08:00
delay_timer: Arc<Mutex<DelayTimer>>,
2022-04-19 01:41:20 +08:00
2022-11-12 11:37:23 +08:00
/// save the current state
2022-11-14 01:26:33 +08:00
timer_map: Arc<Mutex<HashMap<String, (TaskID, u64)>>>,
2022-04-20 20:37:16 +08:00
2022-11-12 11:37:23 +08:00
/// increment id
2022-11-14 01:26:33 +08:00
timer_count: Arc<Mutex<TaskID>>,
/// 标记定时器是否已经初始化
initialized: Arc<Mutex<bool>>,
2022-04-19 01:41:20 +08:00
}
impl Timer {
2022-11-14 01:26:33 +08:00
pub fn global() -> &'static Timer {
static TIMER: OnceCell<Timer> = OnceCell::new();
TIMER.get_or_init(|| Timer {
delay_timer: Arc::new(Mutex::new(DelayTimerBuilder::default().build())),
timer_map: Arc::new(Mutex::new(HashMap::new())),
timer_count: Arc::new(Mutex::new(1)),
initialized: Arc::new(Mutex::new(false)),
2022-11-14 01:26:33 +08:00
})
}
/// restore timer
pub fn init(&self) -> Result<()> {
let mut initialized = self.initialized.lock();
if *initialized {
log::info!(target: "app", "Timer already initialized, skipping...");
return Ok(());
}
log::info!(target: "app", "Initializing timer...");
2022-11-14 01:26:33 +08:00
self.refresh()?;
let cur_timestamp = chrono::Local::now().timestamp();
let timer_map = self.timer_map.lock();
let delay_timer = self.delay_timer.lock();
2024-01-10 17:36:35 +08:00
if let Some(items) = Config::profiles().latest().get_items() {
2022-11-14 01:26:33 +08:00
items
.iter()
.filter_map(|item| {
let interval = ((item.option.as_ref()?.update_interval?) as i64) * 60;
let updated = item.updated? as i64;
if interval > 0 && cur_timestamp - updated >= interval {
Some(item)
} else {
None
}
})
.for_each(|item| {
if let Some(uid) = item.uid.as_ref() {
if let Some((task_id, _)) = timer_map.get(uid) {
log::info!(target: "app", "Advancing task for uid: {}", uid);
2022-11-14 01:26:33 +08:00
crate::log_err!(delay_timer.advance_task(*task_id));
}
}
});
2024-01-10 17:36:35 +08:00
}
2022-11-14 01:26:33 +08:00
*initialized = true;
log::info!(target: "app", "Timer initialization completed");
2022-11-14 01:26:33 +08:00
Ok(())
2022-04-20 20:37:16 +08:00
}
2022-11-12 11:37:23 +08:00
/// Correctly update all cron tasks
2022-11-14 01:26:33 +08:00
pub fn refresh(&self) -> Result<()> {
2022-11-12 11:37:23 +08:00
let diff_map = self.gen_diff();
2022-11-14 01:26:33 +08:00
let mut timer_map = self.timer_map.lock();
2022-11-14 01:45:58 +08:00
let mut delay_timer = self.delay_timer.lock();
2022-11-14 01:26:33 +08:00
2022-11-12 11:37:23 +08:00
for (uid, diff) in diff_map.into_iter() {
match diff {
DiffFlag::Del(tid) => {
2022-11-14 01:26:33 +08:00
let _ = timer_map.remove(&uid);
crate::log_err!(delay_timer.remove_task(tid));
2022-11-12 11:37:23 +08:00
}
DiffFlag::Add(tid, val) => {
2022-11-14 01:26:33 +08:00
let _ = timer_map.insert(uid.clone(), (tid, val));
2022-11-14 01:45:58 +08:00
crate::log_err!(self.add_task(&mut delay_timer, uid, tid, val));
2022-11-12 11:37:23 +08:00
}
DiffFlag::Mod(tid, val) => {
2022-11-14 01:26:33 +08:00
let _ = timer_map.insert(uid.clone(), (tid, val));
crate::log_err!(delay_timer.remove_task(tid));
2022-11-14 01:45:58 +08:00
crate::log_err!(self.add_task(&mut delay_timer, uid, tid, val));
2022-11-12 11:37:23 +08:00
}
}
2022-08-23 15:19:04 +08:00
}
2022-11-12 11:37:23 +08:00
Ok(())
}
2022-08-21 13:33:12 +08:00
2022-11-12 11:37:23 +08:00
/// generate a uid -> update_interval map
fn gen_map(&self) -> HashMap<String, u64> {
let mut new_map = HashMap::new();
2022-04-20 20:37:16 +08:00
2022-11-17 17:07:13 +08:00
if let Some(items) = Config::profiles().latest().get_items() {
2022-11-12 11:37:23 +08:00
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);
}
}
}
2022-04-20 20:37:16 +08:00
}
2022-11-12 11:37:23 +08:00
new_map
}
2022-04-20 20:37:16 +08:00
2022-11-12 11:37:23 +08:00
/// generate the diff map for refresh
2022-11-14 01:26:33 +08:00
fn gen_diff(&self) -> HashMap<String, DiffFlag> {
2022-11-12 11:37:23 +08:00
let mut diff_map = HashMap::new();
2022-04-20 20:37:16 +08:00
2022-11-14 01:26:33 +08:00
let timer_map = self.timer_map.lock();
2022-11-12 11:37:23 +08:00
let new_map = self.gen_map();
2022-11-14 01:26:33 +08:00
let cur_map = &timer_map;
2022-04-20 20:37:16 +08:00
2022-11-12 11:37:23 +08:00
cur_map.iter().for_each(|(uid, (tid, val))| {
let new_val = new_map.get(uid).unwrap_or(&0);
2022-04-20 20:37:16 +08:00
2022-11-12 11:37:23 +08:00
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));
}
});
2022-04-20 20:37:16 +08:00
2022-11-14 01:26:33 +08:00
let mut count = self.timer_count.lock();
2022-04-20 20:37:16 +08:00
2022-11-12 11:37:23 +08:00
new_map.iter().for_each(|(uid, val)| {
if cur_map.get(uid).is_none() {
2022-11-14 01:26:33 +08:00
diff_map.insert(uid.clone(), DiffFlag::Add(*count, *val));
2022-04-20 20:37:16 +08:00
2022-11-14 01:26:33 +08:00
*count += 1;
2022-11-12 11:37:23 +08:00
}
});
2022-04-20 20:37:16 +08:00
2022-11-12 11:37:23 +08:00
diff_map
}
2022-04-20 20:37:16 +08:00
2022-11-12 11:37:23 +08:00
/// add a cron task
2022-11-14 01:45:58 +08:00
fn add_task(
&self,
delay_timer: &mut DelayTimer,
uid: String,
tid: TaskID,
minutes: u64,
) -> Result<()> {
log::info!(target: "app", "Adding new task: uid={}, interval={} minutes", uid, minutes);
2022-11-12 11:37:23 +08:00
let task = TaskBuilder::default()
.set_task_id(tid)
.set_maximum_parallel_runnable_num(1)
.set_frequency_repeated_by_minutes(minutes)
.spawn_async_routine(move || {
let uid = uid.clone();
async move {
Self::async_task(uid).await;
}
})
2022-11-12 11:37:23 +08:00
.context("failed to create timer task")?;
2022-04-20 20:37:16 +08:00
2022-11-14 01:45:58 +08:00
delay_timer
2022-11-12 11:37:23 +08:00
.add_task(task)
.context("failed to add timer task")?;
2022-04-20 20:37:16 +08:00
log::info!(target: "app", "Task added successfully: {}", tid);
2022-11-12 11:37:23 +08:00
Ok(())
}
2022-04-20 20:37:16 +08:00
2022-11-12 11:37:23 +08:00
/// the task runner
2022-11-14 01:26:33 +08:00
async fn async_task(uid: String) {
log::info!(target: "app", "Running timer task `{}`", uid);
match feat::update_profile(uid.clone(), None).await {
Ok(_) => match CoreManager::global().update_config().await {
Ok(_) => {
log::info!(target: "app", "Timer task completed successfully for uid: {}", uid);
}
Err(e) => {
log::error!(target: "app", "Timer task refresh error for uid {}: {}", uid, e);
}
},
Err(e) => {
log::error!(target: "app", "Timer task update error for uid {}: {}", uid, e);
}
}
2022-11-12 11:37:23 +08:00
}
2022-04-20 20:37:16 +08:00
}
2022-04-21 14:26:41 +08:00
#[derive(Debug)]
2022-04-20 20:37:16 +08:00
enum DiffFlag {
2022-11-12 11:37:23 +08:00
Del(TaskID),
Add(TaskID, u64),
Mod(TaskID, u64),
2022-04-19 01:41:20 +08:00
}