Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m27s
129 lines
4.8 KiB
JavaScript
129 lines
4.8 KiB
JavaScript
/**
|
|
* Роуты для сбора статистики трафика с MikroTik RouterOS (интерфейсы по jumphost).
|
|
* GET /api/traffic/interface-stats — статистика rx/tx по каждому интерфейсу для всех jumphost.
|
|
*/
|
|
|
|
const { sendError } = require('../middleware/errorHandler');
|
|
const { decrypt } = require('../utils/encryption');
|
|
const { readServersFromS3 } = require('./serversRoutes');
|
|
const { createRosClient } = require('../services/mikrotikApplyService');
|
|
|
|
/** Получить MikroTik credentials из сервера (jumphost или home) */
|
|
function getMikrotikCredentials(server) {
|
|
if (!server || (server.type !== 'jumphost' && server.type !== 'home')) return null;
|
|
const host = server.mikrotikHost || server.ip || server.dns;
|
|
if (!host) return null;
|
|
const port = server.mikrotikPort;
|
|
const restPort = (port === 80 || port === 443 || port === 8443) ? port : 80;
|
|
const user = server.mikrotikUser || 'admin';
|
|
let password = '';
|
|
if (server.encryptedMikrotikPassword) {
|
|
try {
|
|
password = decrypt(server.encryptedMikrotikPassword);
|
|
} catch (_) {
|
|
return null;
|
|
}
|
|
}
|
|
return { host, port: restPort, user, password, secure: false };
|
|
}
|
|
|
|
// UI-настройки (общие с остальным UI)
|
|
const UI_SETTINGS_KEY = 'bgp_data/rt_ui_settings.json';
|
|
const INTERFACE_SPEED_CACHE_PREFIX = 'interface-speed-cache/';
|
|
|
|
async function loadUiSettings() {
|
|
try {
|
|
const data = await readS3TextObject(UI_SETTINGS_KEY).catch(() => ({ body: '{}' }));
|
|
const parsed = JSON.parse(data?.body || '{}');
|
|
return parsed && typeof parsed === 'object' ? parsed : {};
|
|
} catch (_) {
|
|
return {};
|
|
}
|
|
}
|
|
|
|
function interfaceSpeedCacheKey(serverId, interfaceName) {
|
|
const key = `${serverId || ''}|${interfaceName || ''}`;
|
|
// Хэш не нужен: ключи короткие, но на всякий случай экранируем странные символы
|
|
return (
|
|
INTERFACE_SPEED_CACHE_PREFIX +
|
|
String(key)
|
|
.trim()
|
|
.replace(/[^a-zA-Z0-9_.:-]+/g, '_') +
|
|
'.json'
|
|
);
|
|
}
|
|
|
|
function sleep(ms) {
|
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
}
|
|
|
|
/**
|
|
* GET /api/traffic/interface-stats
|
|
* Возвращает по каждому jumphost список интерфейсов с rx-byte, tx-byte (из RouterOS REST /interface).
|
|
*/
|
|
async function getInterfaceStats(req, res) {
|
|
try {
|
|
const servers = await readServersFromS3();
|
|
const jumphosts = (Array.isArray(servers) ? servers : []).filter(
|
|
(s) => s && (String(s.type || '').toLowerCase() === 'jumphost' || String(s.type || '').toLowerCase() === 'home')
|
|
);
|
|
|
|
const results = await Promise.all(
|
|
jumphosts.map(async (server) => {
|
|
const creds = getMikrotikCredentials(server);
|
|
if (!creds) {
|
|
return {
|
|
serverId: server.id,
|
|
name: server.name || server.dns || server.ip || server.id,
|
|
host: server.mikrotikHost || server.ip || server.dns,
|
|
error: 'MikroTik API не настроен или нет пароля',
|
|
interfaces: [],
|
|
};
|
|
}
|
|
try {
|
|
const client = createRosClient(creds);
|
|
const apiRes = await client.print('interface');
|
|
const raw = apiRes?.data;
|
|
const list = Array.isArray(raw) ? raw : raw ? [raw] : [];
|
|
const interfaces = list.map((iface) => {
|
|
const rx = iface['rx-byte'] != null ? parseInt(String(iface['rx-byte']), 10) : 0;
|
|
const tx = iface['tx-byte'] != null ? parseInt(String(iface['tx-byte']), 10) : 0;
|
|
const total = rx + tx;
|
|
return {
|
|
name: iface.name != null ? String(iface.name) : '',
|
|
type: iface.type != null ? String(iface.type) : '',
|
|
rxBytes: Number.isNaN(rx) ? 0 : rx,
|
|
txBytes: Number.isNaN(tx) ? 0 : tx,
|
|
totalBytes: Number.isNaN(total) ? 0 : total,
|
|
};
|
|
}).filter((i) => i.name && i.totalBytes >= 0);
|
|
return {
|
|
serverId: server.id,
|
|
name: server.name || server.dns || server.ip || server.id,
|
|
host: server.mikrotikHost || server.ip || server.dns,
|
|
interfaces,
|
|
};
|
|
} catch (err) {
|
|
const msg = err.response?.data?.message || err.message || 'Ошибка запроса к RouterOS';
|
|
return {
|
|
serverId: server.id,
|
|
name: server.name || server.dns || server.ip || server.id,
|
|
host: server.mikrotikHost || server.ip || server.dns,
|
|
error: msg,
|
|
interfaces: [],
|
|
};
|
|
}
|
|
})
|
|
);
|
|
|
|
return res.json({ jumphosts: results });
|
|
} catch (error) {
|
|
console.error('getInterfaceStats:', error);
|
|
return sendError(res, 500, error.message || 'Ошибка сбора статистики трафика', 'E_TRAFFIC');
|
|
}
|
|
}
|
|
|
|
module.exports = {
|
|
getInterfaceStats,
|
|
};
|