fix(ui): связывать OSPF узлы по подтверждённым ID
This commit is contained in:
1 parent
7a68ae8184
commit
259c5c3014
16 files changed
+123
-41
No files matched your search
@@ -66,3 +66,8 @@ assert.equal(parseCatalogRoutes(bfdServer, [{ ...rawRoute, "ospf-metric": "0" }]
|
||||
assert.equal(parseCatalogRoutes(bfdServer, [{ ...rawRoute, "ospf-metric": "42" }])[0].cost, 42)
|
||||
assert.equal(parseCatalogRoutes(bfdServer, [{ ...rawRoute, "ospf-metric": "42x" }])[0].cost, null)
|
||||
console.log("OSPF strict interfaces/instances/routes: absent/zero/fractional/flags, no distance-as-cost passed")
|
||||
|
||||
assert.equal(parseBfdCatalogSessions(bfdServer, rawBfd("up"))[0].multihop, null)
|
||||
assert.equal(parseBfdCatalogSessions(bfdServer, [{ ...rawBfd("up")[0], multihop: "false" }])[0].multihop, false)
|
||||
assert.equal(parseCatalogRoutes(bfdServer, [rawRoute])[0].type, "Unknown")
|
||||
assert.equal(parseCatalogRoutes(bfdServer, [{ ...rawRoute, "ospf-type": "intra-area" }])[0].type, "O")
|
||||
@@ -9,7 +9,7 @@ import type {
|
||||
RosBfdSession, RosIpRoute,
|
||||
OspfNeighborRead, OspfInterfaceRead, OspfInstanceRead, OspfRouteRead, BfdSessionRead,
|
||||
} from "../types/server.js"
|
||||
import { parseOspfGateway, parseOspfRouteType } from "../services/ospf-route-parse.js"
|
||||
import { parseOspfGateway, parseOspfRouteType, parseOspfCatalogRouteType } from "../services/ospf-route-parse.js"
|
||||
import { z } from "zod"
|
||||
import { observedInteger, observedDurationMs, observedBoolean } from "../services/ospf-observed-values.js"
|
||||
import { pollOspfCatalog, readOspfCatalogRaw, type OspfCatalogCollections } from "../services/ospf-catalog-poll.js"
|
||||
@@ -123,7 +123,7 @@ export function parseBfdSessions(server: ServerRow, raw: RosBfdSession[], strict
|
||||
export function parseBfdCatalogSessions(server: ServerRow, raw: RosBfdSession[]) {
|
||||
return parseBfdSessions(server, raw, true).map((row, index) => {
|
||||
const source = raw[index]
|
||||
return { ...row, multiplier: observedInteger(source.multiplier, 0, 255), txInterval: observedDurationMs(source["actual-tx-interval"]), rxInterval: observedDurationMs(source["required-min-rx"]), holdTime: observedDurationMs(source["hold-time"]), packetsRx: observedInteger(source["packets-rx"]), packetsTx: observedInteger(source["packets-tx"]), stateChanges: observedInteger(source["state-changes"]) }
|
||||
return { ...row, multihop: observedBoolean(source.multihop), multiplier: observedInteger(source.multiplier, 0, 255), txInterval: observedDurationMs(source["actual-tx-interval"]), rxInterval: observedDurationMs(source["required-min-rx"]), holdTime: observedDurationMs(source["hold-time"]), packetsRx: observedInteger(source["packets-rx"]), packetsTx: observedInteger(source["packets-tx"]), stateChanges: observedInteger(source["state-changes"]) }
|
||||
})
|
||||
}
|
||||
export function parseCatalogNeighbors(server: ServerRow, raw: RosOspfNeighbor[], areaMap: Map<string, string>) {
|
||||
@@ -208,7 +208,7 @@ export function parseCatalogInstances(server: ServerRow, raw: RosOspfInstance[])
|
||||
export function parseCatalogRoutes(server: ServerRow, raw: RosIpRoute[]) {
|
||||
return raw.flatMap((source, index) => {
|
||||
const rows = parseOspfRoutes(server, [{ ...source, ".id": source[".id"] ?? String(index) }])
|
||||
return rows.map(row => ({ ...row, cost: observedInteger(source["ospf-metric"], 0, 4294967295) }))
|
||||
return rows.map(row => ({ ...row, type: parseOspfCatalogRouteType(source) ?? "Unknown", cost: observedInteger(source["ospf-metric"], 0, 4294967295) }))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@ import type { MikrotikClient } from "./mikrotik.js"
|
||||
import type { OspfNeighborRead, OspfInterfaceRead, OspfInstanceRead, BfdSessionRead, OspfRouteRead } from "../types/server.js"
|
||||
export type NullableFields<T, K extends keyof T> = Omit<T, K> & { [P in K]: T[P] | null }
|
||||
export type CatalogNeighbor = NullableFields<OspfNeighborRead, "priority" | "stateChanges">
|
||||
export type CatalogBfdSession = NullableFields<BfdSessionRead, "multiplier" | "txInterval" | "rxInterval" | "holdTime" | "packetsRx" | "packetsTx" | "stateChanges">
|
||||
export type CatalogBfdSession = NullableFields<BfdSessionRead, "multiplier" | "txInterval" | "rxInterval" | "holdTime" | "packetsRx" | "packetsTx" | "stateChanges" | "multihop">
|
||||
export type CatalogInterface = NullableFields<OspfInterfaceRead, "cost" | "type" | "priority" | "helloInterval" | "deadInterval" | "disabled" | "inactive" | "useBfd">
|
||||
export type CatalogInstance = NullableFields<OspfInstanceRead, "version" | "routerId" | "disabled" | "inactive">
|
||||
export type CatalogRoute = NullableFields<OspfRouteRead, "cost">
|
||||
export type CatalogRoute = Omit<NullableFields<OspfRouteRead, "cost">, "type"> & { type: OspfRouteRead["type"] | "Unknown" }
|
||||
export interface OspfCatalogCollections {
|
||||
neighbors: CatalogNeighbor[]; interfaces: CatalogInterface[]; instances: CatalogInstance[];
|
||||
bfdSessions: CatalogBfdSession[]; routes: CatalogRoute[];
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import assert from "node:assert/strict"
|
||||
import type { RosIpRoute } from "../types/server.js"
|
||||
import { parseOspfGateway, parseOspfRouteType } from "./ospf-route-parse.js"
|
||||
import { parseOspfGateway, parseOspfRouteType, parseOspfCatalogRouteType } from "./ospf-route-parse.js"
|
||||
|
||||
function route(partial: Partial<RosIpRoute>): RosIpRoute {
|
||||
return { ".id": "*1", "dst-address": "10.0.0.0/8", ...partial }
|
||||
@@ -20,3 +20,11 @@ assert.deepEqual(parseOspfGateway(route({ gateway: "10.200.0.1%gre-msk-spb" })),
|
||||
})
|
||||
|
||||
console.log("ospf-route-parse.test.ts: ok")
|
||||
|
||||
assert.equal(parseOspfCatalogRouteType(route({ ospf: "true" })), "Unknown")
|
||||
assert.equal(parseOspfCatalogRouteType(route({ ospf: "true", "ospf-type": "future-type" })), "Unknown")
|
||||
assert.equal(parseOspfCatalogRouteType(route({ ospf: "true", "ospf-type": "intra-area" })), "O")
|
||||
assert.equal(parseOspfCatalogRouteType(route({ ospf: "true", "ospf-type": "inter-area" })), "O IA")
|
||||
assert.equal(parseOspfCatalogRouteType(route({ "ospf-type": "ext-type-1" })), "O E1")
|
||||
assert.equal(parseOspfCatalogRouteType(route({ "ospf-type": "nssa-ext-type-2" })), "O E2")
|
||||
assert.equal(parseOspfCatalogRouteType(route({ static: "true" })), null)
|
||||
@@ -26,3 +26,11 @@ export function parseOspfGateway(r: RosIpRoute): { nextHop: string; via: string
|
||||
via: iface || (r.interface ?? "—"),
|
||||
}
|
||||
}
|
||||
|
||||
/** Only an explicit known subtype proves the intra/inter/external class. */
|
||||
export function parseOspfCatalogRouteType(route: RosIpRoute): OspfRouteKind | "Unknown" | null {
|
||||
if (parseOspfRouteType(route) === null) return null
|
||||
const kinds: Record<string, OspfRouteKind> = { "intra-area": "O", internal: "O", "inter-area": "O IA", "ext-type-1": "O E1", "external-type-1": "O E1", "type-1": "O E1", "ext-1": "O E1", e1: "O E1", "nssa-ext-type-1": "O E1", "ext-type-2": "O E2", "external-type-2": "O E2", "type-2": "O E2", "ext-2": "O E2", e2: "O E2", "nssa-ext-type-2": "O E2" }
|
||||
const raw = (route["ospf-type"] ?? route.type ?? "").trim().toLowerCase().replace(/^ospf[- ]/, "")
|
||||
return kinds[raw] ?? "Unknown"
|
||||
}
|
||||
Reference in new issue
Block a user