refactor(auth): Replace custom cache with shared CacheManager
This commit is contained in:
@@ -1,198 +1,131 @@
|
||||
import 'auth_state_manager.dart';
|
||||
import '../services/cache_manager.dart';
|
||||
import '../utils/debug_logger.dart';
|
||||
import 'auth_state_manager.dart';
|
||||
|
||||
/// Comprehensive caching manager for auth-related operations
|
||||
/// Reduces redundant operations and improves app performance
|
||||
/// Comprehensive caching manager for auth-related operations.
|
||||
///
|
||||
/// Delegates to the shared [CacheManager] to keep TTL and eviction behavior
|
||||
/// consistent across the app.
|
||||
class AuthCacheManager {
|
||||
static final AuthCacheManager _instance = AuthCacheManager._internal();
|
||||
factory AuthCacheManager() => _instance;
|
||||
AuthCacheManager._internal();
|
||||
|
||||
// Cache for various auth-related operations
|
||||
final Map<String, dynamic> _cache = {};
|
||||
final Map<String, DateTime> _cacheTimestamps = {};
|
||||
static const Duration _shortCache = Duration(minutes: 2);
|
||||
static const Duration _mediumCache = Duration(minutes: 5);
|
||||
static const Duration _longCache = Duration(minutes: 15);
|
||||
|
||||
// Cache timeouts for different types of data
|
||||
static const Duration _shortCache = Duration(
|
||||
minutes: 2,
|
||||
); // For frequently changing data
|
||||
static const Duration _mediumCache = Duration(
|
||||
minutes: 5,
|
||||
); // For moderately stable data
|
||||
static const Duration _longCache = Duration(minutes: 15); // For stable data
|
||||
|
||||
// Cache keys
|
||||
static const String _userDataKey = 'user_data';
|
||||
static const String _serverConnectionKey = 'server_connection';
|
||||
static const String _credentialsExistKey = 'credentials_exist';
|
||||
static const String _serverConfigsKey = 'server_configs';
|
||||
static const String _authStatusKey = 'auth_status';
|
||||
|
||||
final CacheManager _cache = CacheManager(
|
||||
defaultTtl: _mediumCache,
|
||||
maxEntries: 32,
|
||||
);
|
||||
|
||||
/// Cache user data with medium timeout
|
||||
void cacheUserData(dynamic userData) {
|
||||
_cache[_userDataKey] = userData;
|
||||
_cacheTimestamps[_userDataKey] = DateTime.now();
|
||||
_cache.write<dynamic>(_userDataKey, userData, ttl: _mediumCache);
|
||||
DebugLogger.storage('User data cached');
|
||||
}
|
||||
|
||||
/// Get cached user data
|
||||
dynamic getCachedUserData() {
|
||||
if (_isCacheValid(_userDataKey, _mediumCache)) {
|
||||
final (hit: hit, value: user) = _cache.lookup<dynamic>(_userDataKey);
|
||||
if (hit) {
|
||||
DebugLogger.storage('Using cached user data');
|
||||
return _cache[_userDataKey];
|
||||
}
|
||||
return null;
|
||||
return user;
|
||||
}
|
||||
|
||||
/// Cache server connection status with short timeout
|
||||
void cacheServerConnection(bool isConnected) {
|
||||
_cache[_serverConnectionKey] = isConnected;
|
||||
_cacheTimestamps[_serverConnectionKey] = DateTime.now();
|
||||
_cache.write<bool>(_serverConnectionKey, isConnected, ttl: _shortCache);
|
||||
}
|
||||
|
||||
/// Get cached server connection status
|
||||
bool? getCachedServerConnection() {
|
||||
if (_isCacheValid(_serverConnectionKey, _shortCache)) {
|
||||
return _cache[_serverConnectionKey] as bool?;
|
||||
}
|
||||
return null;
|
||||
final (hit: hit, value: connection) = _cache.lookup<bool>(
|
||||
_serverConnectionKey,
|
||||
);
|
||||
return hit ? connection : null;
|
||||
}
|
||||
|
||||
/// Cache credentials existence with medium timeout
|
||||
void cacheCredentialsExist(bool exist) {
|
||||
_cache[_credentialsExistKey] = exist;
|
||||
_cacheTimestamps[_credentialsExistKey] = DateTime.now();
|
||||
_cache.write<bool>(_credentialsExistKey, exist, ttl: _mediumCache);
|
||||
}
|
||||
|
||||
/// Get cached credentials existence
|
||||
bool? getCachedCredentialsExist() {
|
||||
if (_isCacheValid(_credentialsExistKey, _mediumCache)) {
|
||||
return _cache[_credentialsExistKey] as bool?;
|
||||
}
|
||||
return null;
|
||||
final (hit: hit, value: hasCreds) = _cache.lookup<bool>(
|
||||
_credentialsExistKey,
|
||||
);
|
||||
return hit ? hasCreds : null;
|
||||
}
|
||||
|
||||
/// Cache server configurations with long timeout
|
||||
void cacheServerConfigs(List<dynamic> configs) {
|
||||
_cache[_serverConfigsKey] = configs;
|
||||
_cacheTimestamps[_serverConfigsKey] = DateTime.now();
|
||||
_cache.write<List<dynamic>>(_serverConfigsKey, configs, ttl: _longCache);
|
||||
}
|
||||
|
||||
/// Get cached server configurations
|
||||
List<dynamic>? getCachedServerConfigs() {
|
||||
if (_isCacheValid(_serverConfigsKey, _longCache)) {
|
||||
return _cache[_serverConfigsKey] as List<dynamic>?;
|
||||
}
|
||||
return null;
|
||||
final (hit: hit, value: configs) = _cache.lookup<List<dynamic>>(
|
||||
_serverConfigsKey,
|
||||
);
|
||||
return hit ? configs : null;
|
||||
}
|
||||
|
||||
/// Check if cache entry is valid
|
||||
bool _isCacheValid(String key, Duration timeout) {
|
||||
final timestamp = _cacheTimestamps[key];
|
||||
if (timestamp == null) return false;
|
||||
|
||||
return DateTime.now().difference(timestamp) < timeout;
|
||||
}
|
||||
|
||||
/// Clear specific cache entry
|
||||
void clearCacheEntry(String key) {
|
||||
_cache.remove(key);
|
||||
_cacheTimestamps.remove(key);
|
||||
_cache.invalidate(key);
|
||||
DebugLogger.storage('Cache entry cleared: $key');
|
||||
}
|
||||
|
||||
/// Clear all auth-related cache including server configs
|
||||
void clearAuthCache() {
|
||||
_cache.clear();
|
||||
_cacheTimestamps.clear();
|
||||
DebugLogger.storage('All auth cache cleared (including server configs and custom headers)');
|
||||
}
|
||||
|
||||
/// Clear expired cache entries
|
||||
void cleanExpiredCache() {
|
||||
final now = DateTime.now();
|
||||
final expiredKeys = <String>[];
|
||||
|
||||
for (final entry in _cacheTimestamps.entries) {
|
||||
// Use the longest timeout for cleanup to be conservative
|
||||
if (now.difference(entry.value) > _longCache) {
|
||||
expiredKeys.add(entry.key);
|
||||
}
|
||||
}
|
||||
|
||||
for (final key in expiredKeys) {
|
||||
_cache.remove(key);
|
||||
_cacheTimestamps.remove(key);
|
||||
}
|
||||
|
||||
if (expiredKeys.isNotEmpty) {
|
||||
DebugLogger.storage(
|
||||
'Cleaned ${expiredKeys.length} expired cache entries',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get cache statistics for monitoring
|
||||
Map<String, dynamic> getCacheStats() {
|
||||
final now = DateTime.now();
|
||||
final stats = <String, dynamic>{};
|
||||
|
||||
stats['totalEntries'] = _cache.length;
|
||||
stats['entries'] = <String, Map<String, dynamic>>{};
|
||||
|
||||
for (final key in _cache.keys) {
|
||||
final timestamp = _cacheTimestamps[key];
|
||||
if (timestamp != null) {
|
||||
stats['entries'][key] = {
|
||||
'age': now.difference(timestamp).inSeconds,
|
||||
'hasData': _cache[key] != null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return stats;
|
||||
}
|
||||
|
||||
/// Optimize cache by removing least recently used entries if cache gets too large
|
||||
void optimizeCache() {
|
||||
const maxCacheSize = 20; // Reasonable limit for auth cache
|
||||
|
||||
if (_cache.length <= maxCacheSize) return;
|
||||
|
||||
// Sort by timestamp (oldest first)
|
||||
final sortedEntries = _cacheTimestamps.entries.toList()
|
||||
..sort((a, b) => a.value.compareTo(b.value));
|
||||
|
||||
// Remove oldest entries
|
||||
final entriesToRemove = sortedEntries.length - maxCacheSize;
|
||||
for (int i = 0; i < entriesToRemove; i++) {
|
||||
final key = sortedEntries[i].key;
|
||||
_cache.remove(key);
|
||||
_cacheTimestamps.remove(key);
|
||||
}
|
||||
|
||||
DebugLogger.storage(
|
||||
'Cache optimized, removed $entriesToRemove old entries',
|
||||
'All auth cache cleared (including server configs and custom headers)',
|
||||
);
|
||||
}
|
||||
|
||||
/// Cache state from AuthState for quick access
|
||||
void cleanExpiredCache() {
|
||||
final stats = _cache.stats();
|
||||
final entries = stats['entries'];
|
||||
if (entries is! Map<String, dynamic>) return;
|
||||
|
||||
var expiredCount = 0;
|
||||
entries.forEach((key, value) {
|
||||
if (value is! Map) return;
|
||||
final ageSeconds = value['ageSeconds'];
|
||||
final ttlSeconds = value['ttlSeconds'];
|
||||
if (ageSeconds is num && ttlSeconds is num && ageSeconds > ttlSeconds) {
|
||||
_cache.invalidate(key);
|
||||
expiredCount++;
|
||||
}
|
||||
});
|
||||
|
||||
if (expiredCount > 0) {
|
||||
DebugLogger.storage('Cleaned $expiredCount expired auth cache entries');
|
||||
}
|
||||
}
|
||||
|
||||
Map<String, dynamic> getCacheStats() => _cache.stats();
|
||||
|
||||
void optimizeCache() {
|
||||
// CacheManager enforces maxEntries using LRU; no extra work needed.
|
||||
}
|
||||
|
||||
void cacheAuthState(AuthState authState) {
|
||||
if (authState.user != null) {
|
||||
cacheUserData(authState.user);
|
||||
}
|
||||
|
||||
// Don't cache loading or error states
|
||||
if (authState.status == AuthStatus.authenticated) {
|
||||
_cache['auth_status'] = authState.status;
|
||||
_cacheTimestamps['auth_status'] = DateTime.now();
|
||||
_cache.write<AuthStatus>(
|
||||
_authStatusKey,
|
||||
authState.status,
|
||||
ttl: _shortCache,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get cached auth status
|
||||
AuthStatus? getCachedAuthStatus() {
|
||||
if (_isCacheValid('auth_status', _shortCache)) {
|
||||
return _cache['auth_status'] as AuthStatus?;
|
||||
}
|
||||
return null;
|
||||
final (hit: hit, value: status) = _cache.lookup<AuthStatus>(_authStatusKey);
|
||||
return hit ? status : null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user