123 lines
3.8 KiB
JavaScript
123 lines
3.8 KiB
JavaScript
function loadClients() {
|
|
fetch('clients.php')
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
console.log('Загруженные клиенты:', data);
|
|
renderClientTable(data);
|
|
})
|
|
.catch(error => {
|
|
console.error('Ошибка загрузки данных:', error);
|
|
document.getElementById('client-table').innerHTML = '<tr><td colspan="12">Ошибка загрузки</td></tr>';
|
|
});
|
|
}
|
|
|
|
function renderClientTable(clients) {
|
|
const table = document.getElementById('client-table');
|
|
table.innerHTML = '';
|
|
|
|
const stats = { LZO: 0, ADAPTIVE: 0, STUB: 0, '—': 0 };
|
|
|
|
clients.forEach(client => {
|
|
const row = document.createElement('tr');
|
|
|
|
// TLS ошибка
|
|
if (client.tls_error) {
|
|
row.classList.add('tls-error');
|
|
row.title = client.tls_error;
|
|
}
|
|
|
|
// Сжатие
|
|
const compression = (client.compression || '—').toUpperCase();
|
|
stats[compression] = (stats[compression] || 0) + 1;
|
|
|
|
let compressionClass = 'compression-none';
|
|
if (compression === 'LZO') compressionClass = 'compression-lzo';
|
|
else if (compression === 'ADAPTIVE') compressionClass = 'compression-adaptive';
|
|
else if (compression === 'STUB') compressionClass = 'compression-stub';
|
|
|
|
// Потери
|
|
let lossClass = '';
|
|
if (client.loss_rate >= 10) lossClass = 'loss-high';
|
|
else if (client.loss_rate >= 1) lossClass = 'loss-medium';
|
|
|
|
row.innerHTML = `
|
|
<td>${client.name}</td>
|
|
<td>${client.real_ip}</td>
|
|
<td>${client.virtual_ip}</td>
|
|
<td>${client.connectedSince}</td>
|
|
<td>${formatBytes(client.bytes_received)}</td>
|
|
<td>${formatBytes(client.bytes_sent)}</td>
|
|
<td>${client.statusLabel}</td>
|
|
<td>${client.idleTime || '—'}</td>
|
|
<td class="${compressionClass}">${compression}</td>
|
|
<td>${client.packets_received ?? '—'}</td>
|
|
<td>${client.packets_lost ?? '—'}</td>
|
|
<td class="${lossClass}">${client.loss_rate ?? '—'}%</td>
|
|
`;
|
|
|
|
table.appendChild(row);
|
|
});
|
|
|
|
renderCompressionStats(stats);
|
|
}
|
|
|
|
function renderCompressionStats(stats) {
|
|
const container = document.getElementById('compression-stats');
|
|
container.innerHTML = `
|
|
<strong>Сжатие:</strong>
|
|
LZO: ${stats.LZO || 0},
|
|
Adaptive: ${stats.ADAPTIVE || 0},
|
|
Stub: ${stats.STUB || 0},
|
|
Нет: ${stats['—'] || 0}
|
|
`;
|
|
}
|
|
|
|
function formatBytes(bytes) {
|
|
if (bytes < 1024) return bytes + ' B';
|
|
if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
|
|
return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
|
|
}
|
|
|
|
function loadTlsErrors() {
|
|
fetch('api/tls-errors.php')
|
|
.then(res => res.json())
|
|
.then(data => {
|
|
const container = document.getElementById('tls-errors');
|
|
container.innerHTML = '';
|
|
if (data.tls_errors && data.tls_errors.length > 0) {
|
|
data.tls_errors.forEach(err => {
|
|
const div = document.createElement('div');
|
|
div.textContent = err;
|
|
container.appendChild(div);
|
|
});
|
|
} else {
|
|
container.textContent = 'Нет TLS ошибок.';
|
|
}
|
|
})
|
|
.catch(() => {
|
|
document.getElementById('tls-errors').textContent = 'Ошибка загрузки данных.';
|
|
});
|
|
}
|
|
|
|
document.addEventListener('DOMContentLoaded', () => {
|
|
// Вкладки
|
|
const buttons = document.querySelectorAll('.tab-button');
|
|
const tabs = document.querySelectorAll('.tab-content');
|
|
|
|
buttons.forEach(btn => {
|
|
btn.addEventListener('click', () => {
|
|
buttons.forEach(b => b.classList.remove('active'));
|
|
tabs.forEach(t => t.classList.remove('active'));
|
|
|
|
btn.classList.add('active');
|
|
document.getElementById('tab-' + btn.dataset.tab).classList.add('active');
|
|
});
|
|
});
|
|
|
|
// Загрузка данных
|
|
loadClients();
|
|
loadTlsErrors();
|
|
setInterval(loadClients, 5000);
|
|
setInterval(loadTlsErrors, 10000);
|
|
});
|