auto indent lines

This commit is contained in:
Eduardo Silva 2025-02-25 14:50:22 -03:00
parent f7917c478a
commit d2aa1ef044

View File

@ -1,10 +1,10 @@
{% extends "base.html" %} {% extends "base.html" %}
{% block page_custom_head %} {% block page_custom_head %}
<style> <style>
.peer-extra-info { .peer-extra-info {
display: none; display: none;
} }
</style> </style>
{% endblock %} {% endblock %}
@ -244,208 +244,208 @@
</script> </script>
<script> <script>
var previousMeasurements = {}; var previousMeasurements = {};
var toastShownThisCycle = false; var toastShownThisCycle = false;
const updateThroughput = (peerId, peerInfo) => { const updateThroughput = (peerId, peerInfo) => {
const throughputElement = document.getElementById(`peer-throughput-${peerId}`); const throughputElement = document.getElementById(`peer-throughput-${peerId}`);
const currentTime = Date.now() / 1000; // current timestamp in seconds const currentTime = Date.now() / 1000; // current timestamp in seconds
let formattedThroughput = ''; let formattedThroughput = '';
if (previousMeasurements[peerId]) { if (previousMeasurements[peerId]) {
const prev = previousMeasurements[peerId]; const prev = previousMeasurements[peerId];
const timeDiff = currentTime - prev.timestamp; // time difference in seconds const timeDiff = currentTime - prev.timestamp; // time difference in seconds
// For peer perspective: download corresponds to tx and upload to rx // For peer perspective: download corresponds to tx and upload to rx
let downloadDiff = peerInfo.transfer.tx - prev.transfer.tx; let downloadDiff = peerInfo.transfer.tx - prev.transfer.tx;
let uploadDiff = peerInfo.transfer.rx - prev.transfer.rx; let uploadDiff = peerInfo.transfer.rx - prev.transfer.rx;
// If counters have been reset (current < previous), show toast (only once per cycle) // If counters have been reset (current < previous), show toast (only once per cycle)
if (downloadDiff < 0 || uploadDiff < 0) { if (downloadDiff < 0 || uploadDiff < 0) {
if (!toastShownThisCycle) { if (!toastShownThisCycle) {
$(document).Toasts('create', { $(document).Toasts('create', {
class: 'bg-info', class: 'bg-info',
title: 'info', title: 'info',
body: 'Throughput discarded due to counter reset', body: 'Throughput discarded due to counter reset',
delay: 10000, delay: 10000,
autohide: true autohide: true
}); });
toastShownThisCycle = true; toastShownThisCycle = true;
}
downloadDiff = 0;
uploadDiff = 0;
} }
downloadDiff = 0;
uploadDiff = 0; // Calculate throughput in bytes per second
const downloadThroughput = downloadDiff / timeDiff;
const uploadThroughput = uploadDiff / timeDiff;
// Format throughput values (using convertBytes function)
let downloadDisplay = convertBytes(downloadThroughput) + '/s';
let uploadDisplay = convertBytes(uploadThroughput) + '/s';
// Threshold: 1mb (1 megabit/s = 125000 bytes per second)
const threshold = 125000;
if (downloadThroughput > threshold) {
downloadDisplay = `<strong>${downloadDisplay}</strong>`;
}
if (uploadThroughput > threshold) {
uploadDisplay = `<strong>${uploadDisplay}</strong>`;
}
formattedThroughput = `<i class="fas fa-arrow-down"></i> ${downloadDisplay}, <i class="fas fa-arrow-up"></i> ${uploadDisplay}`;
throughputElement.innerHTML = formattedThroughput;
} else {
// First cycle: no previous measurement available.
formattedThroughput = `<i class="fas fa-arrow-down"></i> -.- B/s, <i class="fas fa-arrow-up"></i> -.- B/s`;
throughputElement.innerHTML = formattedThroughput;
} }
// Calculate throughput in bytes per second previousMeasurements[peerId] = {
const downloadThroughput = downloadDiff / timeDiff; timestamp: currentTime,
const uploadThroughput = uploadDiff / timeDiff; transfer: {
tx: peerInfo.transfer.tx,
rx: peerInfo.transfer.rx
}
};
// Format throughput values (using convertBytes function) return formattedThroughput;
let downloadDisplay = convertBytes(downloadThroughput) + '/s';
let uploadDisplay = convertBytes(uploadThroughput) + '/s';
// Threshold: 1mb (1 megabit/s = 125000 bytes per second)
const threshold = 125000;
if (downloadThroughput > threshold) {
downloadDisplay = `<strong>${downloadDisplay}</strong>`;
}
if (uploadThroughput > threshold) {
uploadDisplay = `<strong>${uploadDisplay}</strong>`;
}
formattedThroughput = `<i class="fas fa-arrow-down"></i> ${downloadDisplay}, <i class="fas fa-arrow-up"></i> ${uploadDisplay}`;
throughputElement.innerHTML = formattedThroughput;
} else {
// First cycle: no previous measurement available.
formattedThroughput = `<i class="fas fa-arrow-down"></i> -.- B/s, <i class="fas fa-arrow-up"></i> -.- B/s`;
throughputElement.innerHTML = formattedThroughput;
}
previousMeasurements[peerId] = {
timestamp: currentTime,
transfer: {
tx: peerInfo.transfer.tx,
rx: peerInfo.transfer.rx
}
}; };
return formattedThroughput; // Convert bytes to human-readable format with abbreviated units
}; const convertBytes = (bytes) => {
if (bytes === 0) return '0 B';
const k = 1024;
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
const i = Math.floor(Math.log(bytes) / Math.log(k));
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};
// Convert bytes to human-readable format with abbreviated units // Fetch Wireguard status and update UI
const convertBytes = (bytes) => { document.addEventListener('DOMContentLoaded', function() {
if (bytes === 0) return '0 B'; const fetchWireguardStatus = async () => {
const k = 1024; try {
const sizes = ['B', 'KB', 'MB', 'GB', 'TB']; const response = await fetch('/api/wireguard_status/');
const i = Math.floor(Math.log(bytes) / Math.log(k)); let data = await response.json();
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
};
// Fetch Wireguard status and update UI // If latest-handshakes is 0, use the stored value
document.addEventListener('DOMContentLoaded', function() { for (const [interfaceName, peers] of Object.entries(data)) {
const fetchWireguardStatus = async () => { for (const [peerId, peerInfo] of Object.entries(peers)) {
try { const peerElementId = `peer-stored-latest-handshake-${peerId}`;
const response = await fetch('/api/wireguard_status/'); const storedHandshakeElement = document.getElementById(peerElementId);
let data = await response.json(); if (peerInfo['latest-handshakes'] === '0' && storedHandshakeElement) {
peerInfo['latest-handshakes'] = storedHandshakeElement.textContent;
}
}
}
// If latest-handshakes is 0, use the stored value updateUI(data);
for (const [interfaceName, peers] of Object.entries(data)) { } catch (error) {
for (const [peerId, peerInfo] of Object.entries(peers)) { console.error('Error fetching Wireguard status:', error);
const peerElementId = `peer-stored-latest-handshake-${peerId}`; }
const storedHandshakeElement = document.getElementById(peerElementId); };
if (peerInfo['latest-handshakes'] === '0' && storedHandshakeElement) {
peerInfo['latest-handshakes'] = storedHandshakeElement.textContent; fetchWireguardStatus();
setInterval(fetchWireguardStatus, {{ current_instance.peer_list_refresh_interval }} * 1000);
});
const updateUI = (data) => {
// Reset the toast flag for this update cycle
toastShownThisCycle = false;
for (const [interfaceName, peers] of Object.entries(data)) {
for (const [peerId, peerInfo] of Object.entries(peers)) {
const peerDiv = document.getElementById(`peer-${peerId}`);
if (peerDiv) {
updatePeerInfo(peerDiv, peerId, peerInfo);
updateCalloutClass(peerDiv, peerInfo['latest-handshakes']);
// Calculate throughput and update the card
const throughputHTML = updateThroughput(peerId, peerInfo);
// If the modal is active for this peer, update its fields as well
const peerUuid = peerDiv.getAttribute("data-uuid");
if ($('#peerPreviewModal').is(':visible') && $('#peerPreviewModal').data('peer-uuid') === peerUuid) {
$('#peerThroughput').html(throughputHTML);
$('#peerTransfer').text(`${convertBytes(peerInfo.transfer.tx)} TX, ${convertBytes(peerInfo.transfer.rx)} RX`);
$('#peerHandshake').text(
peerInfo['latest-handshakes'] !== '0'
? new Date(parseInt(peerInfo['latest-handshakes']) * 1000).toLocaleString()
: '0'
);
$('#peerEndpoints').text(peerInfo.endpoints);
const allowedIpsModalElement = document.getElementById('peerAllowedIPs');
checkAllowedIps(allowedIpsModalElement, peerInfo['allowed-ips']);
} }
} }
} }
updateUI(data);
} catch (error) {
console.error('Error fetching Wireguard status:', error);
} }
}; };
fetchWireguardStatus(); const updatePeerInfo = (peerDiv, peerId, peerInfo) => {
setInterval(fetchWireguardStatus, {{ current_instance.peer_list_refresh_interval }} * 1000); const escapedPeerId = peerId.replace(/([!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g, '\\$1');
}); const transfer = peerDiv.querySelector(`#peer-transfer-${escapedPeerId}`);
const latestHandshake = peerDiv.querySelector(`#peer-latest-handshake-${escapedPeerId}`);
const endpoints = peerDiv.querySelector(`#peer-endpoints-${escapedPeerId}`);
const allowedIps = peerDiv.querySelector(`#peer-allowed-ips-${escapedPeerId}`);
const updateUI = (data) => { transfer.textContent = `${convertBytes(peerInfo.transfer.tx)} TX, ${convertBytes(peerInfo.transfer.rx)} RX`;
// Reset the toast flag for this update cycle latestHandshake.textContent = `${peerInfo['latest-handshakes'] !== '0' ? new Date(parseInt(peerInfo['latest-handshakes']) * 1000).toLocaleString() : '0'}`;
toastShownThisCycle = false; endpoints.textContent = `${peerInfo.endpoints}`;
checkAllowedIps(allowedIps, peerInfo['allowed-ips']);
};
for (const [interfaceName, peers] of Object.entries(data)) { const checkAllowedIps = (allowedIpsElement, allowedIpsApiResponse) => {
for (const [peerId, peerInfo] of Object.entries(peers)) { const apiIps = allowedIpsApiResponse[0].split(' ');
const peerDiv = document.getElementById(`peer-${peerId}`); const htmlIpsText = allowedIpsElement.textContent.trim();
if (peerDiv) { const htmlIpsArray = htmlIpsText.match(/\b(?:\d{1,3}\.){3}\d{1,3}\/\d{1,2}\b/g) || [];
updatePeerInfo(peerDiv, peerId, peerInfo);
updateCalloutClass(peerDiv, peerInfo['latest-handshakes']);
// Calculate throughput and update the card
const throughputHTML = updateThroughput(peerId, peerInfo);
// If the modal is active for this peer, update its fields as well allowedIpsElement.innerHTML = '';
const peerUuid = peerDiv.getAttribute("data-uuid"); let showExtraInfo = false;
if ($('#peerPreviewModal').is(':visible') && $('#peerPreviewModal').data('peer-uuid') === peerUuid) {
$('#peerThroughput').html(throughputHTML); htmlIpsArray.forEach((ip, index, array) => {
$('#peerTransfer').text(`${convertBytes(peerInfo.transfer.tx)} TX, ${convertBytes(peerInfo.transfer.rx)} RX`); const ipSpan = document.createElement('span');
$('#peerHandshake').text( ipSpan.textContent = ip;
peerInfo['latest-handshakes'] !== '0' allowedIpsElement.appendChild(ipSpan);
? new Date(parseInt(peerInfo['latest-handshakes']) * 1000).toLocaleString()
: '0' if (!apiIps.includes(ip)) {
); ipSpan.style.color = 'red';
$('#peerEndpoints').text(peerInfo.endpoints); ipSpan.style.textDecoration = 'underline';
const allowedIpsModalElement = document.getElementById('peerAllowedIPs'); ipSpan.title = 'This address does not appear in the wg show command output, likely indicating that another peer has an IP overlapping this network or that the configuration file is outdated.';
checkAllowedIps(allowedIpsModalElement, peerInfo['allowed-ips']); showExtraInfo = true;
} }
if (index < array.length - 1) {
allowedIpsElement.appendChild(document.createTextNode(', '));
}
});
if (showExtraInfo) {
const extraInfoContainerId = allowedIpsElement.id.replace('peer-allowed-ips-', 'peer-extra-info-allowed-ips-');
const extraInfoContainer = document.getElementById(extraInfoContainerId);
if (extraInfoContainer) {
extraInfoContainer.style.display = 'block';
} }
} }
} };
};
const updatePeerInfo = (peerDiv, peerId, peerInfo) => {
const escapedPeerId = peerId.replace(/([!"#$%&'()*+,.\/:;<=>?@[\]^`{|}~])/g, '\\$1');
const transfer = peerDiv.querySelector(`#peer-transfer-${escapedPeerId}`);
const latestHandshake = peerDiv.querySelector(`#peer-latest-handshake-${escapedPeerId}`);
const endpoints = peerDiv.querySelector(`#peer-endpoints-${escapedPeerId}`);
const allowedIps = peerDiv.querySelector(`#peer-allowed-ips-${escapedPeerId}`);
transfer.textContent = `${convertBytes(peerInfo.transfer.tx)} TX, ${convertBytes(peerInfo.transfer.rx)} RX`;
latestHandshake.textContent = `${peerInfo['latest-handshakes'] !== '0' ? new Date(parseInt(peerInfo['latest-handshakes']) * 1000).toLocaleString() : '0'}`;
endpoints.textContent = `${peerInfo.endpoints}`;
checkAllowedIps(allowedIps, peerInfo['allowed-ips']);
};
const checkAllowedIps = (allowedIpsElement, allowedIpsApiResponse) => {
const apiIps = allowedIpsApiResponse[0].split(' ');
const htmlIpsText = allowedIpsElement.textContent.trim();
const htmlIpsArray = htmlIpsText.match(/\b(?:\d{1,3}\.){3}\d{1,3}\/\d{1,2}\b/g) || [];
allowedIpsElement.innerHTML = '';
let showExtraInfo = false;
htmlIpsArray.forEach((ip, index, array) => {
const ipSpan = document.createElement('span');
ipSpan.textContent = ip;
allowedIpsElement.appendChild(ipSpan);
if (!apiIps.includes(ip)) {
ipSpan.style.color = 'red';
ipSpan.style.textDecoration = 'underline';
ipSpan.title = 'This address does not appear in the wg show command output, likely indicating that another peer has an IP overlapping this network or that the configuration file is outdated.';
showExtraInfo = true;
}
if (index < array.length - 1) {
allowedIpsElement.appendChild(document.createTextNode(', '));
}
});
if (showExtraInfo) {
const extraInfoContainerId = allowedIpsElement.id.replace('peer-allowed-ips-', 'peer-extra-info-allowed-ips-');
const extraInfoContainer = document.getElementById(extraInfoContainerId);
if (extraInfoContainer) {
extraInfoContainer.style.display = 'block';
}
}
};
const updateCalloutClass = (peerDiv, latestHandshake) => { const updateCalloutClass = (peerDiv, latestHandshake) => {
const calloutDiv = peerDiv.querySelector('.callout'); const calloutDiv = peerDiv.querySelector('.callout');
calloutDiv.classList.remove('callout-success', 'callout-info', 'callout-warning', 'callout-danger'); calloutDiv.classList.remove('callout-success', 'callout-info', 'callout-warning', 'callout-danger');
const handshakeAge = Date.now() / 1000 - parseInt(latestHandshake); const handshakeAge = Date.now() / 1000 - parseInt(latestHandshake);
if (latestHandshake === '0') { if (latestHandshake === '0') {
calloutDiv.classList.add('callout-danger'); calloutDiv.classList.add('callout-danger');
} else if (handshakeAge < 600) { } else if (handshakeAge < 600) {
calloutDiv.classList.add('callout-success'); calloutDiv.classList.add('callout-success');
} else if (handshakeAge < 1800) { } else if (handshakeAge < 1800) {
calloutDiv.classList.add('callout-info'); calloutDiv.classList.add('callout-info');
} else if (handshakeAge < 21600) { } else if (handshakeAge < 21600) {
calloutDiv.classList.add('callout-warning'); calloutDiv.classList.add('callout-warning');
} }
calloutDiv.style.transition = 'all 5s'; calloutDiv.style.transition = 'all 5s';
}; };
</script> </script>
<script> <script>
$(document).ready(function(){ $(document).ready(function(){