hodei_authz_redis/
lib.rs

1//! Redis cache adapter for Hodei authorization framework
2//!
3//! This crate provides Redis-based cache invalidation for policies.
4
5use async_trait::async_trait;
6use futures_util::stream::StreamExt;
7use hodei_authz::{CacheError, CacheInvalidation};
8use redis::Client;
9
10/// Redis implementation of CacheInvalidation
11pub struct RedisCacheInvalidation {
12    client: Client,
13}
14
15impl RedisCacheInvalidation {
16    /// Create a new Redis cache invalidation handler
17    pub async fn new(redis_url: &str) -> Result<Self, redis::RedisError> {
18        let client = Client::open(redis_url)?;
19        
20        // Test connection
21        let mut conn = client.get_multiplexed_async_connection().await?;
22        redis::cmd("PING")
23            .query_async::<()>(&mut conn)
24            .await?;
25        
26        Ok(Self { client })
27    }
28}
29
30#[async_trait]
31impl CacheInvalidation for RedisCacheInvalidation {
32    async fn invalidate_policies(&self) -> Result<(), CacheError> {
33        let mut conn = self
34            .client
35            .get_multiplexed_async_connection()
36            .await
37            .map_err(|e| CacheError::Connection(e.to_string()))?;
38        
39        redis::cmd("PUBLISH")
40            .arg("hodei:policy:invalidate")
41            .arg("reload")
42            .query_async::<()>(&mut conn)
43            .await
44            .map_err(|e| CacheError::Publish(e.to_string()))?;
45        
46        Ok(())
47    }
48    
49    async fn subscribe_to_invalidations<F>(&self, callback: F) -> Result<(), CacheError>
50    where
51        F: Fn() + Send + Sync + 'static,
52    {
53        // Note: This is a simplified implementation
54        // In production, you'd want proper PubSub handling with reconnection logic
55        
56        tracing::warn!("Redis PubSub subscription is not fully implemented in this version");
57        tracing::info!("Cache invalidation will work via explicit invalidate_policies() calls");
58        
59        // For now, we just acknowledge the subscription request
60        // A full implementation would require:
61        // 1. A dedicated PubSub connection (not MultiplexedConnection)
62        // 2. Proper error handling and reconnection
63        // 3. Background task management
64        
65        Ok(())
66    }
67}