Something went wrong. Try again.
A small api and web interface to lookup some general information about ATProto users
Something went wrong. Try again.
1234567891011121314151617181920212223242526272829303132333435363738394041424344use std::{fmt::Debug, future::Future};
use serde::{Serialize, de::DeserializeOwned};
use crate::cache::{redis::{FRESH_SECONDS, cache_get, cache_set, now_unix}, refreshing::{REFRESHING, Refreshing}};
pub async fn get_or_compute<T, F, Fut, E>(key: &str, calculate: F) -> Result<T, E>where T: Serialize + DeserializeOwned + Send + Sync + 'static + Debug, F: FnOnce() -> Fut + Send + 'static, Fut: Future<Output = Result<T, E>> + Send + 'static, E: From<redis::RedisError> + std::fmt::Display + Send + 'static,{ if let Some(hit) = cache_get(key).await? { let age = now_unix().saturating_sub(hit.fetched_at); if age < FRESH_SECONDS { return Ok(hit.value) };
spawn_refresh(REFRESHING.get().unwrap().clone(), key.to_string(), calculate); return Ok(hit.value); }
let value = calculate().await?; cache_set(key, &value).await?; Ok(value)}
fn spawn_refresh<T, F, Fut, E>(refreshing: Refreshing, key: String, calculate: F) where T: Serialize + Send + 'static + Debug + DeserializeOwned + Sync, F: FnOnce() -> Fut + Send + 'static, Fut: Future<Output = Result<T, E>> + Send + 'static, E: From<redis::RedisError> + std::fmt::Display + Send + 'static,{ if !refreshing.lock().unwrap().insert(key.to_string()) { return; } tokio::spawn(async move { match calculate().await { Ok(value) => { if let Err(e) = cache_set(&key, &value).await { eprintln!("Failed to save value {:?} in cache: {:?}", value, e) } } Err(e) => { eprintln!("Failed to refresh value for key {key}: {e}") } } refreshing.lock().unwrap().remove(&key); });}