// Virtual SSD Web Interface JavaScript // Utility functions function showMessage(message, type = 'success') { const messagesDiv = document.getElementById('messages'); const messageDiv = document.createElement('div'); messageDiv.className = `message ${type}`; messageDiv.textContent = message; messagesDiv.appendChild(messageDiv); setTimeout(() => { messageDiv.remove(); }, 5000); } function formatBytes(bytes) { if (bytes === 0) return '0 Bytes'; const k = 1024; const sizes = ['Bytes', 'KB', 'MB', 'GB']; const i = Math.floor(Math.log(bytes) / Math.log(k)); return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]; } function showLoading(containerId) { const container = document.getElementById(containerId); container.innerHTML = `
Loading...
`; } // API functions async function apiCall(url, options = {}) { try { const response = await fetch(url, options); const data = await response.json(); if (!data.success) { throw new Error(data.error || 'Unknown error occurred'); } return data; } catch (error) { console.error('API call failed:', error); showMessage(`Error: ${error.message}`, 'error'); throw error; } } // File operations async function uploadFile() { const fileInput = document.getElementById('fileInput'); const filenameInput = document.getElementById('filenameInput'); if (!fileInput.files.length) { showMessage('Please select a file to upload', 'error'); return; } const file = fileInput.files[0]; const filename = filenameInput.value.trim() || file.name; const formData = new FormData(); formData.append('file', file); try { showMessage('Uploading file...', 'success'); await apiCall(`/api/ssd/files/${encodeURIComponent(filename)}`, { method: 'POST', body: formData }); showMessage(`File "${filename}" uploaded successfully!`, 'success'); fileInput.value = ''; filenameInput.value = ''; refreshFiles(); refreshCapacity(); } catch (error) { // Error already shown by apiCall } } async function downloadFile(filename) { try { const response = await fetch(`/api/ssd/files/${encodeURIComponent(filename)}`); if (!response.ok) { throw new Error('Download failed'); } const blob = await response.blob(); const url = window.URL.createObjectURL(blob); const a = document.createElement('a'); a.href = url; a.download = filename; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); showMessage(`File "${filename}" downloaded successfully!`, 'success'); } catch (error) { showMessage(`Failed to download "${filename}": ${error.message}`, 'error'); } } async function deleteFile(filename) { if (!confirm(`Are you sure you want to delete "${filename}"?`)) { return; } try { await apiCall(`/api/ssd/files/${encodeURIComponent(filename)}`, { method: 'DELETE' }); showMessage(`File "${filename}" deleted successfully!`, 'success'); refreshFiles(); refreshCapacity(); } catch (error) { // Error already shown by apiCall } } async function formatSSD() { if (!confirm('Are you sure you want to format the Virtual SSD? This will delete ALL files!')) { return; } try { await apiCall('/api/ssd/format', { method: 'POST' }); showMessage('Virtual SSD formatted successfully!', 'success'); refreshFiles(); refreshCapacity(); refreshStats(); } catch (error) { // Error already shown by apiCall } } // Display functions async function refreshFiles() { showLoading('filesContainer'); try { const data = await apiCall('/api/ssd/files'); const files = data.files; const container = document.getElementById('filesContainer'); if (Object.keys(files).length === 0) { container.innerHTML = '

No files found on the Virtual SSD

'; return; } container.innerHTML = Object.entries(files).map(([filename, info]) => `
${filename}
Size: ${formatBytes(info.size)}
Blocks: ${info.blocks.length}
`).join(''); } catch (error) { document.getElementById('filesContainer').innerHTML = '

Failed to load files

'; } } async function refreshCapacity() { showLoading('capacityInfo'); try { const data = await apiCall('/api/ssd/capacity'); const capacity = data.capacity; const usagePercent = capacity.usage_percent || 0; document.getElementById('capacityInfo').innerHTML = `

Storage Usage

Total: ${capacity.total_gb} GB

Used: ${capacity.used_gb} GB

Free: ${capacity.free_gb} GB

Usage: ${usagePercent.toFixed(2)}%

`; } catch (error) { document.getElementById('capacityInfo').innerHTML = '

Failed to load capacity information

'; } } async function refreshStats() { showLoading('statsContainer'); try { const data = await apiCall('/api/ssd/stats'); const stats = data.stats; const container = document.getElementById('statsContainer'); container.innerHTML = `
Flash Statistics
Used: ${formatBytes(stats.flash_stats.used_bytes)}
Free: ${formatBytes(stats.flash_stats.free_bytes)}
Usage: ${stats.flash_stats.usage_percent.toFixed(2)}%
Bad Blocks: ${stats.flash_stats.bad_blocks}
File System
Total Blocks: ${stats.file_system_stats.total_blocks.toLocaleString()}
Used Blocks: ${stats.file_system_stats.used_blocks.toLocaleString()}
Free Blocks: ${stats.file_system_stats.free_blocks.toLocaleString()}
FTL Statistics
Logical Blocks: ${stats.ftl_stats.total_logical_blocks.toLocaleString()}
Physical Blocks: ${stats.ftl_stats.total_physical_blocks.toLocaleString()}
Mapped Blocks: ${stats.ftl_stats.mapped_blocks.toLocaleString()}
RAM Buffer
Capacity: ${formatBytes(stats.ram_buffer_stats.capacity_bytes)}
Used: ${formatBytes(stats.ram_buffer_stats.used_bytes)}
Items: ${stats.ram_buffer_stats.items_count}
Hit Rate: ${(stats.ram_buffer_stats.hit_rate * 100).toFixed(2)}%
`; } catch (error) { document.getElementById('statsContainer').innerHTML = '

Failed to load statistics

'; } } // Initialize the page document.addEventListener('DOMContentLoaded', function() { refreshFiles(); refreshCapacity(); refreshStats(); // Auto-refresh every 30 seconds setInterval(() => { refreshCapacity(); }, 30000); });