1use async_trait::async_trait;
2use redis::{Client, AsyncCommands};
3use std::time::Duration;
4use serde::{Deserialize, Serialize};
5use crate::{Cache, Result};
6
7pub struct RedisCache {
9 client: Client,
10 default_ttl: Option<Duration>,
11}
12
13impl RedisCache {
14 pub fn new(url: &str) -> Result<Self> {
15 let client = Client::open(url)
16 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
17
18 Ok(Self {
19 client,
20 default_ttl: Some(Duration::from_secs(3600)),
21 })
22 }
23
24 pub fn with_default_ttl(url: &str, ttl: Duration) -> Result<Self> {
25 let client = Client::open(url)
26 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
27
28 Ok(Self {
29 client,
30 default_ttl: Some(ttl),
31 })
32 }
33}
34
35#[async_trait]
36impl Cache for RedisCache {
37 async fn get<T>(&self, key: &str) -> Result<Option<T>>
38 where
39 T: for<'de> Deserialize<'de> + Send,
40 {
41 let mut conn = self.client.get_multiplexed_async_connection()
42 .await
43 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
44
45 let result: Option<String> = conn.get(key)
46 .await
47 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
48
49 if let Some(data) = result {
50 let value: T = serde_json::from_str(&data)
51 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
52 Ok(Some(value))
53 } else {
54 Ok(None)
55 }
56 }
57
58 async fn set<T>(&self, key: &str, value: &T, ttl: Option<Duration>) -> Result<()>
59 where
60 T: Serialize + Send + Sync,
61 {
62 let mut conn = self.client.get_multiplexed_async_connection()
63 .await
64 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
65
66 let data = serde_json::to_string(value)
67 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
68
69 let ttl = ttl.or(self.default_ttl);
70
71 if let Some(duration) = ttl {
72 let _: () = conn.set_ex(key, data, duration.as_secs() as u64)
73 .await
74 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
75 } else {
76 let _: () = conn.set(key, data)
77 .await
78 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
79 }
80
81 Ok(())
82 }
83
84 async fn delete(&self, key: &str) -> Result<()> {
85 let mut conn = self.client.get_multiplexed_async_connection()
86 .await
87 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
88
89 let _: () = conn.del(key)
90 .await
91 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
92
93 Ok(())
94 }
95
96 async fn exists(&self, key: &str) -> Result<bool> {
97 let mut conn = self.client.get_multiplexed_async_connection()
98 .await
99 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
100
101 let exists: bool = conn.exists(key)
102 .await
103 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
104
105 Ok(exists)
106 }
107
108 async fn flush(&self) -> Result<()> {
109 let mut conn = self.client.get_multiplexed_async_connection()
110 .await
111 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
112
113 let _: () = redis::cmd("FLUSHDB")
114 .query_async(&mut conn)
115 .await
116 .map_err(|e| Box::new(e) as Box<dyn std::error::Error + Send + Sync>)?;
117
118 Ok(())
119 }
120}