use redis::{Client, AsyncCommands}; use redis::aio::ConnectionManager; use once_cell::sync::OnceCell; use crate::error::AppError; pub type RedisPool = ConnectionManager; static REDIS_POOL: OnceCell = OnceCell::new(); /// 初始化Redis连接池 pub async fn init_redis() -> Result { let redis_url = std::env::var("REDIS_URL") .unwrap_or_else(|_| "redis://:123456@127.0.0.1:6379/9".into()); tracing::info!("Connecting to Redis at: {}", redis_url.replace(":123456", ":***")); let client = Client::open(redis_url) .map_err(|e| AppError::Anyhow(anyhow::anyhow!("Failed to create Redis client: {}", e)))?; let manager = ConnectionManager::new(client).await .map_err(|e| AppError::Anyhow(anyhow::anyhow!("Failed to create Redis connection manager: {}", e)))?; tracing::info!("Redis connection established successfully"); Ok(manager) } /// 获取Redis连接池 pub fn get_redis() -> Result<&'static RedisPool, AppError> { REDIS_POOL.get().ok_or_else(|| AppError::Anyhow(anyhow::anyhow!("Redis pool not initialized"))) } /// 设置Redis连接池 pub fn set_redis_pool(pool: RedisPool) -> Result<(), AppError> { REDIS_POOL.set(pool) .map_err(|_| AppError::Anyhow(anyhow::anyhow!("Redis pool already initialized"))) } /// Redis工具函数 pub struct RedisHelper; impl RedisHelper { /// 设置带过期时间的键值对 pub async fn set_ex(key: &str, value: &str, expire_seconds: u64) -> Result<(), AppError> { let mut conn = get_redis()?.clone(); tracing::debug!("Redis SET_EX: key={}, value_len={}, expire_seconds={}", key, value.len(), expire_seconds); let _: String = conn.set_ex(key, value, expire_seconds).await .map_err(|e| { tracing::error!("Redis set_ex failed for key {}: {}", key, e); AppError::Anyhow(anyhow::anyhow!("Redis set_ex failed: {}", e)) })?; tracing::debug!("Redis SET_EX successful for key: {}", key); Ok(()) } /// 获取键值 pub async fn get(key: &str) -> Result, AppError> { let mut conn = get_redis()?.clone(); let result: Option = conn.get(key).await .map_err(|e| AppError::Anyhow(anyhow::anyhow!("Redis get failed: {}", e)))?; Ok(result) } /// 删除键 #[allow(dead_code)] pub async fn del(key: &str) -> Result<(), AppError> { let mut conn = get_redis()?.clone(); let _: i32 = conn.del(key).await .map_err(|e| AppError::Anyhow(anyhow::anyhow!("Redis del failed: {}", e)))?; Ok(()) } /// 检查键是否存在 #[allow(dead_code)] pub async fn exists(key: &str) -> Result { let mut conn = get_redis()?.clone(); let result: bool = conn.exists(key).await .map_err(|e| AppError::Anyhow(anyhow::anyhow!("Redis exists failed: {}", e)))?; Ok(result) } /// 设置键的过期时间 #[allow(dead_code)] pub async fn expire(key: &str, seconds: u64) -> Result<(), AppError> { let mut conn = get_redis()?.clone(); let _: bool = conn.expire(key, seconds as i64).await .map_err(|e| AppError::Anyhow(anyhow::anyhow!("Redis expire failed: {}", e)))?; Ok(()) } /// 删除用户相关的所有token pub async fn del_user_tokens(user_id: i64) -> Result<(), AppError> { let pattern = format!("token:*:user:{}", user_id); let mut conn = get_redis()?.clone(); // 获取匹配的键 let keys: Vec = conn.keys(&pattern).await .map_err(|e| AppError::Anyhow(anyhow::anyhow!("Redis keys failed: {}", e)))?; // 删除所有匹配的键 if !keys.is_empty() { let _: i32 = conn.del(&keys).await .map_err(|e| AppError::Anyhow(anyhow::anyhow!("Redis del multiple failed: {}", e)))?; } Ok(()) } } /// Token相关的Redis操作 pub struct TokenRedis; impl TokenRedis { /// 存储访问token pub async fn store_access_token(token: &str, user_id: i64, expire_seconds: u64) -> Result<(), AppError> { let key = format!("token:access:user:{}", user_id); tracing::info!("Storing access token for user {} with key: {}, expires in {} seconds", user_id, key, expire_seconds); RedisHelper::set_ex(&key, token, expire_seconds).await } /// 存储刷新token pub async fn store_refresh_token(token: &str, user_id: i64, expire_seconds: u64) -> Result<(), AppError> { let key = format!("token:refresh:user:{}", user_id); tracing::info!("Storing refresh token for user {} with key: {}, expires in {} seconds", user_id, key, expire_seconds); RedisHelper::set_ex(&key, token, expire_seconds).await } /// 验证访问token pub async fn validate_access_token(token: &str, user_id: i64) -> Result { let key = format!("token:access:user:{}", user_id); let stored_token = RedisHelper::get(&key).await?; Ok(stored_token.as_deref() == Some(token)) } /// 验证刷新token pub async fn validate_refresh_token(token: &str, user_id: i64) -> Result { let key = format!("token:refresh:user:{}", user_id); let stored_token = RedisHelper::get(&key).await?; Ok(stored_token.as_deref() == Some(token)) } /// 删除用户的访问token #[allow(dead_code)] pub async fn revoke_access_token(user_id: i64) -> Result<(), AppError> { let key = format!("token:access:user:{}", user_id); RedisHelper::del(&key).await } /// 删除用户的刷新token #[allow(dead_code)] pub async fn revoke_refresh_token(user_id: i64) -> Result<(), AppError> { let key = format!("token:refresh:user:{}", user_id); RedisHelper::del(&key).await } /// 删除用户的所有token pub async fn revoke_all_tokens(user_id: i64) -> Result<(), AppError> { RedisHelper::del_user_tokens(user_id).await } }