Skip to main content

deltalake_catalog_unity/client/
token.rs

1//! Authorization credentials
2use std::future::Future;
3use std::time::Instant;
4
5use tokio::sync::Mutex;
6
7/// A temporary authentication token with an associated expiry
8#[derive(Debug, Clone)]
9pub struct TemporaryToken<T> {
10    /// The temporary credential
11    pub token: T,
12    /// The instant at which this credential is no longer valid
13    /// None means the credential does not expire
14    pub expiry: Option<Instant>,
15}
16
17/// Provides [`TokenCache::get_or_insert_with`] which can be used to cache a
18/// [`TemporaryToken`] based on its expiry
19#[derive(Debug)]
20pub struct TokenCache<T> {
21    cache: Mutex<Option<TemporaryToken<T>>>,
22}
23
24impl<T> Default for TokenCache<T> {
25    fn default() -> Self {
26        Self {
27            cache: Default::default(),
28        }
29    }
30}
31
32impl<T: Clone + Send> TokenCache<T> {
33    /// Get current token or update with a given closure
34    pub async fn get_or_insert_with<F, Fut, E>(&self, f: F) -> Result<T, E>
35    where
36        F: FnOnce() -> Fut + Send,
37        Fut: Future<Output = Result<TemporaryToken<T>, E>> + Send,
38    {
39        let now = Instant::now();
40        let mut locked = self.cache.lock().await;
41
42        if let Some(cached) = locked.as_ref() {
43            match cached.expiry {
44                Some(ttl)
45                    if ttl
46                        .checked_duration_since(now)
47                        .unwrap_or_default()
48                        .as_secs()
49                        > 300 =>
50                {
51                    return Ok(cached.token.clone());
52                }
53                None => return Ok(cached.token.clone()),
54                _ => (),
55            }
56        }
57
58        let cached = f().await?;
59        let token = cached.token.clone();
60        *locked = Some(cached);
61
62        Ok(token)
63    }
64}