fix(api): проверять исходные шаблоны и план оптимизации OSPF
This commit is contained in:
1 parent
c88e1400bf
commit
0ee7f02e87
7 files changed
+98
-22
No files matched your search
@@ -0,0 +1,12 @@
|
||||
import assert from "node:assert/strict"
|
||||
import {readEditableOspfTemplates,validateOspfOptimizationPlan} from "./ospf-optimizer-plan.js"
|
||||
const raw={".id":"*1",interfaces:"ether1",disabled:"false",cost:"10"}
|
||||
assert.deepEqual(readEditableOspfTemplates([raw]),[{id:"*1",interface:"ether1",cost:10}])
|
||||
assert.deepEqual(readEditableOspfTemplates([{...raw,disabled:"true",cost:undefined},{...raw,".id":"*2",interfaces:"*ref",cost:undefined}]),[])
|
||||
assert.deepEqual(readEditableOspfTemplates([]),[])
|
||||
for(const payload of [null,{},[null],[raw,raw],[{...raw,cost:undefined}],[{...raw,cost:"10junk"}],[{...raw,cost:"0"}],[{...raw,disabled:undefined}],[{...raw,interfaces:""}],[raw,{...raw,".id":"*2"}]])assert.throws(()=>readEditableOspfTemplates(payload))
|
||||
const row={id:"*1",interface:"ether1",currentCost:10,optimalCost:20,pingMs:0,dlMbps:0,ulMbps:0,score:0}
|
||||
assert.equal(validateOspfOptimizationPlan([row])[0].pingMs,0)
|
||||
assert.deepEqual(validateOspfOptimizationPlan([]),[])
|
||||
for(const payload of [null,{},[row,row],[{...row,currentCost:0}],[{...row,optimalCost:65536}],[{...row,pingMs:-1}],[{...row,score:NaN}],[row,{...row,id:"*2"}]])assert.throws(()=>validateOspfOptimizationPlan(payload))
|
||||
console.log("OSPF optimizer plan: observed cost/disabled/id, ref/disabled skip, duplicate/invalid refusal, zero metrics")
|
||||
@@ -0,0 +1,28 @@
|
||||
import {z} from "zod"
|
||||
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){
|
||||
const parsed=templateSchema.safeParse(payload)
|
||||
if(!parsed.success || new Set(parsed.data.map(row=>row[".id"])).size!==parsed.data.length)throw new Error("Недостоверный каталог шаблонов OSPF")
|
||||
const names=new Set<string>()
|
||||
return parsed.data.flatMap(row=>{
|
||||
const disabled=observedBoolean(row.disabled)
|
||||
if(disabled===null)throw new Error("Неизвестен disabled шаблона OSPF "+row[".id"])
|
||||
if(disabled)return []
|
||||
const name=row.interfaces?.trim()
|
||||
if(!name)throw new Error("Неизвестен интерфейс шаблона OSPF "+row[".id"])
|
||||
if(name.startsWith("*"))return []
|
||||
const cost=observedInteger(row.cost,1,65535)
|
||||
if(cost===null)throw new Error("Неизвестен или неподдерживаем cost шаблона OSPF "+row[".id"])
|
||||
if(names.has(name))throw new Error("Несколько активных шаблонов OSPF для интерфейса "+name)
|
||||
names.add(name)
|
||||
return [{id:row[".id"],interface:name,cost}]
|
||||
})
|
||||
}
|
||||
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})
|
||||
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")
|
||||
return parsed.data
|
||||
}
|
||||
Reference in new issue
Block a user