diff --git a/backend/routes/mikrotikConfigRoutes.js b/backend/routes/mikrotikConfigRoutes.js index 7b0bfd4..dd9e9be 100644 --- a/backend/routes/mikrotikConfigRoutes.js +++ b/backend/routes/mikrotikConfigRoutes.js @@ -1146,6 +1146,42 @@ async function runScript(req, res) { } } +/** Логирование в контейнер: JSON запроса/ответа и эквивалент CLI MikroTik */ +function logAddressListRequest(creds, method, path, query) { + const protocol = creds.secure ? 'https' : 'http'; + const url = `${protocol}://${creds.host}:${creds.port}/rest/${path}${query ? `?${query}` : ''}`; + const cli = '/ip firewall address-list print'; + const payload = { component: 'address-lists', request: { method, path, url, cli } }; + console.log(JSON.stringify(payload)); + console.log(`[address-lists] MikroTik CLI: ${cli}`); +} + +function logAddressListResponse(raw, listRawLength, banCount, banCounterCount) { + const firstKeys = Array.isArray(raw) && raw[0] && typeof raw[0] === 'object' + ? Object.keys(raw[0]) + : (raw && typeof raw === 'object' && !Array.isArray(raw) ? Object.keys(raw) : []); + let rawSnippet; + try { + const s = JSON.stringify(raw); + rawSnippet = s.length > 800 ? s.slice(0, 800) + '...' : s; + } catch (_) { + rawSnippet = String(raw); + } + const payload = { + component: 'address-lists', + response: { + rawIsArray: Array.isArray(raw), + rawLength: Array.isArray(raw) ? raw.length : undefined, + listRawLength: listRawLength, + banCount, + banCounterCount, + firstItemKeys: firstKeys, + rawSnippet: rawSnippet?.slice(0, 600), + }, + }; + console.log(JSON.stringify(payload)); +} + /** * GET /api/mikrotik/address-lists?serverId=xxx * Возвращает address-list списки ban и ban_counter с выбранного роутера (MikroTik). @@ -1171,8 +1207,26 @@ async function getAddressLists(req, res) { const client = createRosClient(creds); const path = 'ip/firewall/address-list'; - // REST API не всегда поддерживает фильтр по list — загружаем все и фильтруем по полю list + logAddressListRequest(creds, 'GET', path, ''); + let all = await rosPrint(client, path); + if (!Array.isArray(all) || all.length === 0) { + logAddressListRequest(creds, 'POST', `${path}/print`, ''); + try { + const postRes = await client.command(`${path}/print`, {}); + const data = postRes?.data; + if (data && typeof data === 'object' && Array.isArray(data.ret)) { + all = data.ret; + } else if (Array.isArray(data)) { + all = data; + } else if (data && typeof data === 'object') { + all = Array.isArray(data) ? data : [data]; + } + } catch (postErr) { + console.error(JSON.stringify({ component: 'address-lists', postFallbackError: postErr?.message || String(postErr) })); + } + } + if (Array.isArray(all) && all.length === 1 && all[0] && typeof all[0] === 'object' && Array.isArray(all[0].ret)) { all = all[0].ret; } else if (all && typeof all === 'object' && !Array.isArray(all) && Array.isArray(all.ret)) { @@ -1180,15 +1234,18 @@ async function getAddressLists(req, res) { } const listRaw = Array.isArray(all) ? all : []; + // Имя списка: RouterOS REST отдаёт "list" (или "List"), возможен kebab "address-list" const getListName = (entry) => { if (!entry || typeof entry !== 'object') return ''; - const name = entry.list ?? entry.List ?? ''; + const name = entry.list ?? entry.List ?? entry['address-list'] ?? ''; return String(name).trim().toLowerCase(); }; const ban = listRaw.filter((e) => getListName(e) === 'ban'); const banCounter = listRaw.filter((e) => getListName(e) === 'ban_counter'); + logAddressListResponse(all, listRaw.length, ban.length, banCounter.length); + return sendOk(res, { serverId, serverLabel: server.dns || server.ip || serverId, @@ -1198,7 +1255,7 @@ async function getAddressLists(req, res) { } catch (error) { const msg = error.response?.data?.detail || error.response?.data?.message || error.message || 'Ошибка получения address-list'; const status = error.response?.status; - console.error('getAddressLists:', error); + console.error(JSON.stringify({ component: 'address-lists', error: msg, stack: error?.stack })); return sendError(res, status && status >= 400 ? status : 502, msg, 'E_ADDRESS_LISTS'); } }