package cache import ( "sync" "time" ) // Manager manages multiple cache instances with singleton pattern type Manager struct { logger Logger tokenCache *Cache metadataCache *Cache jwkCache *Cache sessionCache *Cache generalCache *Cache typedToken *TokenCache typedMetadata *MetadataCache typedJWK *JWKCache typedSession *SessionCache mu sync.RWMutex } var ( globalManager *Manager globalManagerOnce sync.Once ) // GetGlobalManager returns the singleton cache manager instance func GetGlobalManager(logger Logger) *Manager { globalManagerOnce.Do(func() { globalManager = NewManager(logger) }) return globalManager } // NewManager creates a new cache manager func NewManager(logger Logger) *Manager { if logger == nil { logger = &noOpLogger{} } m := &Manager{ logger: logger, } // Initialize core caches with appropriate configurations m.initializeCaches() return m } // initializeCaches creates all cache instances with appropriate configurations func (m *Manager) initializeCaches() { // Token cache configuration tokenConfig := Config{ Type: TypeToken, MaxSize: 5000, MaxMemoryBytes: 32 * 1024 * 1024, // 32MB DefaultTTL: 1 * time.Hour, CleanupInterval: 5 * time.Minute, EnableAutoCleanup: true, EnableMemoryLimit: true, EnableMetrics: true, Logger: m.logger, TokenConfig: &TokenConfig{ BlacklistTTL: 24 * time.Hour, RefreshTokenTTL: 7 * 24 * time.Hour, EnableTokenRotation: true, }, } m.tokenCache = New(tokenConfig) m.typedToken = NewTokenCache(m.tokenCache) // Metadata cache configuration metadataConfig := Config{ Type: TypeMetadata, MaxSize: 100, MaxMemoryBytes: 10 * 1024 * 1024, // 10MB DefaultTTL: 24 * time.Hour, CleanupInterval: 30 * time.Minute, EnableAutoCleanup: true, EnableMemoryLimit: true, EnableMetrics: true, Logger: m.logger, MetadataConfig: &MetadataConfig{ GracePeriod: 5 * time.Minute, ExtendedGracePeriod: 15 * time.Minute, MaxGracePeriod: 1 * time.Hour, SecurityCriticalMaxGracePeriod: 30 * time.Minute, SecurityCriticalFields: []string{"issuer", "jwks_uri"}, }, } m.metadataCache = New(metadataConfig) m.typedMetadata = NewMetadataCache(m.metadataCache, *metadataConfig.MetadataConfig) // JWK cache configuration jwkConfig := Config{ Type: TypeJWK, MaxSize: 50, MaxMemoryBytes: 5 * 1024 * 1024, // 5MB DefaultTTL: 1 * time.Hour, CleanupInterval: 10 * time.Minute, EnableAutoCleanup: true, EnableMemoryLimit: true, EnableMetrics: true, Logger: m.logger, JWKConfig: &JWKConfig{ RefreshInterval: 1 * time.Hour, MinRefreshTime: 5 * time.Minute, MaxKeyAge: 24 * time.Hour, }, } m.jwkCache = New(jwkConfig) m.typedJWK = NewJWKCache(m.jwkCache) // Session cache configuration sessionConfig := Config{ Type: TypeSession, MaxSize: 10000, MaxMemoryBytes: 64 * 1024 * 1024, // 64MB DefaultTTL: 30 * time.Minute, CleanupInterval: 5 * time.Minute, EnableAutoCleanup: true, EnableMemoryLimit: true, EnableMetrics: true, Logger: m.logger, } m.sessionCache = New(sessionConfig) m.typedSession = NewSessionCache(m.sessionCache) // General cache configuration generalConfig := Config{ Type: TypeGeneral, MaxSize: 1000, MaxMemoryBytes: 16 * 1024 * 1024, // 16MB DefaultTTL: 10 * time.Minute, CleanupInterval: 5 * time.Minute, EnableAutoCleanup: true, EnableMemoryLimit: true, EnableMetrics: true, Logger: m.logger, } m.generalCache = New(generalConfig) } // GetTokenCache returns the token cache instance func (m *Manager) GetTokenCache() *TokenCache { m.mu.RLock() defer m.mu.RUnlock() return m.typedToken } // GetMetadataCache returns the metadata cache instance func (m *Manager) GetMetadataCache() *MetadataCache { m.mu.RLock() defer m.mu.RUnlock() return m.typedMetadata } // GetJWKCache returns the JWK cache instance func (m *Manager) GetJWKCache() *JWKCache { m.mu.RLock() defer m.mu.RUnlock() return m.typedJWK } // GetSessionCache returns the session cache instance func (m *Manager) GetSessionCache() *SessionCache { m.mu.RLock() defer m.mu.RUnlock() return m.typedSession } // GetGeneralCache returns the general cache instance func (m *Manager) GetGeneralCache() *Cache { m.mu.RLock() defer m.mu.RUnlock() return m.generalCache } // GetRawTokenCache returns the raw token cache for compatibility func (m *Manager) GetRawTokenCache() *Cache { m.mu.RLock() defer m.mu.RUnlock() return m.tokenCache } // GetRawMetadataCache returns the raw metadata cache for compatibility func (m *Manager) GetRawMetadataCache() *Cache { m.mu.RLock() defer m.mu.RUnlock() return m.metadataCache } // GetRawJWKCache returns the raw JWK cache for compatibility func (m *Manager) GetRawJWKCache() *Cache { m.mu.RLock() defer m.mu.RUnlock() return m.jwkCache } // GetStats returns statistics for all caches func (m *Manager) GetStats() map[string]map[string]interface{} { m.mu.RLock() defer m.mu.RUnlock() return map[string]map[string]interface{}{ "token": m.tokenCache.GetStats(), "metadata": m.metadataCache.GetStats(), "jwk": m.jwkCache.GetStats(), "session": m.sessionCache.GetStats(), "general": m.generalCache.GetStats(), } } // ClearAll clears all cache instances func (m *Manager) ClearAll() { m.mu.Lock() defer m.mu.Unlock() m.tokenCache.Clear() m.metadataCache.Clear() m.jwkCache.Clear() m.sessionCache.Clear() m.generalCache.Clear() } // Close gracefully shuts down all cache instances func (m *Manager) Close() error { m.mu.Lock() defer m.mu.Unlock() var firstErr error if err := m.tokenCache.Close(); err != nil { firstErr = err } if err := m.metadataCache.Close(); err != nil && firstErr == nil { firstErr = err } if err := m.jwkCache.Close(); err != nil && firstErr == nil { firstErr = err } if err := m.sessionCache.Close(); err != nil && firstErr == nil { firstErr = err } if err := m.generalCache.Close(); err != nil && firstErr == nil { firstErr = err } return firstErr } // CleanupAll runs cleanup on all cache instances func (m *Manager) CleanupAll() { m.mu.RLock() defer m.mu.RUnlock() m.tokenCache.Cleanup() m.metadataCache.Cleanup() m.jwkCache.Cleanup() m.sessionCache.Cleanup() m.generalCache.Cleanup() } // SetLogger updates the logger for all caches func (m *Manager) SetLogger(logger Logger) { m.mu.Lock() defer m.mu.Unlock() m.logger = logger if logger != nil { m.tokenCache.logger = logger m.metadataCache.logger = logger m.jwkCache.logger = logger m.sessionCache.logger = logger m.generalCache.logger = logger } }