tetrio_api/http/caches/
redis_cache.rs

1use std::{borrow::Cow, fmt::Debug};
2
3use async_trait::async_trait;
4use redis::Commands;
5use serde::{de::DeserializeOwned, Serialize};
6
7use crate::{http::error::Error, models::packet::{Packet, SuccessPacket}};
8
9use super::cache::CacheHandler;
10
11/// A cache implementation that uses a Redis instance to automatically remove the cache entries when their expiration date has passed.
12pub struct RedisCache<'a> {
13    pub client: Cow<'a, redis::Client>
14}
15
16impl<'a> RedisCache<'a> {
17    pub fn new(client: Cow<'a, redis::Client>) -> Self {
18        Self {
19            client
20        }
21    }
22}
23
24#[async_trait]
25impl<'a, ErrorT: std::error::Error + Sync + Send + Debug> CacheHandler<ErrorT> for RedisCache<'a> {
26    type CachingError = redis::RedisError;
27    async fn try_get_cache<T: DeserializeOwned + Serialize>(&self, key: &str) -> Result<Option<Packet<T>>, Error<ErrorT, Self::CachingError>>
28    {
29        let mut con = self.client.get_connection().map_err(Error::CachingError)?;
30
31        let exists: bool = con.exists(key).map_err(Error::CachingError)?;
32        
33        match exists {
34            false => Ok(None),
35            true => Ok(Some(serde_json::from_str(&con.get::<&str, String>(key).map_err(Error::CachingError)?).map_err(Error::CacheConversionError)?))
36        }
37    }
38
39    async fn cache_value<T: DeserializeOwned + Serialize + Send + Sync>(&self, key: &str, value: SuccessPacket<T>) -> Result<(), Error<ErrorT, Self::CachingError>> {
40        let mut con = self.client.get_connection().map_err(Error::CachingError)?;
41        
42        con.set_ex::<_, _, redis::Value>(key, serde_json::to_string(&value).map_err(Error::CacheConversionError)?, value.cache.time_until_elapsed().as_secs()).map_err(Error::CachingError)?;
43
44        Ok(())
45    }
46
47}