feat(mikrotik): implement batch removal of address lists with fallback to individual deletes for improved efficiency and error handling
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m52s

This commit is contained in:
2026-02-24 14:39:25 +07:00
parent b56df61c8f
commit 1f391d9398
2 changed files with 123 additions and 210 deletions
+56 -10
View File
@@ -1475,6 +1475,58 @@ async function getAddressLists(req, res) {
}
const ADDRESS_LIST_PATH = 'ip/firewall/address-list';
const ADDRESS_LIST_REMOVE_CHUNK_SIZE = 100;
function chunkArray(items, size) {
if (!Array.isArray(items) || items.length === 0) return [];
const chunkSize = Math.max(1, Number(size) || 1);
const chunks = [];
for (let i = 0; i < items.length; i += chunkSize) {
chunks.push(items.slice(i, i + chunkSize));
}
return chunks;
}
/**
* Удаление address-list по .id:
* 1) пытаемся батчем через POST .../remove { numbers: "*1,*2" }
* 2) при ошибке откатываемся к поштучному DELETE, чтобы не ломать совместимость.
*/
async function removeAddressListIds(client, ids) {
const normalizedIds = [...new Set(
(Array.isArray(ids) ? ids : [])
.map((id) => String(id || '').trim())
.filter(Boolean)
)];
if (normalizedIds.length === 0) return 0;
let removed = 0;
const chunks = chunkArray(normalizedIds, ADDRESS_LIST_REMOVE_CHUNK_SIZE);
for (const chunk of chunks) {
try {
await client.command(`${ADDRESS_LIST_PATH}/remove`, { numbers: chunk.join(',') });
removed += chunk.length;
continue;
} catch (err) {
console.warn(
`[address-lists] batch remove fallback (${chunk.length} ids):`,
err?.message || String(err)
);
}
for (const id of chunk) {
try {
await rosRemove(client, ADDRESS_LIST_PATH, id);
removed++;
} catch (err) {
console.warn(`[address-lists] remove ${id}:`, err?.message);
}
}
}
return removed;
}
/**
* POST /api/mikrotik/address-lists/apply-summary
@@ -1487,7 +1539,9 @@ async function applyAddressListSummary(req, res) {
if (!serverId) {
return sendError(res, 400, 'serverId is required', 'E_BAD_REQUEST');
}
const ids = Array.isArray(removeIds) ? removeIds.filter((id) => id != null && String(id).trim()) : [];
const ids = Array.isArray(removeIds)
? [...new Set(removeIds.map((id) => String(id || '').trim()).filter(Boolean))]
: [];
const entries = Array.isArray(addEntries)
? addEntries.filter((e) => e && (e.address || e.list))
: [];
@@ -1507,15 +1561,7 @@ async function applyAddressListSummary(req, res) {
let removed = 0;
let added = 0;
for (const id of ids) {
try {
const pathId = String(id).trim();
await rosRemove(client, ADDRESS_LIST_PATH, pathId);
removed++;
} catch (err) {
console.warn(`[address-lists] remove ${id}:`, err?.message);
}
}
removed = await removeAddressListIds(client, ids);
for (const entry of entries) {
try {