1use std::{future::Future, time::Instant};
2
3use async_std::sync::Mutex;
4
5#[derive(Default)]
6pub struct Expiring<T>(Mutex<Option<ExpiringState<T>>>);
7
8pub struct ExpiringState<T> {
9 value: T,
10 expires_at: Instant,
11}
12
13impl<T: Clone> Expiring<T> {
14 pub async fn get_or_refresh<F, G>(&self, f: F) -> tide::Result<T>
15 where
16 F: FnOnce() -> G,
17 G: Future<Output = tide::Result<(T, Instant)>>,
18 {
19 let mut state = self.0.lock().await;
20
21 if let Some(state) = state.as_mut() {
22 if Instant::now() >= state.expires_at {
23 let (value, expires_at) = f().await?;
24 state.value = value.clone();
25 state.expires_at = expires_at;
26 Ok(value)
27 } else {
28 Ok(state.value.clone())
29 }
30 } else {
31 let (value, expires_at) = f().await?;
32 *state = Some(ExpiringState {
33 value: value.clone(),
34 expires_at,
35 });
36 Ok(value)
37 }
38 }
39
40 pub async fn clear(&self) {
41 self.0.lock().await.take();
42 }
43}