feat: Implement nested if/else block generation for RouterOS configuration in gateway management to enhance filter logic and maintain compatibility
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 4m27s

This commit is contained in:
2025-08-10 21:57:38 +07:00
parent d3490c438b
commit 817a8981f4
+35 -108
View File
@@ -26,6 +26,35 @@ const s3 = new AWS.S3({
const BUCKET_NAME = process.env.S3_BUCKET_NAME;
const FILE_KEY = 'bgp_data/domains.txt';
// Helper: build MikroTik nested if/else blocks (RouterOS v7 filter language does not support 'else if')
function buildNestedGatewayBlocks(gatewayGroups, baseIndentSpaces = 4) {
const indent = (n) => ' '.repeat(n);
const entries = Object.entries(gatewayGroups);
if (entries.length === 0) return '';
function buildAt(index, pad) {
const [gateway, communities] = entries[index];
let s = '';
s += `${indent(pad)}if (\n`;
communities.forEach((community, i) => {
s += `${indent(pad + 4)}(bgp-communities includes ${community})`;
if (i < communities.length - 1) s += ' or \n';
});
s += `\n${indent(pad)})\n`;
s += `${indent(pad)}{\n${indent(pad + 8 - 4)}set gw ${gateway}; accept;\n${indent(pad)}}\n`;
if (index < entries.length - 1) {
s += `${indent(pad)}else\n${indent(pad)}{\n`;
s += buildAt(index + 1, pad + 4);
s += `\n${indent(pad)}}`;
} else {
s += `${indent(pad)}else\n${indent(pad)}{\n${indent(pad + 4)}reject;\n${indent(pad)}}`;
}
return s;
}
return buildAt(0, baseIndentSpaces);
}
// Get domains from S3
app.get('/api/domains', async (req, res) => {
const params = {
@@ -608,42 +637,8 @@ app.get('/api/filters/generate-config', async (req, res) => {
config += `// Date: ${new Date().toISOString()}\n\n`;
config += '/routing filter bgp-in-tmp {\n';
// Если есть только один gateway, создаем простую конфигурацию
if (Object.keys(gatewayGroups).length === 1) {
const [gateway, communities] = Object.entries(gatewayGroups)[0];
config += ` if (\n`;
communities.forEach((community, index) => {
config += ` (bgp-communities includes ${community})`;
if (index < communities.length - 1) {
config += ` or \n`;
}
});
config += `\n )\n {\n set gw ${gateway}; accept;\n }\n else\n {\n reject;\n }\n`;
} else {
// Если несколько gateway, создаем каскадную структуру
const gatewayEntries = Object.entries(gatewayGroups);
gatewayEntries.forEach(([gateway, communities], gatewayIndex) => {
if (gatewayIndex === 0) {
config += ` if (\n`;
} else {
config += ` else if (\n`;
}
communities.forEach((community, index) => {
config += ` (bgp-communities includes ${community})`;
if (index < communities.length - 1) {
config += ` or \n`;
}
});
config += `\n )\n {\n set gw ${gateway}; accept;\n }`;
if (gatewayIndex === gatewayEntries.length - 1) {
config += `\n else\n {\n reject;\n }\n`;
} else {
config += `\n`;
}
});
}
// Строим вложенные if/else (RouterOS не поддерживает else if в данном контексте)
config += buildNestedGatewayBlocks(gatewayGroups, 4);
config += '}\n';
@@ -698,42 +693,8 @@ app.post('/api/filters/export-config', async (req, res) => {
config += `// Date: ${new Date().toISOString()}\n\n`;
config += '/routing filter bgp-in-tmp {\n';
// Если есть только один gateway, создаем простую конфигурацию
if (Object.keys(gatewayGroups).length === 1) {
const [gateway, communities] = Object.entries(gatewayGroups)[0];
config += ` if (\n`;
communities.forEach((community, index) => {
config += ` (bgp-communities includes ${community})`;
if (index < communities.length - 1) {
config += ` or \n`;
}
});
config += `\n )\n {\n set gw ${gateway}; accept;\n }\n else\n {\n reject;\n }\n`;
} else {
// Если несколько gateway, создаем каскадную структуру
const gatewayEntries = Object.entries(gatewayGroups);
gatewayEntries.forEach(([gateway, communities], gatewayIndex) => {
if (gatewayIndex === 0) {
config += ` if (\n`;
} else {
config += ` else if (\n`;
}
communities.forEach((community, index) => {
config += ` (bgp-communities includes ${community})`;
if (index < communities.length - 1) {
config += ` or \n`;
}
});
config += `\n )\n {\n set gw ${gateway}; accept;\n }`;
if (gatewayIndex === gatewayEntries.length - 1) {
config += `\n else\n {\n reject;\n }\n`;
} else {
config += `\n`;
}
});
}
// Строим вложенные if/else (RouterOS не поддерживает else if в данном контексте)
config += buildNestedGatewayBlocks(gatewayGroups, 4);
config += '}\n';
@@ -977,42 +938,8 @@ app.post('/api/server-filters/generate-config', async (req, res) => {
config += `// Date: ${new Date().toISOString()}\n\n`;
config += '/routing filter bgp-in-tmp {\n';
// Если есть только один gateway, создаем простую конфигурацию
if (Object.keys(gatewayGroups).length === 1) {
const [gateway, communities] = Object.entries(gatewayGroups)[0];
config += ` if (\n`;
communities.forEach((community, index) => {
config += ` (bgp-communities includes ${community})`;
if (index < communities.length - 1) {
config += ` or \n`;
}
});
config += `\n )\n {\n set gw ${gateway}; accept;\n }\n else\n {\n reject;\n }\n`;
} else {
// Если несколько gateway, создаем каскадную структуру
const gatewayEntries = Object.entries(gatewayGroups);
gatewayEntries.forEach(([gateway, communities], gatewayIndex) => {
if (gatewayIndex === 0) {
config += ` if (\n`;
} else {
config += ` else if (\n`;
}
communities.forEach((community, index) => {
config += ` (bgp-communities includes ${community})`;
if (index < communities.length - 1) {
config += ` or \n`;
}
});
config += `\n )\n {\n set gw ${gateway}; accept;\n }`;
if (gatewayIndex === gatewayEntries.length - 1) {
config += `\n else\n {\n reject;\n }\n`;
} else {
config += `\n`;
}
});
}
// Строим вложенные if/else (RouterOS не поддерживает else if в данном контексте)
config += buildNestedGatewayBlocks(gatewayGroups, 4);
config += '}\n';