cal-redis 0.1.80

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

use crate::cache::CallableCache;
use crate::local_cache::build_account_identifiers_locally;
use crate::{get_account_by_id, get_account_by_ident, get_accounts, get_trunk_and_ddi};
use cal_core::AccountLite;
use redis::RedisError;
use std::sync::Arc;

impl CallableCache {
    /// Retrieves an account by trunk IP and DDI, first checking the local cache and then Redis.
    ///
    /// This function:
    /// 1. Checks if the trunk-DDI combination exists in the local cache
    /// 2. If found, retrieves the account ID and uses it to look up the account
    /// 3. If not found in local cache, falls back to Redis lookup
    /// 4. Caches the result for future use
    ///
    /// # Arguments
    /// * `ddi_id` - DDI identifier (typically a phone number)
    /// * `trunk_ip` - IP address of the trunk
    ///
    /// # Returns
    /// * `Result<Option<AccountLite>, RedisError>` - Account if found, None if not found, or a Redis error
    pub async fn get_account_by_trunk_ddi(
        self,
        ddi_id: &str,
        trunk_ip: &str,
    ) -> Result<Option<Arc<AccountLite>>, RedisError> {
        println!("[CallableCache::get_account_by_trunk_ddi] Looking up account for DDI: {}, Trunk IP: {}", ddi_id, trunk_ip);
        // Create a composite key for the trunk-DDI combination
        let trunk_ddi_key = format!("{}:{}", trunk_ip, ddi_id);

        // Try to get the account ID from the local trunk-DDI cache
        if let Some(account_id) = self.local_cache.trunk_ddi_idents.get(&trunk_ddi_key) {
            println!("[CallableCache::get_account_by_trunk_ddi] Found trunk-DDI in local cache, account_id: {}", account_id);
            // If we have an account ID, try to get the account from the local account cache
            if let Some(account) = self.local_cache.accounts.get(account_id.as_str()) {
                println!("[CallableCache::get_account_by_trunk_ddi] Found account in local cache: {}", account.name);
                return Ok(Some(account.clone()));
            }

            // If account not in local cache, but we have the ID, fetch from Redis
            println!("[CallableCache::get_account_by_trunk_ddi] Account not in local cache, fetching from Redis");
            match get_account_by_id(self.remote_cache.connection.clone(), account_id.as_str())
                .await?
            {
                Some(account) => {
                    println!("[CallableCache::get_account_by_trunk_ddi] Found account in Redis: {}", account.name);
                    // Cache the retrieved account for future use
                    build_account_identifiers_locally(self.local_cache, &account.clone());
                    Ok(Some(Arc::new(account)))
                }
                None => {
                    println!("[CallableCache::get_account_by_trunk_ddi] Account not found in Redis for id: {}", account_id);
                    Ok(None)
                }
            }
        } else {
            // If trunk-DDI combination not in local cache, try Redis
            println!("[CallableCache::get_account_by_trunk_ddi] Trunk-DDI not in local cache, checking Redis");
            match get_trunk_and_ddi(self.remote_cache.connection.clone(), ddi_id, trunk_ip).await? {
                Some(account) => {
                    println!("[CallableCache::get_account_by_trunk_ddi] Found account in Redis via trunk-DDI lookup: {}", account.name);
                    // Cache the retrieved account and trunk-DDI mapping for future use
                    build_account_identifiers_locally(self.local_cache.clone(), &account.clone());

                    // Add the trunk-DDI mapping to local cache
                    self.local_cache
                        .trunk_ddi_idents
                        .insert(trunk_ddi_key, account.id.clone());

                    Ok(Some(Arc::new(account)))
                }
                None => {
                    println!("[CallableCache::get_account_by_trunk_ddi] No account found for trunk-DDI combination");
                    Ok(None)
                }
            }
        }
    }

    /// Retrieves an account by its ID, first checking the local cache and then Redis.
    ///
    /// # Arguments
    /// * `id` - Account ID to look up
    ///
    /// # Returns
    /// * `Result<Option<AccountLite>, RedisError>` - Account if found, None if not found, or a Redis error
    pub async fn get_account_by_id(self, id: &str) -> Result<Option<Arc<AccountLite>>, RedisError> {
        // Try to get the resolved ID from the local cache
        if let Some(resolved_id) = self.local_cache.account_idents.get(id) {
            // If we have a resolved ID, try to get the account from the local cache
            println!(
                "CallableCache: get_account_by_id: Found local ident {:?}",
                resolved_id
            );
            if let Some(account) = self.local_cache.accounts.get(resolved_id.as_str()) {
                println!(
                    "CallableCache: get_account_by_id: Found local account {:?}",
                    resolved_id
                );
                return Ok(Some(account));
            }

            // If not in local cache, fetch from Redis using the resolved ID
            match get_account_by_id(self.remote_cache.connection.clone(), &resolved_id).await? {
                Some(account) => {
                    // Cache the retrieved account for future use
                    println!(
                        "CallableCache: get_account_by_id: Found remote account {:?}",
                        resolved_id
                    );
                    self.local_cache
                        .account_idents
                        .insert(id.to_string(), account.id.to_string());
                    build_account_identifiers_locally(self.local_cache, &account.clone());
                    Ok(Some(Arc::new(account)))
                }
                None => Ok(None),
            }
        } else {
            // If account identifier not in local cache, try Redis
            println!(
                "CallableCache: get_account_by_id: Find remote account ident {:?}",
                id
            );
            match get_account_by_ident(self.remote_cache.connection.clone(), id).await? {
                Some(account) => {
                    // Cache the retrieved account for future use
                    println!(
                        "CallableCache: get_account_by_id: Found remote account {:?}",
                        account.name
                    );
                    self.local_cache
                        .accounts
                        .insert(id.to_string(), Arc::new(account.clone()));
                    build_account_identifiers_locally(self.local_cache, &account.clone());
                    Ok(Some(Arc::new(account)))
                }
                None => {
                    println!(
                        "CallableCache: get_account_by_id: No account ident {:?}",
                        id
                    );
                    Ok(None)
                }
            }
        }
    }

    /// Retrieves all accounts from Redis.
    ///
    /// # Returns
    /// * `Result<Vec<AccountLite>, RedisError>` - Vec of AccountLite
    pub async fn get_accounts(self) -> Result<Arc<Vec<AccountLite>>, RedisError> {
        println!("[CallableCache::get_accounts] Getting all accounts from Redis");
        let accounts = get_accounts(self.remote_cache.connection).await?;
        println!("[CallableCache::get_accounts] Retrieved {} accounts from Redis", accounts.len());
        for account in &accounts {
            build_account_identifiers_locally(self.local_cache.clone(), account);
        }
        Ok(Arc::new(accounts))
    }
}