1use std::time::{Duration, Instant};
4
5pub trait Cache<K, V>: Send + Sync {
7 fn get(&self, key: &K) -> Option<V>;
9
10 fn put(&self, key: K, value: V, ttl_secs: u64);
12
13 fn remove(&self, key: &K) -> Option<V>;
15
16 fn clear(&self);
18}
19
20#[derive(Clone)]
22pub struct NoOpCache;
23
24impl<K, V> Cache<K, V> for NoOpCache {
25 fn get(&self, _key: &K) -> Option<V> {
26 None
27 }
28
29 fn put(&self, _key: K, _value: V, _ttl_secs: u64) {}
30
31 fn remove(&self, _key: &K) -> Option<V> {
32 None
33 }
34
35 fn clear(&self) {}
36}
37
38#[derive(Clone)]
40pub struct MemoryCache;
41
42impl<K, V> Cache<K, V> for MemoryCache {
43 fn get(&self, _key: &K) -> Option<V> {
44 None
47 }
48
49 fn put(&self, _key: K, _value: V, _ttl_secs: u64) {
50 }
52
53 fn remove(&self, _key: &K) -> Option<V> {
54 None
55 }
56
57 fn clear(&self) {}
58}
59
60#[cfg(feature = "lru")]
62pub struct LruCacheImpl<K: std::hash::Hash + Eq + Clone, V: Clone> {
63 inner: std::sync::Mutex<LruCacheInner<K, V>>,
64}
65
66#[cfg(feature = "lru")]
67struct LruCacheInner<K: std::hash::Hash + Eq + Clone, V: Clone> {
68 cache: lru::LruCache<K, (V, Instant)>,
69}
70
71#[cfg(feature = "lru")]
72impl<K: std::hash::Hash + Eq + Clone, V: Clone> LruCacheImpl<K, V> {
73 pub fn new(capacity: usize) -> Self {
75 Self {
76 inner: std::sync::Mutex::new(LruCacheInner {
77 cache: lru::LruCache::new(capacity.try_into().unwrap()),
78 }),
79 }
80 }
81}
82
83#[cfg(feature = "lru")]
84impl<K: std::hash::Hash + Eq + Clone + Send + Sync + std::fmt::Display, V: Clone + Send + Sync>
85 Cache<K, V> for LruCacheImpl<K, V>
86{
87 fn get(&self, key: &K) -> Option<V> {
88 let mut inner = self.inner.lock().unwrap();
89 let result = if let Some((value, expires_at)) = inner.cache.get(key) {
90 if Instant::now() < *expires_at {
91 Some(value.clone())
92 } else {
93 inner.cache.pop(key);
94 None
95 }
96 } else {
97 None
98 };
99
100 tracing::debug!(
101 target: "xjp_oidc::cache",
102 cache_key = %key,
103 cache_hit = result.is_some(),
104 cache_type = "lru",
105 "缓存查询"
106 );
107
108 result
109 }
110
111 fn put(&self, key: K, value: V, ttl_secs: u64) {
112 let expires_at = Instant::now() + Duration::from_secs(ttl_secs);
113 let mut inner = self.inner.lock().unwrap();
114 inner.cache.put(key, (value, expires_at));
115 }
116
117 fn remove(&self, key: &K) -> Option<V> {
118 let mut inner = self.inner.lock().unwrap();
119 inner.cache.pop(key).map(|(v, _)| v)
120 }
121
122 fn clear(&self) {
123 let mut inner = self.inner.lock().unwrap();
124 inner.cache.clear();
125 }
126}
127
128#[cfg(all(not(target_arch = "wasm32"), feature = "moka"))]
130#[derive(Clone)]
131pub struct MokaCacheImpl<K: std::hash::Hash + Eq + Clone + Send + Sync, V: Clone + Send + Sync> {
132 cache: moka::future::Cache<K, (V, Option<std::time::Instant>)>,
133}
134
135#[cfg(all(not(target_arch = "wasm32"), feature = "moka"))]
136impl<K: std::hash::Hash + Eq + Clone + Send + Sync + 'static, V: Clone + Send + Sync + 'static>
137 MokaCacheImpl<K, V>
138{
139 pub fn new(capacity: u64) -> Self {
141 let cache = moka::future::Cache::builder().max_capacity(capacity).build();
142 Self { cache }
143 }
144
145 pub fn with_config(
147 capacity: u64,
148 time_to_live: Option<Duration>,
149 time_to_idle: Option<Duration>,
150 ) -> Self {
151 let mut builder = moka::future::Cache::builder().max_capacity(capacity);
152
153 if let Some(ttl) = time_to_live {
154 builder = builder.time_to_live(ttl);
155 }
156
157 if let Some(tti) = time_to_idle {
158 builder = builder.time_to_idle(tti);
159 }
160
161 Self { cache: builder.build() }
162 }
163}
164
165#[cfg(all(not(target_arch = "wasm32"), feature = "moka"))]
166impl<K: std::hash::Hash + Eq + Clone + Send + Sync + 'static, V: Clone + Send + Sync + 'static>
167 Cache<K, V> for MokaCacheImpl<K, V>
168{
169 fn get(&self, key: &K) -> Option<V> {
170 futures::executor::block_on(async {
173 if let Some((value, expiry)) = self.cache.get(key).await {
174 if let Some(exp_time) = expiry {
176 if std::time::Instant::now() > exp_time {
177 self.cache.invalidate(key).await;
179 return None;
180 }
181 }
182 Some(value)
183 } else {
184 None
185 }
186 })
187 }
188
189 fn put(&self, key: K, value: V, ttl_secs: u64) {
190 futures::executor::block_on(async {
193 let expiry = if ttl_secs > 0 {
195 Some(std::time::Instant::now() + Duration::from_secs(ttl_secs))
196 } else {
197 None };
199
200 self.cache.insert(key, (value, expiry)).await;
202 });
203 }
204
205 fn remove(&self, key: &K) -> Option<V> {
206 futures::executor::block_on(async {
207 self.cache.remove(key).await.map(|(value, _)| value)
208 })
209 }
210
211 fn clear(&self) {
212 futures::executor::block_on(async { self.cache.invalidate_all() });
215 }
216}