// Configuration const API_BASE_URL = '/api'; // Use relative URL const UPDATE_INTERVAL = 1000; // 1 second const DEBUG = true; // Enable debug logging // Debug logger function debug(message, data = null) { if (DEBUG) { if (data) { console.log(`[Debug] ${message}`, data); } else { console.log(`[Debug] ${message}`); } } } // Chart configuration const chartConfig = { hashrate: { data: { labels: [], datasets: [{ label: 'Hashrate (KH/s)', data: [], borderColor: '#2ecc71', tension: 0.4, fill: false }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, grid: { color: 'rgba(255, 255, 255, 0.1)' } }, x: { grid: { color: 'rgba(255, 255, 255, 0.1)' } } }, plugins: { legend: { display: false } } } }, totalHashes: { data: { labels: [], datasets: [{ label: 'Total Hashes', data: [], borderColor: '#3498db', tension: 0.4, fill: false }] }, options: { responsive: true, maintainAspectRatio: false, scales: { y: { beginAtZero: true, grid: { color: 'rgba(255, 255, 255, 0.1)' } }, x: { grid: { color: 'rgba(255, 255, 255, 0.1)' } } }, plugins: { legend: { display: false } } } } }; // DOM Elements const elements = { startButton: document.getElementById('startButton'), stopButton: document.getElementById('stopButton'), statusText: document.getElementById('statusText'), statusDot: document.querySelector('.status-dot'), lastUpdate: document.getElementById('lastUpdate'), hashrateValue: document.getElementById('hashrateValue'), totalHashesValue: document.getElementById('totalHashesValue'), blocksFoundValue: document.getElementById('blocksFoundValue'), difficultyValue: document.getElementById('difficultyValue'), bestHashValue: document.getElementById('bestHashValue'), hashrateChart: document.getElementById('hashrateChart').getContext('2d'), totalHashesChart: document.getElementById('totalHashesChart').getContext('2d') }; // Initialize charts const charts = { hashrate: new Chart(elements.hashrateChart, chartConfig.hashrate), totalHashes: new Chart(elements.totalHashesChart, chartConfig.totalHashes) }; // Helper functions function formatNumber(num) { return num.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); } function updateLastUpdateTime() { const now = new Date(); elements.lastUpdate.textContent = now.toLocaleTimeString(); } function updateStatusIndicator(status) { elements.statusText.textContent = status; elements.statusDot.classList.toggle('active', status === 'Running'); } function updateCharts(hashrate, totalHashes) { const timestamp = new Date().toLocaleTimeString(); // Update hashrate chart if (chartConfig.hashrate.data.labels.length > 20) { chartConfig.hashrate.data.labels.shift(); chartConfig.hashrate.data.datasets[0].data.shift(); } chartConfig.hashrate.data.labels.push(timestamp); chartConfig.hashrate.data.datasets[0].data.push(hashrate); charts.hashrate.update(); // Update total hashes chart if (chartConfig.totalHashes.data.labels.length > 20) { chartConfig.totalHashes.data.labels.shift(); chartConfig.totalHashes.data.datasets[0].data.shift(); } chartConfig.totalHashes.data.labels.push(timestamp); chartConfig.totalHashes.data.datasets[0].data.push(totalHashes); charts.totalHashes.update(); } // API functions async function fetchStatus() { try { debug('Fetching status...'); const response = await fetch(`${API_BASE_URL}/status`); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); debug('Received status data:', data); // Update UI elements.hashrateValue.textContent = data.hashrate.toFixed(2); elements.totalHashesValue.textContent = formatNumber(data.total_hashes); elements.blocksFoundValue.textContent = data.blocks_found; elements.difficultyValue.textContent = formatNumber(data.difficulty); elements.bestHashValue.textContent = data.best_hash || 'None'; updateStatusIndicator(data.status); updateLastUpdateTime(); updateCharts(data.hashrate, data.total_hashes); debug('UI updated successfully'); } catch (error) { console.error('Error fetching status:', error); updateStatusIndicator('Error'); // Show error in UI elements.hashrateValue.textContent = 'ERR'; elements.totalHashesValue.textContent = 'ERR'; elements.blocksFoundValue.textContent = 'ERR'; elements.difficultyValue.textContent = 'ERR'; elements.bestHashValue.textContent = 'Error fetching data'; } } async function startMining() { try { debug('Starting mining...'); elements.startButton.disabled = true; const response = await fetch(`${API_BASE_URL}/start`, { method: 'POST', headers: { 'Content-Type': 'application/json' } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); debug('Mining started:', data); alert(data.message); } catch (error) { console.error('Error starting mining:', error); alert('Failed to start mining: ' + error.message); } finally { elements.startButton.disabled = false; } } async function stopMining() { try { debug('Stopping mining...'); elements.stopButton.disabled = true; const response = await fetch(`${API_BASE_URL}/stop`, { method: 'POST', headers: { 'Content-Type': 'application/json' } }); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } const data = await response.json(); debug('Mining stopped:', data); alert(data.message); } catch (error) { console.error('Error stopping mining:', error); alert('Failed to stop mining: ' + error.message); } finally { elements.stopButton.disabled = false; } } // Event listeners elements.startButton.addEventListener('click', startMining); elements.stopButton.addEventListener('click', stopMining); // Start periodic updates setInterval(fetchStatus, UPDATE_INTERVAL); // Initial status fetch fetchStatus();