libsubconverter/utils/
memory_cache.rs1use crate::utils::system::safe_system_time;
2use once_cell::sync::Lazy;
3use std::collections::HashMap;
4use std::sync::{Arc, Mutex};
5use std::time::{Duration, SystemTime};
6
7static MEMORY_CACHE: Lazy<Arc<Mutex<MemoryCache>>> =
9 Lazy::new(|| Arc::new(Mutex::new(MemoryCache::new())));
10
11#[derive(Clone)]
13struct CachedItem {
14 content: String,
16 timestamp: SystemTime,
18}
19
20struct MemoryCache {
22 cache: HashMap<String, CachedItem>,
24}
25
26impl MemoryCache {
27 fn new() -> Self {
29 Self {
30 cache: HashMap::new(),
31 }
32 }
33}
34
35pub fn store(key: &str, content: &str) -> Result<(), String> {
45 let mut cache = match MEMORY_CACHE.lock() {
46 Ok(cache) => cache,
47 Err(e) => return Err(format!("Failed to lock memory cache: {}", e)),
48 };
49
50 cache.cache.insert(
52 key.to_string(),
53 CachedItem {
54 content: content.to_string(),
55 timestamp: safe_system_time(),
56 },
57 );
58
59 Ok(())
60}
61
62pub fn get(key: &str) -> Option<String> {
71 let cache = match MEMORY_CACHE.lock() {
72 Ok(cache) => cache,
73 Err(_) => return None,
74 };
75
76 cache.cache.get(key).map(|item| item.content.clone())
77}
78
79pub fn exists(key: &str) -> bool {
88 let cache = match MEMORY_CACHE.lock() {
89 Ok(cache) => cache,
90 Err(_) => return false,
91 };
92
93 cache.cache.contains_key(key)
94}
95
96pub fn is_valid(key: &str, max_age: u32) -> bool {
106 let cache = match MEMORY_CACHE.lock() {
107 Ok(cache) => cache,
108 Err(_) => return false,
109 };
110
111 if let Some(item) = cache.cache.get(key) {
112 let now = safe_system_time();
113 if let Ok(elapsed) = now.duration_since(item.timestamp) {
114 return elapsed.as_secs() < u64::from(max_age);
115 }
116 }
117
118 false
119}
120
121pub fn get_if_valid(key: &str, max_age: u32) -> Option<String> {
131 let cache = match MEMORY_CACHE.lock() {
132 Ok(cache) => cache,
133 Err(_) => return None,
134 };
135
136 if let Some(item) = cache.cache.get(key) {
137 let now = safe_system_time();
138 if let Ok(elapsed) = now.duration_since(item.timestamp) {
139 if elapsed.as_secs() < u64::from(max_age) {
140 return Some(item.content.clone());
141 }
142 }
143 }
144
145 None
146}
147
148pub fn remove(key: &str) {
153 if let Ok(mut cache) = MEMORY_CACHE.lock() {
154 cache.cache.remove(key);
155 }
156}
157
158pub fn clear() {
160 if let Ok(mut cache) = MEMORY_CACHE.lock() {
161 cache.cache.clear();
162 }
163}
164
165pub fn size() -> usize {
167 if let Ok(cache) = MEMORY_CACHE.lock() {
168 return cache.cache.len();
169 }
170 0
171}
172
173pub fn clean_expired(max_age: u32) {
178 if let Ok(mut cache) = MEMORY_CACHE.lock() {
179 let now = safe_system_time();
180 let max_duration = Duration::from_secs(u64::from(max_age));
181
182 cache.cache.retain(|_, item| {
184 if let Ok(elapsed) = now.duration_since(item.timestamp) {
185 elapsed <= max_duration
186 } else {
187 true
189 }
190 });
191 }
192}