File size: 4,476 Bytes
5da4770 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
import { FileCache } from '@/hooks/use-cached-file';
/**
* Initialize cache maintenance routines
* - Sets up interval to clean expired cache entries
* - Adds event handlers for visibility and page unload
*/
export function initializeCacheSystem() {
// Clean up expired cache entries every 5 minutes
const CLEANUP_INTERVAL = 5 * 60 * 1000; // 5 minutes
// Cache entry expiration
const DEFAULT_EXPIRATION = 30 * 60 * 1000; // 30 minutes
// Keep track of our interval
let cleanupInterval: NodeJS.Timeout | null = null;
// Clean up function to remove expired entries and release blob URLs
const cleanupCache = () => {
const now = Date.now();
let blobUrlsToRevoke: string[] = [];
// This is the implementation detail of how we access the Map inside the FileCache
// We can't modify it directly, but we need to iterate through it for cleanup
const cache = (FileCache as any).cache;
if (cache && typeof cache.forEach === 'function') {
const keysToDelete: string[] = [];
cache.forEach((entry: any, key: string) => {
// Check if the entry has expired
if (now - entry.timestamp > DEFAULT_EXPIRATION) {
keysToDelete.push(key);
// If it's a blob URL, add it to our revocation list
if (entry.type === 'url' && typeof entry.content === 'string' && entry.content.startsWith('blob:')) {
blobUrlsToRevoke.push(entry.content);
}
}
});
// Delete expired keys
keysToDelete.forEach(key => {
FileCache.delete(key);
});
// Revoke blob URLs
blobUrlsToRevoke.forEach(url => {
try {
URL.revokeObjectURL(url);
} catch (err) {
console.error(`Failed to revoke blob URL: ${url}`, err);
}
});
if (keysToDelete.length > 0) {
console.log(`Cache cleanup: removed ${keysToDelete.length} expired entries`);
}
}
};
// Set up visibility change handler to clean cache when page becomes visible again
const handleVisibilityChange = () => {
if (document.visibilityState === 'visible') {
// User returned to the page, run a cleanup
cleanupCache();
}
};
// Clean all blob URLs before page unload to prevent memory leaks
const handleBeforeUnload = () => {
// This is more aggressive as we're about to unload anyway
const cache = (FileCache as any).cache;
if (cache && typeof cache.forEach === 'function') {
cache.forEach((entry: any) => {
if (entry.type === 'url' && typeof entry.content === 'string' && entry.content.startsWith('blob:')) {
try {
URL.revokeObjectURL(entry.content);
} catch (err) {
// Ignore errors during page unload
}
}
});
}
};
// Start the cleanup interval
const startCleanupInterval = () => {
// Clear any existing interval first
if (cleanupInterval) {
clearInterval(cleanupInterval);
}
// Set new interval
cleanupInterval = setInterval(cleanupCache, CLEANUP_INTERVAL);
};
// Initialize event listeners
const initEventListeners = () => {
document.addEventListener('visibilitychange', handleVisibilityChange);
window.addEventListener('beforeunload', handleBeforeUnload);
};
// Remove event listeners
const removeEventListeners = () => {
document.removeEventListener('visibilitychange', handleVisibilityChange);
window.removeEventListener('beforeunload', handleBeforeUnload);
if (cleanupInterval) {
clearInterval(cleanupInterval);
cleanupInterval = null;
}
};
// Initialize the cache system
startCleanupInterval();
initEventListeners();
// Return a cleanup function
return {
stopCacheSystem: removeEventListeners,
clearCache: () => {
// Revoke all blob URLs before clearing
const cache = (FileCache as any).cache;
if (cache && typeof cache.forEach === 'function') {
cache.forEach((entry: any) => {
if (entry.type === 'url' && typeof entry.content === 'string' && entry.content.startsWith('blob:')) {
try {
URL.revokeObjectURL(entry.content);
} catch (err) {
console.error('Failed to revoke URL during cache clear', err);
}
}
});
}
// Clear the cache
FileCache.clear();
}
};
} |