fix(api): передавать происхождение метрик оптимизатора OSPF
This commit is contained in:
1 parent
255f272fab
commit
7077844655
13 files changed
+96
-9
No files matched your search
@@ -0,0 +1,14 @@
|
||||
import assert from "node:assert/strict"
|
||||
import {readOspfOptimizerObserved} from "./ospf-optimizer-metrics.js"
|
||||
const probe={id:"p",lastPingRttMs:0,lastPingAt:"2020-01-01 00:00:00+00",lastTxAvgMbps:0,lastRxAvgMbps:null}
|
||||
const traffic={interfaceName:"ether1",rxBps:1234567,txBps:0,sampledAt:"2020-01-02 00:00:00+00"}
|
||||
const observed=readOspfOptimizerObserved(probe,traffic)
|
||||
assert.deepEqual(observed.ping,{value:0,source:"speed-probe",sourceId:"p",measuredAt:"2020-01-01T00:00:00.000Z"})
|
||||
assert.equal(observed.dl.value,0);assert.equal(observed.dl.source,"speed-probe");assert.equal(observed.dl.measuredAt,null)
|
||||
assert.equal(observed.ul.value,0);assert.equal(observed.ul.source,"interface-traffic");assert.equal(observed.ul.measuredAt,"2020-01-02T00:00:00.000Z")
|
||||
assert.equal(readOspfOptimizerObserved(undefined,traffic).dl.value,1.234567)
|
||||
assert.deepEqual(readOspfOptimizerObserved(undefined,undefined),{ping:{value:null,source:"unknown",sourceId:null,measuredAt:null},dl:{value:null,source:"unknown",sourceId:null,measuredAt:null},ul:{value:null,source:"unknown",sourceId:null,measuredAt:null}})
|
||||
assert.throws(()=>readOspfOptimizerObserved({...probe,lastPingRttMs:-1},traffic))
|
||||
assert.throws(()=>readOspfOptimizerObserved({...probe,lastPingAt:"invalid"},traffic))
|
||||
assert.throws(()=>readOspfOptimizerObserved(undefined,{...traffic,txBps:-1}))
|
||||
console.log("OSPF observed metrics: raw zero/null/fractions, provenance/old timestamps, no speed date inference; no DB/RouterOS")
|
||||
@@ -0,0 +1,16 @@
|
||||
import {ospfOptimizerObservedSchema,type OspfOptimizerObserved} from "@mmapp/contracts"
|
||||
interface Probe {id:string;lastPingRttMs:number|null;lastPingAt:string|null;lastTxAvgMbps:number|null;lastRxAvgMbps:number|null}
|
||||
interface Traffic {interfaceName:string;rxBps:number;txBps:number;sampledAt:string}
|
||||
const unknown=()=>({value:null,source:"unknown" as const,sourceId:null,measuredAt:null})
|
||||
function timestamp(value:string|null){return value===null?null:new Date(value).toISOString()}
|
||||
export function readOspfOptimizerObserved(probe:Probe|undefined,traffic:Traffic|undefined):OspfOptimizerObserved{
|
||||
function speed(value:number|null|undefined,field:"rxBps"|"txBps"){
|
||||
if(value!=null&&probe)return {value,source:"speed-probe" as const,sourceId:probe.id,measuredAt:null}
|
||||
if(traffic)return {value:traffic[field]/1_000_000,source:"interface-traffic" as const,sourceId:traffic.interfaceName,measuredAt:timestamp(traffic.sampledAt)}
|
||||
return unknown()
|
||||
}
|
||||
return ospfOptimizerObservedSchema.parse({
|
||||
ping:probe?.lastPingRttMs!=null?{value:probe.lastPingRttMs,source:"speed-probe",sourceId:probe.id,measuredAt:timestamp(probe.lastPingAt)}:unknown(),
|
||||
dl:speed(probe?.lastTxAvgMbps,"rxBps"),ul:speed(probe?.lastRxAvgMbps,"txBps"),
|
||||
})
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import {z} from "zod"
|
||||
import {ospfOptimizerObservedSchema} from "@mmapp/contracts"
|
||||
import {observedBoolean,observedInteger} from "./ospf-observed-values.js"
|
||||
const templateSchema=z.array(z.object({".id":z.string().trim().min(1),interfaces:z.string().optional(),cost:z.string().optional(),disabled:z.string().optional()}))
|
||||
export function readEditableOspfTemplates(payload:unknown){
|
||||
@@ -20,7 +21,7 @@ export function readEditableOspfTemplates(payload:unknown){
|
||||
})
|
||||
}
|
||||
const measured=z.number().finite().nonnegative()
|
||||
const rowSchema=z.object({id:z.string().trim().min(1),interface:z.string().trim().min(1),currentCost:z.number().int().min(1).max(65535),optimalCost:z.number().int().min(1).max(65535),score:z.number().finite(),pingMs:measured,dlMbps:measured,ulMbps:measured})
|
||||
const rowSchema=z.object({observed:ospfOptimizerObservedSchema.optional(),id:z.string().trim().min(1),interface:z.string().trim().min(1),currentCost:z.number().int().min(1).max(65535),optimalCost:z.number().int().min(1).max(65535),score:z.number().finite(),pingMs:measured,dlMbps:measured,ulMbps:measured})
|
||||
export function validateOspfOptimizationPlan(payload:unknown){
|
||||
const parsed=z.array(rowSchema).safeParse(payload)
|
||||
if(!parsed.success || new Set(parsed.data.map(row=>row.id)).size!==parsed.data.length || new Set(parsed.data.map(row=>row.interface)).size!==parsed.data.length)throw new Error("Недостоверный план оптимизации OSPF")
|
||||
|
||||
Reference in new issue
Block a user