fix(network-map): рисовать пунктир и скорость до сервиса
Docker images / prepare-release (push) Successful in 8s
Docker images / backend-image (push) Successful in 1m41s
Docker images / frontend-image (push) Successful in 2m55s
Docker images / notify-webhook (push) Skipped
Docker images / updater-image (push) Successful in 43s
Docker images / publish-release (push) Successful in 9s

Якорь hop на EN даже без nextHop; линия ARN\to Google с NetflowRateBadge.

Co-authored-by: Cursor <[email protected]>
This commit is contained in:
Denozordec
2026-09-07 17:02:28 +07:00
co-authored by Cursor
parent 77425cca32
commit cd1fd2c9d3
3 changed files with 181 additions and 52 deletions
@@ -371,4 +371,42 @@ try {
resetFlowCatalogForTests()
}
resetFlowRingsForTests()
resetIfaceCacheForTests()
resetRipeCacheForTests()
disableRipeEnqueueForTests()
seedFlowTopologyForTests(topo)
rememberServerIfaces(7, [
{ ".id": "*1", name: "SWE-VEESP" },
])
ingestParsedFlowsForServerForTests(7, [
{
src: "173.194.151.65",
dst: "10.200.100.53",
proto: 6,
srcPort: 443,
dstPort: 57182,
bytes: 9_000,
packets: 80,
inIface: "1",
outIface: "1",
nextHop: "",
},
])
try {
resetFlowMapHopsCacheForTests()
const wanOnly = buildFlowMapHops({ minutes: 5, minSharePct: 0 })
const googleEdge = wanOnly.serviceEdges?.find((e) => e.toId === "svc:google")
assert.ok(googleEdge, "Google WAN без GRE payload")
assert.equal(googleEdge.fromId, "9", "единственный EN, даже без nextHop")
assert.ok(googleEdge.bps > 0, "скорость на hop EN→сервис")
assert.ok(!(wanOnly.serviceEdges ?? []).some((e) => e.fromId === "7"), "нет пунктира с JH")
} finally {
seedFlowTopologyForTests(null)
resetFlowRingsForTests()
resetIfaceCacheForTests()
resetRipeCacheForTests()
resetFlowCatalogForTests()
}
console.log("traffic-flow-map-hops.test.ts: ok")
@@ -327,11 +327,22 @@ function buildFlowMapHopsUncached(q: FlowMapHopsQuery, minSharePct: number): Flo
clients: Map<string, string>
}>()
for (const h of hops.values()) {
if (h.kind !== "gre" || !h.toId) continue
const from = Number(h.fromId)
const to = Number(h.toId)
if (!Number.isFinite(from) || !Number.isFinite(to)) continue
if (enIds.has(to) && !enIds.has(from)) jhToEn.set(from, to)
}
const soleEnId = topo.enNodes.length === 1 ? String(topo.enNodes[0]!.id) : null
function anchorEnId(exporterId: string): string | null {
const n = Number(exporterId)
if (enIds.has(n)) return exporterId
const mapped = jhToEn.get(n)
if (mapped != null) return String(mapped)
if (soleEnId) return soleEnId
return null
}