cal_redis/cache/
mod.rs

1// File: cal-redis/src/cache/mod.rs
2
3mod account;
4mod agent;
5mod asset;
6mod device;
7mod ddi;
8mod hook;
9mod proxy;
10mod queue;
11mod region;
12mod session;
13mod trunk;
14mod user;
15mod websocket;
16mod helpers;
17mod jambonz;
18mod contact;
19
20pub use helpers::{create_pool, get_hash, get_hash_all_values, get_str, publish_event};
21
22use crate::local_cache::{
23    build_account_identifiers_locally, build_region_identifiers_locally,
24    build_user_identifiers_locally, LocalCache,
25};
26use crate::redis_cache::RedisCache;
27use cal_core::{RedisEvent, User};
28use redis::aio::MultiplexedConnection;
29use redis::RedisError;
30use std::sync::Arc;
31
32/// Main cache structure that combines local in-memory caching with remote Redis storage.
33///
34/// Provides a unified interface for accessing data with automatic fallback to Redis
35/// when items aren't found in the local cache.
36#[derive(Clone)]
37pub struct CallableCache {
38    pub local_cache: LocalCache,
39    pub remote_cache: RedisCache,
40}
41
42impl CallableCache {
43    /// Creates a new CallableCache instance with local and remote caches.
44    ///
45    /// # Returns
46    /// * `CallableCache` - The new cache instance
47    pub async fn new() -> CallableCache {
48        println!("[CallableCache::new] Creating new CallableCache instance");
49        let (remote_cache, local_cache) = create_pool().await;
50        println!("[CallableCache::new] Cache instance created successfully");
51        CallableCache {
52            local_cache,
53            remote_cache,
54        }
55    }
56
57    /// Raw Redis connection access for custom operations
58    pub fn redis_connection(&self) -> MultiplexedConnection {
59        self.remote_cache.connection.clone()
60    }
61
62    /// Retrieves a string value from Redis.
63    ///
64    /// # Arguments
65    /// * `key` - Redis key
66    ///
67    /// # Returns
68    /// * `Result<Option<String>, RedisError>` - String value if found, None if not found, or a Redis error
69    pub async fn get_str(self, key: &str) -> Result<Option<String>, RedisError> {
70        println!("[CallableCache::get_str] Getting string value for key: {}", key);
71        let result = get_str(self.remote_cache.connection, key).await?;
72        match &result {
73            Some(value) => println!("[CallableCache::get_str] Found value of length: {}", value.len()),
74            None => println!("[CallableCache::get_str] No value found"),
75        }
76        Ok(result)
77    }
78
79    /// Retrieves a field from a Redis hash.
80    ///
81    /// # Arguments
82    /// * `key` - Redis hash key
83    /// * `field` - Field to retrieve
84    ///
85    /// # Returns
86    /// * `Result<Option<String>, RedisError>` - Field value if found, None if not found, or a Redis error
87    pub async fn get_hash(self, key: &str, field: &str) -> Result<Option<String>, RedisError> {
88        println!("[CallableCache::get_hash] Getting hash field - Key: {}, Field: {}", key, field);
89        let result = get_hash(self.remote_cache.connection, key, field).await?;
90        match &result {
91            Some(value) => println!("[CallableCache::get_hash] Found field value of length: {}", value.len()),
92            None => println!("[CallableCache::get_hash] Field not found"),
93        }
94        Ok(result)
95    }
96}
97
98/// Handles Redis pubsub events by updating the local cache appropriately.
99///
100/// # Arguments
101/// * `event` - The Redis event to handle
102/// * `cache` - The local cache to update
103pub(crate) fn handle_redis_event(event: RedisEvent, cache: &LocalCache) {
104    match event {
105        RedisEvent::AccountUpdate(update) => {
106            println!("[handle_redis_event] Processing AccountUpdate for: {}", update.payload.name);
107            build_account_identifiers_locally(cache.clone(), &update.payload.into());
108        }
109        RedisEvent::AccountDelete(delete) => {
110            println!("[handle_redis_event] Processing AccountDelete for ID: {}", delete.id);
111            cache.accounts.invalidate(&delete.id);
112        }
113        RedisEvent::AccountCreate(create) => {
114            println!("[handle_redis_event] Processing AccountCreate for: {}", create.payload.name);
115            build_account_identifiers_locally(cache.clone(), &create.payload.into());
116        }
117        RedisEvent::AccountSync => {
118            println!("[handle_redis_event] Processing AccountSync - invalidating all accounts");
119            cache.accounts.invalidate_all();
120            cache.account_idents.invalidate_all();
121        }
122        RedisEvent::RegionUpdate(update) => {
123            println!("[handle_redis_event] Processing RegionUpdate for: {}", update.payload.name);
124            cache
125                .regions
126                .insert(update.payload.id.to_string(), Arc::new(update.payload));
127        }
128        RedisEvent::RegionDelete(delete) => {
129            println!("[handle_redis_event] Processing RegionDelete for ID: {}", delete.id);
130            cache.regions.invalidate(&delete.id);
131        }
132        RedisEvent::RegionCreate(create) => {
133            println!("[handle_redis_event] Processing RegionCreate for: {}", create.payload.name);
134            build_region_identifiers_locally(cache.clone(), Arc::new(create.payload));
135        }
136        RedisEvent::RegionSync => {
137            println!("[handle_redis_event] Processing RegionSync - invalidating all regions");
138            cache.regions.invalidate_all();
139            cache.region_idents.invalidate_all();
140        }
141        RedisEvent::UserCreate(create) => {
142            println!("[handle_redis_event] Processing UserCreate for: {}", create.payload.email);
143            let user: User = create.payload.into();
144            build_user_identifiers_locally(cache, &user);
145        }
146        RedisEvent::UserUpdate(update) => {
147            println!("[handle_redis_event] Processing UserUpdate for: {}", update.payload.email);
148            let user: User = update.payload.into();
149            build_user_identifiers_locally(cache, &user);
150        }
151        RedisEvent::UserDelete(delete) => {
152            println!("[handle_redis_event] Processing UserDelete for ID: {}", delete.id);
153            cache.users.invalidate(&delete.id);
154            // Also remove from idents cache
155            cache.user_idents.invalidate(&delete.id);
156        }
157        RedisEvent::UserSync => {
158            println!("[handle_redis_event] Processing UserSync - invalidating all users");
159            cache.users.invalidate_all();
160            cache.user_idents.invalidate_all();
161        }
162    }
163}