import { trafficFlowSettingsPatchSchema, type TrafficFlowSettingsDto, type TrafficFlowSettingsPatch } from "@mmapp/contracts/traffic-flow" export type NetflowDraft = { enabled: boolean; collectorIp: string; flowListenPort: string; wgListenPort: string; prefix: string; publicEndpoint: string; retentionHours: string; topN: string; shareOn: boolean; mapServiceMinSharePct: string } export const emptyNetflowDraft: NetflowDraft = { enabled: false, collectorIp: "", flowListenPort: "", wgListenPort: "", prefix: "", publicEndpoint: "", retentionHours: "", topN: "", shareOn: false, mapServiceMinSharePct: "" } export function netflowDraftFromSettings(data: TrafficFlowSettingsDto): NetflowDraft { return { enabled: data.enabled, collectorIp: data.collectorIp, flowListenPort: String(data.flowListenPort), wgListenPort: String(data.wgListenPort), prefix: data.prefix, publicEndpoint: data.publicEndpoint, retentionHours: String(data.retentionHours), topN: String(data.topN), shareOn: data.mapServiceMinSharePct > 0, mapServiceMinSharePct: String(data.mapServiceMinSharePct) } } export function netflowDraftPatch(draft: NetflowDraft, dirty: ReadonlySet): TrafficFlowSettingsPatch { const patch: TrafficFlowSettingsPatch = {} for (const field of ["collectorIp", "prefix", "publicEndpoint"] as const) if (dirty.has(field)) { const value = draft[field].trim() if ((field !== "publicEndpoint" && !value) || /[\r\n]/.test(value)) throw new Error("Укажите корректное значение: " + field) patch[field] = value } for (const [field, label, max] of [["flowListenPort","UDP IPFIX",65535],["wgListenPort","WG listen",65535],["retentionHours","Хранение (часов)",2147483647],["topN","Top-N разговоров",1000]] as const) if (dirty.has(field)) { const raw = draft[field], value = Number(raw) if (!/^\d+$/.test(raw) || !Number.isSafeInteger(value) || value < 1 || value > max) throw new Error(label + ": укажите целое число от 1 до " + max) patch[field] = value } if (dirty.has("enabled")) patch.enabled = draft.enabled if (dirty.has("shareOn") || dirty.has("mapServiceMinSharePct")) { const value = Number(draft.mapServiceMinSharePct) if (draft.shareOn && (!/^\d+(?:\.\d+)?$/.test(draft.mapServiceMinSharePct) || !Number.isFinite(value) || value <= 0 || value > 100)) throw new Error("Порог карты: укажите долю больше 0 и не более 100%") patch.mapServiceMinSharePct = draft.shareOn ? value : 0 } const parsed = trafficFlowSettingsPatchSchema.safeParse(patch) if (!parsed.success) throw new Error(parsed.error.issues[0]?.message ?? "Укажите допустимые настройки NetFlow") return parsed.data }