// 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 = `
`;
}
// 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}
📥 Download
🗑️ Delete
`).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);
});