diff --git a/backend/services/mikrotikApplyService.js b/backend/services/mikrotikApplyService.js index caf7c0d..1640b9d 100644 --- a/backend/services/mikrotikApplyService.js +++ b/backend/services/mikrotikApplyService.js @@ -358,21 +358,74 @@ async function fetchExportViaFile(client) { await client.command('export', { compact: '', file: basename }); - const printRes = await client.command('file/print', { - '.proplist': 'contents,.id', - '.query': [`name=${basename}`], - }); - const data = printRes?.data; - const list = Array.isArray(data) ? data : (data ? [data] : []); + // REST API: file/print — пробуем GET с query в URL (некоторые версии ожидают это) + const qs = `?.proplist=.id,name,contents&name=${encodeURIComponent(basename)}`; + let printRes = await client.print(`file/print${qs}`); + let data = printRes?.data; + let list = Array.isArray(data) ? data : (data ? [data] : []); + + // Если по name в URL не нашли — пробуем POST с .query в body + if (list.length === 0) { + printRes = await client.command('file/print', { + '.proplist': ['.id', 'name', 'contents'], + '.query': [`name=${basename}`], + }); + data = printRes?.data; + list = Array.isArray(data) ? data : (data ? [data] : []); + } + + // Если всё ещё пусто — печатаем все файлы и ищем по имени вручную + if (list.length === 0) { + printRes = await client.command('file/print', { + '.proplist': ['.id', 'name', 'contents'], + }); + data = printRes?.data; + list = Array.isArray(data) ? data : (data ? [data] : []); + const found = list.find( + (f) => + (f.name || '') === basename || + (f.name || '').endsWith('/' + basename) || + (f.name || '').endsWith(basename), + ); + if (found) list = [found]; + } + const file = list[0]; - if (!file || file.contents == null) { + if (!file) { + throw new Error('Failed to read export file from MikroTik (file not found after export)'); + } + + let config = String(file.contents || ''); + + // Для файлов >60KB API не возвращает contents в print — читаем через /file/read чанками + if (!config && file.name) { + const chunkSize = 32768; + let offset = 0; + const chunks = []; + for (;;) { + const readRes = await client.command('file/read', { + file: file.name, + offset: String(offset), + 'chunk-size': String(chunkSize), + }); + const rd = readRes?.data; + const chunk = Array.isArray(rd) ? (rd[0]?.data ?? rd[0]) : (rd?.data ?? rd); + const str = typeof chunk === 'string' ? chunk : (chunk ? String(chunk) : ''); + if (!str) break; + chunks.push(str); + offset += str.length; + if (str.length < chunkSize) break; + } + config = chunks.join(''); + } + + if (!config) { try { - const id = file?.['.id']; + const id = file['.id']; if (id) await client.remove(`file/${id}`); } catch (_) {} - throw new Error('Failed to read export file from MikroTik'); + throw new Error('Failed to read export file from MikroTik (file/print and file/read returned no contents)'); } - const config = String(file.contents || ''); try { const id = file['.id'];