feat(MikrotikTools): deduplicate traceroute results and handle empty rows for improved accuracy
Publish Fast Tabler Docker image / build-and-push-fast (push) Failing after 2m40s

This commit is contained in:
2026-02-12 16:06:22 +07:00
parent 3b60a5885b
commit 1e28fa33f5
+38 -13
View File
@@ -737,19 +737,44 @@ async function tracerouteViaGateway(req, res) {
return m ? Number(m[1]) : null;
};
const hops = rows.map((r, index) => ({
hop: r.hop != null ? Number(r.hop) : index + 1,
host: r.host || r.address || '',
avgMs: parseMs(r['avg-rtt'] || r.time || r.avg),
bestMs: parseMs(r['best-rtt'] || r['min-rtt']),
worstMs: parseMs(r['worst-rtt'] || r['max-rtt']),
loss:
r['packet-loss'] != null
? Number(String(r['packet-loss']).replace('%', ''))
: null,
status: r.status || '',
raw: r,
}));
// MikroTik REST для traceroute может отдавать несколько строк
// по одному и тому же хопу. Дедуплицируем по host+avg+loss и
// выбрасываем пустые служебные строки без host.
const hops = [];
const seen = new Set();
for (const r of rows) {
const host = r.host || r.address || '';
// Пропускаем полностью пустые строки без адреса и статуса
if (!host && !r.status) continue;
const avgField = r.avg || r['avg-rtt'] || r.time;
const lossField = r['packet-loss'];
const key = `${host}|${avgField || ''}|${lossField || ''}`;
if (host && seen.has(key)) continue;
if (host) seen.add(key);
hops.push({
hop: null, // заполним ниже последовательной нумерацией
host,
avgMs: parseMs(avgField),
bestMs: parseMs(r.best || r['best-rtt'] || r['min-rtt']),
worstMs: parseMs(r.worst || r['worst-rtt'] || r['max-rtt']),
loss:
lossField != null
? Number(String(lossField).replace('%', ''))
: null,
status: r.status || '',
raw: r,
});
}
// Финальная нумерация хопов 1..N
hops.forEach((h, idx) => {
h.hop = idx + 1;
});
return res.json({ ok: true, hops });
} catch (error) {