sa_token_storage_redis/
lib.rs1use std::time::Duration;
41use async_trait::async_trait;
42use redis::{Client, AsyncCommands, aio::ConnectionManager};
43use serde::{Deserialize, Serialize};
44use sa_token_adapter::storage::{SaStorage, StorageResult, StorageError};
45
46#[derive(Debug, Clone, Serialize, Deserialize)]
48pub struct RedisConfig {
49 #[serde(default = "default_host")]
51 pub host: String,
52
53 #[serde(default = "default_port")]
55 pub port: u16,
56
57 #[serde(default)]
59 pub password: Option<String>,
60
61 #[serde(default)]
63 pub database: u8,
64
65 #[serde(default = "default_pool_size")]
67 pub pool_size: u32,
68}
69
70impl Default for RedisConfig {
71 fn default() -> Self {
72 Self {
73 host: default_host(),
74 port: default_port(),
75 password: None,
76 database: 0,
77 pool_size: default_pool_size(),
78 }
79 }
80}
81
82impl RedisConfig {
83 pub fn to_url(&self) -> String {
89 if let Some(password) = &self.password {
90 format!("redis://:{}@{}:{}/{}", password, self.host, self.port, self.database)
91 } else {
92 format!("redis://{}:{}/{}", self.host, self.port, self.database)
93 }
94 }
95}
96
97fn default_host() -> String {
98 "localhost".to_string()
99}
100
101fn default_port() -> u16 {
102 6379
103}
104
105fn default_pool_size() -> u32 {
106 10
107}
108
109#[derive(Clone)]
111pub struct RedisStorage {
112 client: ConnectionManager,
113 key_prefix: String,
114}
115
116impl RedisStorage {
117 pub async fn new(redis_url: &str, key_prefix: impl Into<String>) -> StorageResult<Self> {
142 let client = Client::open(redis_url)
143 .map_err(|e| StorageError::ConnectionError(e.to_string()))?;
144
145 let connection_manager = ConnectionManager::new(client).await
146 .map_err(|e| StorageError::ConnectionError(e.to_string()))?;
147
148 Ok(Self {
149 client: connection_manager,
150 key_prefix: key_prefix.into(),
151 })
152 }
153
154 pub async fn from_config(config: RedisConfig, key_prefix: impl Into<String>) -> StorageResult<Self> {
175 let redis_url = config.to_url();
176 Self::new(&redis_url, key_prefix).await
177 }
178
179 pub fn builder() -> RedisStorageBuilder {
195 RedisStorageBuilder::default()
196 }
197
198 fn full_key(&self, key: &str) -> String {
200 format!("{}{}", self.key_prefix, key)
201 }
202}
203
204#[derive(Default)]
206pub struct RedisStorageBuilder {
207 config: RedisConfig,
208 key_prefix: Option<String>,
209}
210
211impl RedisStorageBuilder {
212 pub fn host(mut self, host: impl Into<String>) -> Self {
214 self.config.host = host.into();
215 self
216 }
217
218 pub fn port(mut self, port: u16) -> Self {
220 self.config.port = port;
221 self
222 }
223
224 pub fn password(mut self, password: impl Into<String>) -> Self {
226 self.config.password = Some(password.into());
227 self
228 }
229
230 pub fn database(mut self, database: u8) -> Self {
232 self.config.database = database;
233 self
234 }
235
236 pub fn pool_size(mut self, size: u32) -> Self {
238 self.config.pool_size = size;
239 self
240 }
241
242 pub fn key_prefix(mut self, prefix: impl Into<String>) -> Self {
244 self.key_prefix = Some(prefix.into());
245 self
246 }
247
248 pub async fn build(self) -> StorageResult<RedisStorage> {
253 let key_prefix = self.key_prefix
254 .expect("key_prefix must be set before building RedisStorage");
255
256 RedisStorage::from_config(self.config, key_prefix).await
257 }
258}
259
260#[async_trait]
261impl SaStorage for RedisStorage {
262 async fn get(&self, key: &str) -> StorageResult<Option<String>> {
263 let mut conn = self.client.clone();
264 let full_key = self.full_key(key);
265
266 conn.get(&full_key).await
267 .map_err(|e| StorageError::OperationFailed(e.to_string()))
268 }
269
270 async fn set(&self, key: &str, value: &str, ttl: Option<Duration>) -> StorageResult<()> {
271 let mut conn = self.client.clone();
272 let full_key = self.full_key(key);
273
274 if let Some(ttl) = ttl {
275 conn.set_ex(&full_key, value, ttl.as_secs()).await
276 .map_err(|e| StorageError::OperationFailed(e.to_string()))
277 } else {
278 conn.set(&full_key, value).await
279 .map_err(|e| StorageError::OperationFailed(e.to_string()))
280 }
281 }
282
283 async fn delete(&self, key: &str) -> StorageResult<()> {
284 let mut conn = self.client.clone();
285 let full_key = self.full_key(key);
286
287 conn.del(&full_key).await
288 .map_err(|e| StorageError::OperationFailed(e.to_string()))
289 }
290
291 async fn exists(&self, key: &str) -> StorageResult<bool> {
292 let mut conn = self.client.clone();
293 let full_key = self.full_key(key);
294
295 conn.exists(&full_key).await
296 .map_err(|e| StorageError::OperationFailed(e.to_string()))
297 }
298
299 async fn expire(&self, key: &str, ttl: Duration) -> StorageResult<()> {
300 let mut conn = self.client.clone();
301 let full_key = self.full_key(key);
302
303 conn.expire(&full_key, ttl.as_secs() as i64).await
304 .map_err(|e| StorageError::OperationFailed(e.to_string()))
305 }
306
307 async fn ttl(&self, key: &str) -> StorageResult<Option<Duration>> {
308 let mut conn = self.client.clone();
309 let full_key = self.full_key(key);
310
311 let ttl_secs: i64 = conn.ttl(&full_key).await
312 .map_err(|e| StorageError::OperationFailed(e.to_string()))?;
313
314 match ttl_secs {
315 -2 => Ok(None), -1 => Ok(None), secs if secs > 0 => Ok(Some(Duration::from_secs(secs as u64))),
318 _ => Ok(Some(Duration::from_secs(0))),
319 }
320 }
321
322 async fn mget(&self, keys: &[&str]) -> StorageResult<Vec<Option<String>>> {
323 let mut conn = self.client.clone();
324 let full_keys: Vec<String> = keys.iter().map(|k| self.full_key(k)).collect();
325
326 conn.get(&full_keys).await
327 .map_err(|e| StorageError::OperationFailed(e.to_string()))
328 }
329
330 async fn mset(&self, items: &[(&str, &str)], ttl: Option<Duration>) -> StorageResult<()> {
331 let mut conn = self.client.clone();
332 let full_items: Vec<(String, &str)> = items.iter()
333 .map(|(k, v)| (self.full_key(k), *v))
334 .collect();
335
336 let mut pipe = redis::pipe();
338 for (key, value) in &full_items {
339 if let Some(ttl) = ttl {
340 pipe.set_ex(key, *value, ttl.as_secs());
341 } else {
342 pipe.set(key, *value);
343 }
344 }
345
346 pipe.query_async(&mut conn).await
347 .map_err(|e| StorageError::OperationFailed(e.to_string()))
348 }
349
350 async fn mdel(&self, keys: &[&str]) -> StorageResult<()> {
351 let mut conn = self.client.clone();
352 let full_keys: Vec<String> = keys.iter().map(|k| self.full_key(k)).collect();
353
354 conn.del(&full_keys).await
355 .map_err(|e| StorageError::OperationFailed(e.to_string()))
356 }
357
358 async fn incr(&self, key: &str) -> StorageResult<i64> {
359 let mut conn = self.client.clone();
360 let full_key = self.full_key(key);
361
362 conn.incr(&full_key, 1).await
363 .map_err(|e| StorageError::OperationFailed(e.to_string()))
364 }
365
366 async fn decr(&self, key: &str) -> StorageResult<i64> {
367 let mut conn = self.client.clone();
368 let full_key = self.full_key(key);
369
370 conn.decr(&full_key, 1).await
371 .map_err(|e| StorageError::OperationFailed(e.to_string()))
372 }
373
374 async fn clear(&self) -> StorageResult<()> {
375 let mut conn = self.client.clone();
376 let pattern = format!("{}*", self.key_prefix);
377
378 let keys: Vec<String> = conn.keys(&pattern).await
380 .map_err(|e| StorageError::OperationFailed(e.to_string()))?;
381
382 if !keys.is_empty() {
383 conn.del::<_, ()>(&keys).await
384 .map_err(|e| StorageError::OperationFailed(e.to_string()))?;
385 }
386
387 Ok(())
388 }
389}