geph5-client 0.2.15

Geph5 client
Documentation
use std::{future::Future, sync::Arc, time::Duration};

use parking_lot::Mutex;
use smol::future::FutureExt;
use smolscale::immortal::Immortal;

pub struct RefreshCell<T: Clone> {
    inner: Arc<Mutex<T>>,
    _task: Immortal,
}

impl<T: Clone + Send + 'static> RefreshCell<T> {
    pub async fn create<Fut: Future<Output = T> + Send>(
        interval: Duration,
        mut refresh: impl FnMut() -> Fut + Send + 'static,
    ) -> Self {
        let inner = Arc::new(Mutex::new(refresh().await));
        let inner2 = inner.clone();
        let task = Immortal::spawn(async move {
            let mut heartbeat = smol::Timer::interval(interval);
            loop {
                let fresh = async {
                    let new_value = refresh().await;
                    tracing::debug!(interval = debug(interval), "RefreshCell refreshed properly");
                    let mut inner = inner2.lock();
                    *inner = new_value;
                    true
                };
                let timeout = async {
                    (&mut heartbeat).await;
                    tracing::debug!(
                        interval = debug(interval),
                        "RefreshCell timed out this time"
                    );
                    false
                };
                let refreshed = fresh.race(timeout).await;
                if refreshed {
                    (&mut heartbeat).await;
                }
            }
        });
        Self { inner, _task: task }
    }

    pub fn get(&self) -> T {
        self.inner.lock().clone()
    }
}