1/** 2 * Message Cleanup System 3 * Automatically deletes old messages and images to prevent Firebase bloat 4 */ 5 6window.ChatroomMessageCleanup = (function() { 7 'use strict'; 8 9 // Default retention period: 30 days 10 // Can be changed via settings (1-90 days) 11 let retentionDays = 30; 12 let cleanupRunning = false; 13 let lastCleanupTime = null; 14 15 /** 16 * Initialize cleanup system 17 */ 18 function init() { 19 // Load retention period from settings 20 loadRetentionSettings(); 21 22 // Run cleanup on page load (if enough time has passed) 23 checkAndRunCleanup(); 24 25 // Set up periodic cleanup check (every hour) 26 setInterval(() => { 27 checkAndRunCleanup(); 28 }, 60 * 60 * 1000); // 1 hour 29 30 // Also run cleanup when user becomes active (after 5 minutes of inactivity) 31 let activityTimeout; 32 document.addEventListener('mousemove', () => { 33 clearTimeout(activityTimeout); 34 activityTimeout = setTimeout(() => { 35 checkAndRunCleanup(); 36 }, 5 * 60 * 1000); // 5 minutes 37 }); 38 } 39 40 /** 41 * Load retention settings 42 */ 43 function loadRetentionSettings() { 44 try { 45 const saved = localStorage.getItem('chatroom_retention_days'); 46 if (saved) { 47 const days = parseInt(saved, 10); 48 if (days >= 1 && days <= 90) { 49 retentionDays = days; 50 } 51 } 52 } catch (e) { 53 console.error('Error loading retention settings:', e); 54 } 55 } 56 57 /** 58 * Set retention period (in days) 59 */ 60 function setRetentionDays(days) { 61 if (days >= 1 && days <= 90) { 62 retentionDays = days; 63 try { 64 localStorage.setItem('chatroom_retention_days', days.toString()); 65 } catch (e) { 66 console.error('Error saving retention settings:', e); 67 } 68 } 69 } 70 71 /** 72 * Get retention period 73 */ 74 function getRetentionDays() { 75 return retentionDays; 76 } 77 78 /** 79 * Check if cleanup should run and run it if needed 80 */ 81 function checkAndRunCleanup() { 82 // Don't run if already running 83 if (cleanupRunning) return; 84 85 // Check if enough time has passed since last cleanup (at least 1 hour) 86 const now = Date.now(); 87 if (lastCleanupTime && (now - lastCleanupTime) < 60 * 60 * 1000) { 88 return; 89 } 90 91 // Run cleanup 92 runCleanup(); 93 } 94 95 /** 96 * Run cleanup to delete old messages 97 */ 98 async function runCleanup() { 99 if (cleanupRunning) { 100 console.log('Cleanup already running, skipping...'); 101 return; 102 } 103 104 cleanupRunning = true; 105 const cutoffTime = Date.now() - (retentionDays * 24 * 60 * 60 * 1000); 106 107 console.log(`ð§¹ Starting message cleanup (deleting messages older than ${retentionDays} days)...`); 108 109 try { 110 if (!firebase || !firebase.database) { 111 console.error('Firebase not available for cleanup'); 112 cleanupRunning = false; 113 return; 114 } 115 116 const channelsRef = firebase.database().ref('chatroom/channels'); 117 const dmsRef = firebase.database().ref('chatroom/dms'); 118 119 let deletedCount = 0; 120 121 // Cleanup channel messages 122 const channelsSnapshot = await channelsRef.once('value'); 123 if (channelsSnapshot.exists()) { 124 const channels = channelsSnapshot.val(); 125 const cleanupPromises = []; 126 127 for (const channelId in channels) { 128 const messagesRef = channelsRef.child(channelId).child('messages'); 129 const messagesSnapshot = await messagesRef.once('value'); 130 131 if (messagesSnapshot.exists()) { 132 const messages = messagesSnapshot.val(); 133 const deletePromises = []; 134 135 for (const messageId in messages) { 136 const message = messages[messageId]; 137 if (message.timestamp && message.timestamp < cutoffTime) { 138 deletePromises.push( 139 messagesRef.child(messageId).remove() 140 .then(() => { 141 deletedCount++; 142 return true; 143 }) 144 .catch(err => { 145 console.error(`Error deleting message ${messageId}:`, err); 146 return false; 147 }) 148 ); 149 } 150 } 151 152 // Batch delete old messages (limit concurrent operations) 153 if (deletePromises.length > 0) { 154 cleanupPromises.push( 155 Promise.all(deletePromises.slice(0, 50)) // Process 50 at a time 156 ); 157 } 158 } 159 } 160 161 // Wait for all channel cleanups to complete 162 await Promise.all(cleanupPromises); 163 } 164 165 // Cleanup DM messages
166 const dmsSnapshot = await dmsRef.once('value'); 167 if (dmsSnapshot.exists()) { 168 const conversations = dmsSnapshot.val(); 169 const cleanupPromises = []; 170 171 for (const conversationId in conversations) { 172 const messagesRef = dmsRef.child(conversationId).child('messages'); 173 const messagesSnapshot = await messagesRef.once('value'); 174 175 if (messagesSnapshot.exists()) { 176 const messages = messagesSnapshot.val(); 177 const deletePromises = []; 178 179 for (const messageId in messages) { 180 const message = messages[messageId]; 181 if (message.timestamp && message.timestamp < cutoffTime) { 182 deletePromises.push( 183 messagesRef.child(messageId).remove() 184 .then(() => { 185 deletedCount++; 186 return true; 187 }) 188 .catch(err => { 189 console.error(`Error deleting DM message ${messageId}:`, err); 190 return false; 191 }) 192 ); 193 } 194 } 195 196 // Batch delete old messages 197 if (deletePromises.length > 0) { 198 cleanupPromises.push( 199 Promise.all(deletePromises.slice(0, 50)) // Process 50 at a time 200 ); 201 } 202 } 203 } 204 205 // Wait for all DM cleanups to complete 206 await Promise.all(cleanupPromises); 207 } 208 209 lastCleanupTime = Date.now(); 210 console.log(`â Cleanup complete! Deleted ${deletedCount} old messages.`); 211 212 // Show notification if cleanup deleted messages 213 if (deletedCount > 0 && window.ChatroomNotifications) { 214 window.ChatroomNotifications.showToast( 215 `Cleaned up ${deletedCount} old message${deletedCount !== 1 ? 's' : ''}`, 216 'info' 217 ); 218 } 219 220 } catch (error) { 221 console.error('Error during cleanup:', error); 222 } finally { 223 cleanupRunning = false; 224 } 225 } 226 227 /** 228 * Manual cleanup trigger (for testing or immediate cleanup) 229 */ 230 function manualCleanup() { 231 console.log('Manual cleanup triggered'); 232 runCleanup(); 233 } 234 235 /** 236 * Get cleanup status 237 */ 238 function getStatus() { 239 return { 240 retentionDays: retentionDays, 241 lastCleanupTime: lastCleanupTime, 242 isRunning: cleanupRunning 243 }; 244 } 245 246 // Initialize on load 247 if (document.readyState === 'loading') { 248 document.addEventListener('DOMContentLoaded', init); 249 } else { 250 init(); 251 } 252 253 return { 254 init, 255 runCleanup, 256 manualCleanup, 257 setRetentionDays, 258 getRetentionDays, 259 getStatus 260 }; 261})(); 262
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.