cache_any/caches/
redis.rs1use std::fmt::{Debug, Formatter};
2use std::sync::Arc;
3use redis::AsyncCommands;
4use tokio::sync::RwLock;
5use crate::{Cache, Cacheable};
6
7#[derive(Debug, Clone)]
32pub struct RedisCache {
33 inner: Arc<RwLock<Inner>>,
34}
35
36impl RedisCache {
37 pub async fn new<S: ToString>(client: redis::Client, map: S) -> anyhow::Result<Self> {
38 let conn = client.get_multiplexed_async_connection().await?;
39
40 Ok(Self {
41 inner: Arc::new(RwLock::new(Inner {
42 map: Arc::new(map.to_string()),
43 client,
44 conn,
45 }))
46 })
47 }
48}
49
50#[async_trait::async_trait]
51impl Cache for RedisCache {
52 async fn get<T: Cacheable + Send + Sync>(&self, key: &str) -> anyhow::Result<Option<T>> {
53 let val: Option<String> = {
54 let mut inner = self.inner.write().await;
55 let map = inner.map.clone();
56 inner.conn.hget(map, key).await?
57 };
58
59 val.map(|val| T::from_hex(&val))
60 .transpose()
61 }
62
63 async fn set<T: Cacheable + Send + Sync>(&self, key: &str, value: T) -> anyhow::Result<()> {
64 let val = value.to_hex();
65 let mut inner = self.inner.write().await;
66 let map = inner.map.clone();
67 inner.conn.hset(map, key, val).await?;
68
69 Ok(())
70 }
71
72 async fn delete(&self, key: &str) -> anyhow::Result<()> {
73 let mut inner = self.inner.write().await;
74 let map = inner.map.clone();
75 inner.conn.hdel(map, key).await?;
76
77 Ok(())
78 }
79
80 async fn len(&self) -> anyhow::Result<usize> {
81 let mut inner = self.inner.write().await;
82 let map = inner.map.clone();
83 let len: u64 = inner.conn.hlen(map).await?;
84
85 Ok(len as usize)
86 }
87}
88
89struct Inner {
90 map: Arc<String>,
91 client: redis::Client,
92 conn: redis::aio::MultiplexedConnection,
93}
94
95impl Debug for Inner {
96 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
97 f.debug_struct("RedisCache.Inner")
98 .field("client", &self.client)
99 .field("map", &self.map)
100 .finish()
101 }
102}
103
104#[cfg(test)]
105mod tests {
106 use redis::Client;
107 use super::*;
108
109 #[tokio::test]
110 async fn test_redis_cache() -> anyhow::Result<()> {
111 let client = Client::open("redis://127.0.0.1:6379/")?;
112 let cache = RedisCache::new(client, "aaa").await?;
113
114 assert_eq!(cache.get::<u8>("none").await.unwrap(), None);
115 cache.set("a", String::from("aaaaaa")).await?;
116 assert_eq!(cache.get::<String>("a").await.unwrap().unwrap(), String::from("aaaaaa"));
117 cache.set("a", String::from("aaaaaaa")).await?;
118 assert_eq!(cache.get::<String>("a").await.unwrap().unwrap(), String::from("aaaaaaa"));
119
120 cache.set("b", String::from("bbbbbb")).await?;
121 assert_eq!(cache.get::<String>("b").await.unwrap().unwrap(), String::from("bbbbbb"));
122 cache.set("c", 1).await?;
123 assert_eq!(cache.get::<usize>("c").await.unwrap().unwrap(), 1);
124
125 let cloned = cache.clone();
126 assert_eq!(cloned.get::<u8>("none").await.unwrap(), None);
127 cloned.set("a", String::from("aaaaaa")).await?;
128 assert_eq!(cloned.get::<String>("a").await.unwrap().unwrap(), String::from("aaaaaa"));
129 cloned.set("a", String::from("aaaaaaa")).await?;
130 assert_eq!(cloned.get::<String>("a").await.unwrap().unwrap(), String::from("aaaaaaa"));
131
132 cloned.set("b", String::from("bbbbbb")).await?;
133 assert_eq!(cloned.get::<String>("b").await.unwrap().unwrap(), String::from("bbbbbb"));
134 cloned.set("c", 1).await?;
135 assert_eq!(cloned.get::<usize>("c").await.unwrap().unwrap(), 1);
136
137 println!("{:?}", cache);
138 println!("{:?}", cloned);
139 println!("size = {}", cloned.len().await?);
140 Ok(())
141 }
142}