feat(MikrotikConfig): enhance MikroTik configuration generation with support for 'text' and 'json' formats; add new API endpoints for interface and recursive route generation
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 2m37s

This commit is contained in:
2026-02-03 17:46:30 +07:00
parent 5b96325184
commit 0ea0f376a6
7 changed files with 644 additions and 152 deletions
+27 -142
View File
@@ -2146,8 +2146,14 @@ function NetworkConfigManager() {
const handleGenerateMikrotikCode = async () => {
setLoading(true);
try {
const code = await generateMikrotikRecursiveRoutes();
setGeneratedMikrotikCode(code);
const { data } = await api.post('/mikrotik/generate', {
format: 'text',
type: 'all',
config,
servers,
});
const blocks = data?.blocks || [];
setGeneratedMikrotikCode(blocks);
setMikrotikCodeModalOpen(true);
} catch (error) {
console.error('Error generating MikroTik code:', error);
@@ -2167,156 +2173,35 @@ function NetworkConfigManager() {
setLoading(true);
try {
if (type === 'interface') {
// Получаем все интерфейсы для этого сервера (где сервер участвует как первый или второй)
// Фильтруем только те, где оба сервера указаны и есть IP адреса
const serverInterfaces = (config.tunnelInterfaces || []).filter(iface =>
(iface.serverId === serverId || iface.serverId2 === serverId) &&
iface.serverId && iface.serverId2 && iface.localIp && iface.remoteIp
);
if (serverInterfaces.length === 0) {
const { data } = await api.post('/mikrotik/generate', {
format: 'text',
type: 'interfaces',
serverId,
config,
servers,
});
const blocks = data?.blocks || [];
if (!blocks.length) {
notify.error('Нет интерфейсов с полной конфигурацией для этого сервера');
setLoading(false);
return;
}
const blocks = await generateMikrotikInterfaceAddressesForSelection(serverInterfaces);
if (!blocks || blocks.length === 0) {
notify.error('Нет данных для генерации кода MikroTik для этого сервера');
setLoading(false);
return;
}
// Фильтруем блоки, чтобы показать только те, что относятся к данному серверу
const server = getServerInfo(serverId);
const serverName = server?.dns || server?.ip || serverId;
const filteredBlocks = blocks.filter(block =>
block.serverName === serverName || block.server?.id === serverId
);
if (filteredBlocks.length === 0) {
notify.error('Не удалось сгенерировать код для этого сервера');
setLoading(false);
return;
}
setGeneratedMikrotikCode(filteredBlocks);
setGeneratedMikrotikCode(blocks);
setMikrotikCodeModalOpen(true);
} else if (type === 'gateway') {
// Получаем все gateways для этого сервера
const serverGateways = (config.gateways || []).filter(gw => gw.serverId === serverId);
if (serverGateways.length === 0) {
notify.error('Нет gateways для этого сервера');
setLoading(false);
return;
}
// Генерируем код для рекурсивных маршрутов этого сервера
const recursiveGateways = serverGateways.filter(gw => gw.type === 'recursive');
if (recursiveGateways.length === 0) {
const { data } = await api.post('/mikrotik/generate', {
format: 'text',
type: 'recursive',
serverId,
config,
servers,
});
const blocks = data?.blocks || [];
if (!blocks.length) {
notify.error('Нет рекурсивных gateways для генерации кода');
setLoading(false);
return;
}
const blocks = [];
const server = getServerInfo(serverId);
const serverName = server?.dns || server?.ip || serverId;
// Генерируем код для каждого рекурсивного gateway
recursiveGateways.forEach(gw => {
if (!gw.ip) return;
// Поддержка старого формата (parentGatewayId) и нового (parentGateways)
const parentGatewaysList = gw.parentGateways && Array.isArray(gw.parentGateways) && gw.parentGateways.length > 0
? gw.parentGateways
: (gw.parentGatewayId ? [{ id: gw.parentGatewayId, distance: undefined }] : []);
if (parentGatewaysList.length === 0) return;
let code = `# Рекурсивный маршрут для gateway: ${gw.ip}\n`;
if (server?.provider) {
code += `# Провайдер: ${server.provider}\n`;
}
if (server?.country) {
code += `# Страна: ${server.country}\n`;
}
code += '\n';
let validRoutesCount = 0;
parentGatewaysList.forEach((parentRef) => {
const parent = getParentGateway(parentRef.id);
if (!parent) {
code += `# Родительский gateway/интерфейс "${parentRef.id}" не найден, пропущен\n`;
return;
}
// Определяем IP родителя в зависимости от типа
const parentIp = parent.parentType === 'interface' ? parent.remoteIp : parent.ip;
if (!parentIp) {
const parentType = parent.parentType === 'interface' ? 'интерфейс' : 'gateway';
code += `# Родительский ${parentType} не имеет IP, пропущен\n`;
return;
}
validRoutesCount++;
// Создаём маршрут для рекурсивного gateway
const parentLabel = parent.parentType === 'interface'
? `интерфейс ${parent.name || parent.interfaceType || 'interface'} (${parent.remoteIp})`
: `gateway ${parent.ip}`;
const distanceSuffix = parentRef.distance !== undefined && parentRef.distance !== null ? ` (distance: ${parentRef.distance})` : '';
code += `# Рекурсивный gateway: ${gw.ip}${distanceSuffix}\n`;
code += `# Родительский: ${parentLabel}\n`;
// Формируем gateway: для интерфейсов добавляем имя через %, для gateway - только IP
const gatewayValue = parent.parentType === 'interface'
? `${parentIp}%${parent.name || parent.interfaceType || 'interface'}`
: parentIp;
// Создаём маршрут к IP рекурсивного gateway через родительский
const comment = gw.description
? `Recursive: ${gw.description} -> ${parentIp}${distanceSuffix}`
: `Recursive: ${gw.ip} -> ${parentIp}${distanceSuffix}`;
const distanceParam = parentRef.distance !== undefined && parentRef.distance !== null ? ` distance=${parentRef.distance}` : '';
code += `/ip route add dst-address=${gw.ip}/32 gateway=${gatewayValue}${distanceParam} comment="${comment}"\n`;
// Если у рекурсивного gateway есть описание с указанием на default route
if (gw.description && (gw.description.toLowerCase().includes('default') || gw.description.toLowerCase().includes('0.0.0.0'))) {
code += `# Дополнительный default route через рекурсивный gateway${distanceSuffix}\n`;
const defaultComment = gw.description ? `Recursive: ${gw.description} (default)${distanceSuffix}` : `Recursive: ${gw.ip} (default)${distanceSuffix}`;
code += `/ip route add dst-address=0.0.0.0/0 gateway=${gatewayValue}${distanceParam} comment="${defaultComment}"\n`;
}
code += '\n';
});
code += '# Проверка созданных маршрутов:\n';
code += '# /ip route print where comment~"Recursive"\n';
code += `# Всего создано маршрутов: ${validRoutesCount}\n`;
if (validRoutesCount > 0) {
blocks.push({
type: 'recursive-routes',
serverName,
server,
code
});
}
});
if (blocks.length === 0) {
notify.error('Не удалось сгенерировать код для gateways этого сервера');
setLoading(false);
return;
}
setGeneratedMikrotikCode(blocks);
setMikrotikCodeModalOpen(true);
} else {