Skip to content

Commit 412c5cb

Browse files
committed
Web UI: ditch JSON-P. Use fetch() for everything, it's 2026.
1 parent af9a1d2 commit 412c5cb

1 file changed

Lines changed: 32 additions & 143 deletions

File tree

dnscrypt-proxy/static/js/monitoring.js

Lines changed: 32 additions & 143 deletions
Original file line numberDiff line numberDiff line change
@@ -389,74 +389,35 @@ function formatSourceStatus(status, error) {
389389
return label;
390390
}
391391

392-
// Simple direct data loading approach
393-
function loadData() {
394-
console.log('Loading data using simple approach');
395-
396-
// Create a script element to load the data
397-
var script = document.createElement('script');
398-
script.src = '/api/metrics?callback=handleMetricsData&_=' + new Date().getTime();
399-
script.onerror = function(e) {
400-
console.error('Script load error:', e);
401-
handleError(new Error('Failed to load metrics data'));
402-
403-
// Try again after 5 seconds
404-
setTimeout(loadData, 5000);
405-
};
406-
407-
// Add the script to the document
408-
document.body.appendChild(script);
409-
410-
// Remove the script after a timeout (whether it loaded or not)
411-
setTimeout(function() {
412-
if (script.parentNode) {
413-
script.parentNode.removeChild(script);
392+
function fetchMetrics() {
393+
return fetch('/api/metrics', {
394+
credentials: 'same-origin',
395+
cache: 'no-store',
396+
headers: { 'Accept': 'application/json' },
397+
}).then(function(response) {
398+
if (!response.ok) {
399+
throw new Error('HTTP ' + response.status);
414400
}
415-
}, 10000);
401+
return response.json();
402+
});
416403
}
417404

418-
// Callback function for the JSONP-style request
419-
window.handleMetricsData = function(data) {
420-
console.log('Data received via JSONP');
421-
if (data) {
422-
safeUpdateDashboard(data);
423-
} else {
424-
console.error('Empty data received');
425-
handleError(new Error('Empty data received'));
426-
}
427-
};
405+
function loadData() {
406+
fetchMetrics().then(function(data) {
407+
if (data) {
408+
safeUpdateDashboard(data);
409+
} else {
410+
handleError(new Error('Empty data received'));
411+
}
412+
}).catch(function(err) {
413+
console.error('Initial metrics load failed:', err);
414+
handleError(err);
415+
setTimeout(loadData, 5000);
416+
});
417+
}
428418

429-
// Start loading data
430419
loadData();
431420

432-
// Fallback: If data doesn't load within 10 seconds, try direct XHR
433-
setTimeout(function() {
434-
var loadingIndicator = document.getElementById('loading-indicator');
435-
if (loadingIndicator && loadingIndicator.style.display !== 'none') {
436-
console.log('Loading indicator still visible after 10s, trying direct XHR');
437-
438-
var xhr = new XMLHttpRequest();
439-
xhr.open('GET', '/api/metrics', true);
440-
xhr.timeout = 10000;
441-
442-
xhr.onload = function() {
443-
if (xhr.status >= 200 && xhr.status < 300) {
444-
try {
445-
var data = JSON.parse(xhr.responseText);
446-
if (data) {
447-
console.log('XHR fallback succeeded');
448-
safeUpdateDashboard(data);
449-
}
450-
} catch (e) {
451-
console.error('XHR fallback parse error:', e);
452-
}
453-
}
454-
};
455-
456-
xhr.send();
457-
}
458-
}, 10000);
459-
460421
// WebSocket connection with error handling and reconnection
461422
let wsReconnectAttempts = 0;
462423
const maxReconnectAttempts = 5;
@@ -552,42 +513,19 @@ function connectWebSocket() {
552513
// Start WebSocket connection
553514
let ws = connectWebSocket();
554515

555-
// Polling function with error handling - using script tag approach
556516
function pollMetrics() {
557-
console.log('Polling metrics...');
558-
559-
if (!ws || ws.readyState !== WebSocket.OPEN) {
560-
// Use script tag approach for better compatibility
561-
var pollScript = document.createElement('script');
562-
pollScript.src = '/api/metrics?callback=handlePollData&_=' + new Date().getTime();
563-
564-
// Handle errors
565-
pollScript.onerror = function(e) {
566-
console.error('Polling script load error:', e);
567-
};
568-
569-
// Add the script to the document
570-
document.body.appendChild(pollScript);
571-
572-
// Remove the script after a timeout
573-
setTimeout(function() {
574-
if (pollScript.parentNode) {
575-
pollScript.parentNode.removeChild(pollScript);
576-
}
577-
}, 5000);
517+
if (ws && ws.readyState === WebSocket.OPEN) {
518+
return;
578519
}
520+
fetchMetrics().then(function(data) {
521+
if (data) {
522+
safeUpdateDashboard(data);
523+
}
524+
}).catch(function(err) {
525+
console.error('Polling metrics failed:', err);
526+
});
579527
}
580528

581-
// Callback function for polling
582-
window.handlePollData = function(data) {
583-
if (data) {
584-
console.log('Polling data received successfully');
585-
safeUpdateDashboard(data);
586-
} else {
587-
console.warn('Received empty data from polling');
588-
}
589-
};
590-
591529
// Initialize dashboard with default values
592530
function initializeDashboard() {
593531
updateElementText('total-queries', '0');
@@ -609,53 +547,4 @@ function initializeDashboard() {
609547
// Initialize with default values
610548
initializeDashboard();
611549

612-
// Refresh data every 5 seconds as a fallback if WebSocket fails
613550
setInterval(pollMetrics, 5000);
614-
615-
// Ultimate fallback: If nothing works after 20 seconds, create an iframe
616-
setTimeout(function() {
617-
var loadingIndicator = document.getElementById('loading-indicator');
618-
if (loadingIndicator && loadingIndicator.style.display !== 'none') {
619-
console.log('Still no data after 20s, trying iframe approach');
620-
621-
// Create a message for the user
622-
loadingIndicator.innerHTML = '<h2>Loading Data...</h2>' +
623-
'<p>We\'re having trouble loading data directly. Trying alternative method...</p>' +
624-
'<div id="iframe-container" style="display: none;"></div>';
625-
626-
// Create an iframe to load the metrics directly
627-
var iframe = document.createElement('iframe');
628-
iframe.style.display = 'none';
629-
iframe.src = '/api/metrics';
630-
631-
// When the iframe loads, try to extract the data
632-
iframe.onload = function() {
633-
try {
634-
console.log('Iframe loaded, attempting to extract data');
635-
636-
// Try to get the content
637-
var iframeContent = iframe.contentDocument || iframe.contentWindow.document;
638-
var jsonText = iframeContent.body.innerText || iframeContent.body.textContent;
639-
640-
if (jsonText) {
641-
var data = JSON.parse(jsonText);
642-
console.log('Successfully extracted data from iframe');
643-
safeUpdateDashboard(data);
644-
}
645-
} catch (e) {
646-
console.error('Error extracting data from iframe:', e);
647-
648-
// Last resort: just hide the loading indicator and show whatever we have
649-
loadingIndicator.style.display = 'none';
650-
}
651-
};
652-
653-
// Add the iframe to the page
654-
document.getElementById('iframe-container').appendChild(iframe);
655-
656-
// Set a timeout to hide the loading indicator regardless
657-
setTimeout(function() {
658-
loadingIndicator.style.display = 'none';
659-
}, 5000);
660-
}
661-
}, 20000);

0 commit comments

Comments
 (0)