cal-redis 0.1.80

Callable Redis Implementation
Documentation
// File: cal-redis/src/cache/mod.rs

mod account;
mod agent;
mod asset;
mod device;
mod ddi;
mod hook;
mod proxy;
mod queue;
mod region;
mod session;
mod trunk;
mod user;
mod websocket;
mod helpers;
mod jambonz;
mod contact;

pub use helpers::{create_pool, get_hash, get_hash_all_values, get_str, publish_event};

use crate::local_cache::{
    build_account_identifiers_locally, build_region_identifiers_locally,
    build_user_identifiers_locally, LocalCache,
};
use crate::redis_cache::RedisCache;
use cal_core::{RedisEvent, User};
use redis::aio::MultiplexedConnection;
use redis::RedisError;
use std::sync::Arc;

/// Main cache structure that combines local in-memory caching with remote Redis storage.
///
/// Provides a unified interface for accessing data with automatic fallback to Redis
/// when items aren't found in the local cache.
#[derive(Clone)]
pub struct CallableCache {
    pub local_cache: LocalCache,
    pub remote_cache: RedisCache,
}

impl CallableCache {
    /// Creates a new CallableCache instance with local and remote caches.
    ///
    /// # Returns
    /// * `CallableCache` - The new cache instance
    pub async fn new() -> CallableCache {
        println!("[CallableCache::new] Creating new CallableCache instance");
        let (remote_cache, local_cache) = create_pool().await;
        println!("[CallableCache::new] Cache instance created successfully");
        CallableCache {
            local_cache,
            remote_cache,
        }
    }

    /// Raw Redis connection access for custom operations
    pub fn redis_connection(&self) -> MultiplexedConnection {
        self.remote_cache.connection.clone()
    }

    /// Retrieves a string value from Redis.
    ///
    /// # Arguments
    /// * `key` - Redis key
    ///
    /// # Returns
    /// * `Result<Option<String>, RedisError>` - String value if found, None if not found, or a Redis error
    pub async fn get_str(self, key: &str) -> Result<Option<String>, RedisError> {
        println!("[CallableCache::get_str] Getting string value for key: {}", key);
        let result = get_str(self.remote_cache.connection, key).await?;
        match &result {
            Some(value) => println!("[CallableCache::get_str] Found value of length: {}", value.len()),
            None => println!("[CallableCache::get_str] No value found"),
        }
        Ok(result)
    }

    /// Retrieves a field from a Redis hash.
    ///
    /// # Arguments
    /// * `key` - Redis hash key
    /// * `field` - Field to retrieve
    ///
    /// # Returns
    /// * `Result<Option<String>, RedisError>` - Field value if found, None if not found, or a Redis error
    pub async fn get_hash(self, key: &str, field: &str) -> Result<Option<String>, RedisError> {
        println!("[CallableCache::get_hash] Getting hash field - Key: {}, Field: {}", key, field);
        let result = get_hash(self.remote_cache.connection, key, field).await?;
        match &result {
            Some(value) => println!("[CallableCache::get_hash] Found field value of length: {}", value.len()),
            None => println!("[CallableCache::get_hash] Field not found"),
        }
        Ok(result)
    }
}

/// Handles Redis pubsub events by updating the local cache appropriately.
///
/// # Arguments
/// * `event` - The Redis event to handle
/// * `cache` - The local cache to update
pub(crate) fn handle_redis_event(event: RedisEvent, cache: &LocalCache) {
    match event {
        RedisEvent::AccountUpdate(update) => {
            println!("[handle_redis_event] Processing AccountUpdate for: {}", update.payload.name);
            build_account_identifiers_locally(cache.clone(), &update.payload.into());
        }
        RedisEvent::AccountDelete(delete) => {
            println!("[handle_redis_event] Processing AccountDelete for ID: {}", delete.id);
            cache.accounts.invalidate(&delete.id);
        }
        RedisEvent::AccountCreate(create) => {
            println!("[handle_redis_event] Processing AccountCreate for: {}", create.payload.name);
            build_account_identifiers_locally(cache.clone(), &create.payload.into());
        }
        RedisEvent::AccountSync => {
            println!("[handle_redis_event] Processing AccountSync - invalidating all accounts");
            cache.accounts.invalidate_all();
            cache.account_idents.invalidate_all();
        }
        RedisEvent::RegionUpdate(update) => {
            println!("[handle_redis_event] Processing RegionUpdate for: {}", update.payload.name);
            cache
                .regions
                .insert(update.payload.id.to_string(), Arc::new(update.payload));
        }
        RedisEvent::RegionDelete(delete) => {
            println!("[handle_redis_event] Processing RegionDelete for ID: {}", delete.id);
            cache.regions.invalidate(&delete.id);
        }
        RedisEvent::RegionCreate(create) => {
            println!("[handle_redis_event] Processing RegionCreate for: {}", create.payload.name);
            build_region_identifiers_locally(cache.clone(), Arc::new(create.payload));
        }
        RedisEvent::RegionSync => {
            println!("[handle_redis_event] Processing RegionSync - invalidating all regions");
            cache.regions.invalidate_all();
            cache.region_idents.invalidate_all();
        }
        RedisEvent::UserCreate(create) => {
            println!("[handle_redis_event] Processing UserCreate for: {}", create.payload.email);
            let user: User = create.payload.into();
            build_user_identifiers_locally(cache, &user);
        }
        RedisEvent::UserUpdate(update) => {
            println!("[handle_redis_event] Processing UserUpdate for: {}", update.payload.email);
            let user: User = update.payload.into();
            build_user_identifiers_locally(cache, &user);
        }
        RedisEvent::UserDelete(delete) => {
            println!("[handle_redis_event] Processing UserDelete for ID: {}", delete.id);
            cache.users.invalidate(&delete.id);
            // Also remove from idents cache
            cache.user_idents.invalidate(&delete.id);
        }
        RedisEvent::UserSync => {
            println!("[handle_redis_event] Processing UserSync - invalidating all users");
            cache.users.invalidate_all();
            cache.user_idents.invalidate_all();
        }
    }
}