From 99b346fd940f2550b8e93de473dab45e4171dc59 Mon Sep 17 00:00:00 2001 From: shats Date: Tue, 17 Feb 2026 23:22:38 +0700 Subject: [PATCH] refactor(TrafficRoutes): remove deprecated interface statistics and speed test functions; streamline MikroTik credentials retrieval --- backend/routes/trafficRoutes.js | 311 -------------------------------- 1 file changed, 311 deletions(-) diff --git a/backend/routes/trafficRoutes.js b/backend/routes/trafficRoutes.js index 0ee8f6e..1df81ca 100644 --- a/backend/routes/trafficRoutes.js +++ b/backend/routes/trafficRoutes.js @@ -8,125 +8,6 @@ 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 }; -} - -/** - * 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, -}; - -/** - * Роуты для сбора статистики трафика с 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'); -const { readS3TextObject, writeS3JsonObject } = require('../services/s3Service'); - /** Получить MikroTik credentials из сервера (jumphost или home) */ function getMikrotikCredentials(server) { if (!server || (server.type !== 'jumphost' && server.type !== 'home')) return null; @@ -242,198 +123,6 @@ async function getInterfaceStats(req, res) { } } -/** - * POST /api/traffic/interface-speed-test - * Замеряет среднюю скорость по выбранному интерфейсу RouterOS на jumphost/home. - * - * Body: - * - serverId (обязательный) — id/dns/ip сервера из servers.json - * - interfaceName (обязательный) — имя интерфейса в RouterOS (как в /interface) - * - durationSeconds? — время замера (по умолчанию из ui-settings.interfaceSpeedTestDurationSeconds или 10 сек) - * - * Использует счётчики rx-byte/tx-byte: берёт значение в начале и в конце интервала - * и делит дельту на время замера. - */ -async function measureInterfaceSpeed(req, res) { - try { - const { serverId, interfaceName } = req.body || {}; - let { durationSeconds } = req.body || {}; - - if (!serverId || !interfaceName) { - return sendError( - res, - 400, - 'serverId и interfaceName обязательны', - 'E_BAD_REQUEST' - ); - } - - const uiSettings = await loadUiSettings(); - const defaultDuration = Math.max( - 1, - Math.min( - 600, - parseInt(uiSettings.interfaceSpeedTestDurationSeconds, 10) || 10 - ) - ); - durationSeconds = Math.max( - 1, - Math.min( - 600, - parseInt(durationSeconds != null ? durationSeconds : defaultDuration, 10) || - defaultDuration - ) - ); - - const cacheMinutes = Math.max( - 0, - parseInt(uiSettings.interfaceSpeedTestCacheMinutes, 10) || 0 - ); - const cacheKey = - cacheMinutes > 0 - ? interfaceSpeedCacheKey(serverId, interfaceName) - : null; - - if (cacheKey) { - try { - const raw = await readS3TextObject(cacheKey).catch(() => null); - if (raw?.body) { - const cached = JSON.parse(raw.body); - const cachedAt = - typeof cached.cachedAt === 'number' ? cached.cachedAt : 0; - const ttlMs = cacheMinutes * 60 * 1000; - if (cachedAt && Date.now() - cachedAt < ttlMs) { - return res.json({ ...cached, cached: true }); - } - } - } catch (_) { - // Если кеш не прочитался — просто продолжаем без него - } - } - - const servers = await readServersFromS3(); - const server = - (Array.isArray(servers) ? servers : []).find( - (s) => (s.id || s.dns || s.ip) === serverId - ) || null; - - if ( - !server || - (server.type !== 'jumphost' && - String(server.type || '').toLowerCase() !== 'home') - ) { - return sendError( - res, - 400, - 'Сервер (jumphost или home) не найден', - 'E_NOT_FOUND' - ); - } - - const creds = getMikrotikCredentials(server); - if (!creds) { - return sendError( - res, - 400, - 'MikroTik API не настроен или нет пароля', - 'E_CREDENTIALS' - ); - } - - const client = createRosClient(creds); - - async function readOne() { - const apiRes = await client.print('interface'); - const raw = apiRes?.data; - const list = Array.isArray(raw) ? raw : raw ? [raw] : []; - const iface = list.find( - (i) => - i && - i.name != null && - String(i.name).trim() === String(interfaceName).trim() - ); - if (!iface) { - return null; - } - 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; - return { - rxBytes: Number.isNaN(rx) ? 0 : rx, - txBytes: Number.isNaN(tx) ? 0 : tx, - }; - } - - const notFoundMessage = `Интерфейс "${interfaceName}" не найден на RouterOS (${serverId})`; - - const start = await readOne(); - if (!start) { - return sendError(res, 400, notFoundMessage, 'E_IFACE_NOT_FOUND'); - } - await sleep(durationSeconds * 1000); - const end = await readOne(); - if (!end) { - return sendError(res, 400, notFoundMessage, 'E_IFACE_NOT_FOUND'); - } - - const rxBytesDelta = Math.max(0, (end.rxBytes || 0) - (start.rxBytes || 0)); - const txBytesDelta = Math.max(0, (end.txBytes || 0) - (start.txBytes || 0)); - const totalBytesDelta = rxBytesDelta + txBytesDelta; - const duration = durationSeconds || 1; - - const rxBps = rxBytesDelta * 8 / duration; - const txBps = txBytesDelta * 8 / duration; - const totalBps = totalBytesDelta * 8 / duration; - - const payload = { - ok: true, - serverId, - interfaceName, - durationSeconds: duration, - rxBytesStart: start.rxBytes, - txBytesStart: start.txBytes, - rxBytesEnd: end.rxBytes, - txBytesEnd: end.txBytes, - rxBytesDelta, - txBytesDelta, - totalBytesDelta, - rxBps, - txBps, - totalBps, - cached: false, - }; - - if (cacheKey) { - writeS3JsonObject(cacheKey, { - ...payload, - cached: false, - cachedAt: Date.now(), - }).catch((err) => - console.warn( - '[traffic][interface-speed-test] cache write failed:', - err?.message || err - ) - ); - } - - return res.json(payload); - } catch (error) { - console.error('measureInterfaceSpeed:', error); - return sendError( - res, - 500, - error?.message || 'Ошибка замера скорости по интерфейсу', - 'E_IFACE_SPEED' - ); - } -} - module.exports = { getInterfaceStats, - measureInterfaceSpeed, };