fix(netflow): проверять ответы аналитики и выбранный месяц

This commit is contained in:
Denozordec committed 2026-10-11 17:58:18 +07:00
1 parent 979dc3cfb0
commit 64df472202
10 files changed
+271 -16

No files matched your search

+13 -3
View File
@@ -12,13 +12,21 @@ import type {
TrafficFlowSettingsPatch,
} from "@mmapp/contracts/traffic-flow"
import { z } from "zod"
import { trafficFlowSettingsDtoSchema, trafficFlowSettingsPatchSchema, trafficFlowHostFileSchema, flowPurgeDtoSchema } from "@mmapp/contracts/traffic-flow"
import { trafficFlowSettingsDtoSchema, trafficFlowSettingsPatchSchema, trafficFlowHostFileSchema, flowPurgeDtoSchema, flowAnalyticsDtoSchema, flowMonthlyDtoSchema } from "@mmapp/contracts/traffic-flow"
import { requestJson } from "@/shared/api/http-client"
export type { TrafficFlowHostFile }
const flowSettingsSchema = trafficFlowSettingsDtoSchema.extend({ flowListenPort: z.number().int().min(1).max(65535), wgListenPort: z.number().int().min(1).max(65535) }).refine(data => (!data.hasHostPrivateKey || data.hostPublicKey.length > 0) && (!data.listenerBound || !!data.listenerAddress) && (data.lastDatagramAt === null || Number.isFinite(Date.parse(data.lastDatagramAt))) && new Set(data.peers.map(peer => peer.serverId)).size === data.peers.length, "Несогласованные настройки NetFlow")
const flowPatchSchema = trafficFlowSettingsPatchSchema.strict()
// Optional overlay/wire measurements may be unavailable independently of the
// confirmed primary counters. Preserve that distinction instead of inventing zero.
const optionalFlowMetric = z.preprocess(value => typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : undefined, z.number().nonnegative().optional())
const flowAnalyticsSchema = flowAnalyticsDtoSchema.extend({
bytesPayload: optionalFlowMetric, bytesOverlay: optionalFlowMetric,
bytesMesh: optionalFlowMetric, bytesWire: optionalFlowMetric,
bpsOverlay: optionalFlowMetric, bpsWire: optionalFlowMetric,
}).refine(data => [...data.rxSeries, ...data.txSeries].every(value => Number.isFinite(value) && value >= 0), "Некорректные измерения трафика")
function flowConfirmed<T>(schema: z.ZodType<T>, raw: unknown): T {
const parsed = schema.safeParse(raw)
if (!parsed.success) throw new Error("Данные NetFlow не подтверждены: получен некорректный ответ сервера")
@@ -135,7 +143,7 @@ export async function getFlowAnalytics(
excludeOverlay?: boolean
},
): Promise<FlowAnalyticsDto> {
return requestJson<FlowAnalyticsDto>(baseUrl, `/api/traffic/flow/analytics${flowQuery(params)}`)
return flowConfirmed(flowAnalyticsSchema, await requestJson<unknown>(baseUrl, `/api/traffic/flow/analytics${flowQuery(params)}`))
}
export async function getFlowMonthly(
@@ -145,7 +153,9 @@ export async function getFlowMonthly(
const q = new URLSearchParams()
q.set("month", params.month)
if (params.serverId) q.set("serverId", params.serverId)
return requestJson<FlowMonthlyDto>(baseUrl, `/api/traffic/flow/monthly?${q.toString()}`)
const data = flowConfirmed(flowMonthlyDtoSchema, await requestJson<unknown>(baseUrl, `/api/traffic/flow/monthly?${q.toString()}`))
if (data.month !== params.month) throw new Error("Сервер вернул данные другого месяца. Повторите загрузку.")
return data
}
export async function purgeTrafficFlowData(baseUrl: string, init?: RequestInit): Promise<FlowPurgeDto> {