use crate::cache::CacheStore;
use crate::error::Error;
use async_trait::async_trait;
use redis::aio::ConnectionManager;
use redis::AsyncCommands;
use std::time::Duration;
use tracing::debug;
pub struct RedisStore {
client: ConnectionManager,
}
impl RedisStore {
pub async fn new(url: &str) -> Result<Self, Error> {
let client = redis::Client::open(url).map_err(|e| Error::connection(e.to_string()))?;
let manager = ConnectionManager::new(client)
.await
.map_err(|e| Error::connection(e.to_string()))?;
debug!("Connected to Redis at {}", url);
Ok(Self { client: manager })
}
}
#[async_trait]
impl CacheStore for RedisStore {
async fn get_raw(&self, key: &str) -> Result<Option<Vec<u8>>, Error> {
let mut conn = self.client.clone();
let value: Option<Vec<u8>> = conn.get(key).await?;
Ok(value)
}
async fn put_raw(&self, key: &str, value: Vec<u8>, ttl: Duration) -> Result<(), Error> {
let mut conn = self.client.clone();
let seconds = ttl.as_secs() as i64;
if seconds > 0 {
conn.set_ex::<_, _, ()>(key, value, seconds as u64).await?;
} else {
conn.set::<_, _, ()>(key, value).await?;
}
Ok(())
}
async fn has(&self, key: &str) -> Result<bool, Error> {
let mut conn = self.client.clone();
let exists: bool = conn.exists(key).await?;
Ok(exists)
}
async fn forget(&self, key: &str) -> Result<bool, Error> {
let mut conn = self.client.clone();
let deleted: i64 = conn.del(key).await?;
Ok(deleted > 0)
}
async fn flush(&self) -> Result<(), Error> {
let mut conn = self.client.clone();
redis::cmd("FLUSHDB").query_async::<()>(&mut conn).await?;
Ok(())
}
async fn increment(&self, key: &str, value: i64) -> Result<i64, Error> {
let mut conn = self.client.clone();
let result: i64 = conn.incr(key, value).await?;
Ok(result)
}
async fn decrement(&self, key: &str, value: i64) -> Result<i64, Error> {
let mut conn = self.client.clone();
let result: i64 = conn.decr(key, value).await?;
Ok(result)
}
async fn tag_add(&self, tag: &str, key: &str) -> Result<(), Error> {
let mut conn = self.client.clone();
conn.sadd::<_, _, ()>(tag, key).await?;
Ok(())
}
async fn tag_members(&self, tag: &str) -> Result<Vec<String>, Error> {
let mut conn = self.client.clone();
let members: Vec<String> = conn.smembers(tag).await?;
Ok(members)
}
async fn tag_flush(&self, tag: &str) -> Result<(), Error> {
let mut conn = self.client.clone();
let keys: Vec<String> = conn.smembers(tag).await?;
if !keys.is_empty() {
for key in &keys {
conn.del::<_, ()>(key).await?;
}
}
conn.del::<_, ()>(tag).await?;
Ok(())
}
}
#[cfg(test)]
mod tests {
}