use std::future::Future;
use bb8::{Pool, PooledConnection};
use bb8_redis::RedisConnectionManager;
use eyre::{OptionExt, Result};
use redis::{AsyncCommands, FromRedisValue, ToRedisArgs};
use serde::Serialize;
use serde_json::Value;
use crate::services::{Redis, service};
async fn store() -> Result<PooledConnection<'static,RedisConnectionManager>> {
let client = service().get::<Redis>().unwrap();
client.connection().await
}
pub async fn has<K>(key: K) -> eyre::Result<bool>
where
K: ToRedisArgs + Send + Sync,
{
let mut con = store().await?;
let exist: bool = con.exists(key).await?;
Ok(exist)
}
pub async fn get<K, T>(key: K) -> eyre::Result<T>
where
K: ToRedisArgs + Send + Sync,
T: FromRedisValue,
{
let mut con = store().await?;
let result: T = con.get(key).await?;
tracing::debug!("cache hit");
Ok(result)
}
pub async fn set<K, V>(key: K, value: V, seconds: u64) -> eyre::Result<()>
where
K: ToRedisArgs + Send + Sync,
V: ToRedisArgs + Send + Sync,
{
let mut con = store().await?;
con.set_ex(key, value, seconds).await?;
Ok(())
}
pub async fn get_json<K>(key: K) -> eyre::Result<Value>
where
K: ToRedisArgs + Send + Sync,
{
let value: String = get(key).await?;
let result = serde_json::from_str(&value)?;
Ok(result)
}
pub async fn set_json<K, V>(key: K, value: &V, seconds: u64) -> eyre::Result<()>
where
K: ToRedisArgs + Send + Sync,
V: Serialize,
{
set(key, serde_json::to_string(value)?, seconds).await?;
Ok(())
}
pub async fn remember<K, F, Fut>(key: K, seconds: u64, func: F) -> eyre::Result<Value>
where
K: ToRedisArgs + Send + Sync,
F: FnOnce() -> Fut,
Fut: Future<Output = Result<Value>>,
{
if has(&key).await? {
return get_json(&key).await;
}
let value = func().await?;
set_json(&key, &value, seconds).await?;
Ok(value)
}
pub async fn remember_multi<K, F, Fut>(key: K, seconds: u64, func: F) -> eyre::Result<Vec<Value>>
where
K: ToRedisArgs + Send + Sync,
F: FnOnce() -> Fut,
Fut: Future<Output = Result<Vec<Value>>>,
{
if has(&key).await? {
let result = get_json(&key).await?;
let values = result.as_array().ok_or_eyre("not an array")?;
return Ok(values.to_owned());
}
let values = func().await?;
set_json(&key, &values, seconds).await?;
Ok(values)
}