Files
clash-verge-rev-lite/src-tauri/src/cache/mod.rs
Tunglies c207516b47 refactor: clash-verge-service management (#4674)
* refactor: clash-verge-service management

* fix: correct service state checks in ProxyControlSwitches component
refactor: improve logging in service state update functions

* fix: add missing async handler for Windows and adjust logging import for macOS

* fix: streamline logging imports and add missing async handler for Windows

* refactor: remove unused useServiceStateSync hook and update imports in _layout

* refactor: remove unused useServiceStateSync import and clean up code in ProxyControlSwitches and _layout

* refactor: simplify service status checks and reduce wait time in useServiceInstaller hook

* refactor: remove unnecessary logging statements in service checks and IPC connection

* refactor: extract SwitchRow component for better code organization and readability

* refactor: enhance service state management and update related mutations in layout

* refactor: streamline core stopping logic and improve IPC connection logging

* refactor: consolidate service uninstallation logic and improve error handling

* fix: simplify conditional statements in CoreManager and service functions

* feat: add backoff dependency and implement retry strategy for IPC requests

* refactor: remove redundant Windows conditional and improve error handling in IPC tests

* test: improve error handling in IPC tests for message signing and verification

* fix: adjust IPC backoff retry parameters

* refactor: Remove service state tracking and related logic from service management

* feat: Enhance service status handling with logging and running mode updates

* fix: Improve service status handling with enhanced error logging

* fix: Ensure proper handling of service operations with error propagation

* refactor: Simplify service operation execution and enhance service status handling

* fix: Improve error message formatting in service operation execution and simplify service status retrieval

* refactor: Replace Cache with CacheProxy in multiple modules and update CacheEntry to be generic

* fix: Remove unnecessary success message from config validation

* refactor: Comment out logging statements in service version check and IPC request handling
2025-09-17 22:59:02 +08:00

112 lines
3.5 KiB
Rust

use crate::singleton;
use anyhow::Result;
use dashmap::DashMap;
use serde_json::Value;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tokio::sync::OnceCell;
pub const SHORT_TERM_TTL: Duration = Duration::from_millis(4_250);
pub struct CacheEntry<T> {
pub value: Arc<T>,
pub expires_at: Instant,
}
pub struct Cache<T> {
pub map: DashMap<String, Arc<OnceCell<Box<CacheEntry<T>>>>>,
}
impl<T> Cache<T> {
fn new() -> Self {
Cache {
map: DashMap::new(),
}
}
pub fn make_key(prefix: &str, id: &str) -> String {
format!("{prefix}:{id}")
}
pub async fn get_or_fetch<F, Fut>(&self, key: String, ttl: Duration, fetch_fn: F) -> Arc<T>
where
F: Fn() -> Fut + Send + Sync + 'static,
Fut: std::future::Future<Output = T> + Send + 'static,
T: Send + Sync + 'static,
{
loop {
let now = Instant::now();
let key_cloned = key.clone();
// Get or create the cell
let cell = self
.map
.entry(key_cloned.clone())
.or_insert_with(|| Arc::new(OnceCell::new()))
.clone();
// Check if we have a valid cached entry
if let Some(entry) = cell.get() {
if entry.expires_at > now {
return Arc::clone(&entry.value);
}
// Entry is expired, remove it
self.map
.remove_if(&key_cloned, |_, v| Arc::ptr_eq(v, &cell));
continue; // Retry with fresh cell
}
// Try to set a new value
let value = fetch_fn().await;
let entry = Box::new(CacheEntry {
value: Arc::new(value),
expires_at: Instant::now() + ttl,
});
match cell.set(entry) {
Ok(_) => {
// Successfully set the value, it must exist now
if let Some(set_entry) = cell.get() {
return Arc::clone(&set_entry.value);
}
}
Err(_) => {
if let Some(existing_entry) = cell.get() {
if existing_entry.expires_at > Instant::now() {
return Arc::clone(&existing_entry.value);
}
self.map
.remove_if(&key_cloned, |_, v| Arc::ptr_eq(v, &cell));
}
}
}
}
}
// pub fn clean_key(&self, key: &str) {
// self.map.remove(key);
// }
// TODO
pub fn clean_default_keys(&self) {
// logging!(info, Type::Cache, "Cleaning proxies keys");
// let proxies_key = Self::make_key("proxies", "default");
// self.map.remove(&proxies_key);
// logging!(info, Type::Cache, "Cleaning providers keys");
// let providers_key = Self::make_key("providers", "default");
// self.map.remove(&providers_key);
// !The frontend goes crash if we clean the clash_config cache
// logging!(info, Type::Cache, "Cleaning clash config keys");
// let clash_config_key = Self::make_key("clash_config", "default");
// self.map.remove(&clash_config_key);
}
}
pub type CacheService = Cache<Result<String>>;
pub type CacheProxy = Cache<Value>;
singleton!(Cache<Value>, PROXY_INSTANCE);
singleton!(Cache<Result<String>>, SERVICE_INSTANCE);