feat: implement internet path functionality with backend support
Added internet path settings and snapshot management to the application. This includes new database tables for internet path settings and snapshots, API routes for fetching and managing internet path data, and integration into the dashboard and data collection pages. Enhanced the scheduler to support internet path jobs, ensuring regular data collection and updates. Updated relevant types and interfaces to accommodate the new functionality.
This commit is contained in:
@@ -30,6 +30,7 @@ import {
|
||||
type AlertEngineRuleDiagSnapshot,
|
||||
type AlertEngineRunSnapshot,
|
||||
type GreBgpSnapshotRunSnapshot,
|
||||
type InternetPathRunSnapshot,
|
||||
type PingRunSnapshot,
|
||||
type ResourcesRunSnapshot,
|
||||
type SchedulerRunSnapshot,
|
||||
@@ -436,6 +437,33 @@ function SnapshotTables({ snap }: { snap: SchedulerRunSnapshot }) {
|
||||
</div>
|
||||
)
|
||||
}
|
||||
if (snap.job === "internet_path") {
|
||||
const p = snap as InternetPathRunSnapshot
|
||||
return (
|
||||
<div className="space-y-3">
|
||||
<p className="text-xs text-muted-foreground">
|
||||
Снимок internet-path на{" "}
|
||||
<span className="font-mono tabular-nums">{new Date(p.sampledAt).toLocaleString("ru-RU")}</span>
|
||||
</p>
|
||||
<dl className="grid grid-cols-2 gap-3 text-xs">
|
||||
<div>
|
||||
<dt className="text-muted-foreground">Home routers</dt>
|
||||
<dd className="font-mono font-medium">{p.homes}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt className="text-muted-foreground">Сохранение snapshot</dt>
|
||||
<dd className="font-mono font-medium">{p.snapshotSaved ? "ok" : "no"}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
{p.fatalError ? (
|
||||
<Alert variant="destructive" className="py-2">
|
||||
<AlertCircleIcon />
|
||||
<AlertDescription className="text-xs">Критическая ошибка: {p.fatalError}</AlertDescription>
|
||||
</Alert>
|
||||
) : null}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
if (snap.job === "alert_engine") {
|
||||
const a = snap as AlertEngineRunSnapshot
|
||||
const transitionRu = (t: AlertEngineRuleDiagSnapshot["hitTransition"]) => {
|
||||
@@ -640,6 +668,7 @@ export default function DataCollectionPage() {
|
||||
const [trafficCollector, setTrafficCollector] = useState<CollectorSettingsDto | null>(null)
|
||||
const [serversApiCollector, setServersApiCollector] = useState<CollectorSettingsDto | null>(null)
|
||||
const [uptimeCollector, setUptimeCollector] = useState<UptimeSettingsDto | null>(null)
|
||||
const [internetPathCollector, setInternetPathCollector] = useState<CollectorSettingsDto | null>(null)
|
||||
const [trafficIntervalDraft, setTrafficIntervalDraft] = useState("30")
|
||||
const [trafficRetentionDraft, setTrafficRetentionDraft] = useState("14")
|
||||
const [uptimeResourceIntervalDraft, setUptimeResourceIntervalDraft] = useState("300")
|
||||
@@ -652,6 +681,8 @@ export default function DataCollectionPage() {
|
||||
const [draftResourcesEnabled, setDraftResourcesEnabled] = useState(true)
|
||||
const [draftPingEnabled, setDraftPingEnabled] = useState(true)
|
||||
const [draftSpeedEnabled, setDraftSpeedEnabled] = useState(true)
|
||||
const [draftInternetPathEnabled, setDraftInternetPathEnabled] = useState(true)
|
||||
const [internetPathIntervalDraft, setInternetPathIntervalDraft] = useState("300")
|
||||
const [schedulerRuns, setSchedulerRuns] = useState<SchedulerRunRowDto[]>([])
|
||||
const [runFilterJobKey, setRunFilterJobKey] = useState<string>("")
|
||||
const [runNowJobKey, setRunNowJobKey] = useState<string | null>(null)
|
||||
@@ -683,15 +714,17 @@ export default function DataCollectionPage() {
|
||||
runFilterJobKey && SCHEDULER_JOB_KEYS.includes(runFilterJobKey as (typeof SCHEDULER_JOB_KEYS)[number])
|
||||
? `?limit=80&jobKey=${encodeURIComponent(runFilterJobKey)}`
|
||||
: "?limit=80"
|
||||
const [traffic, serversApi, uptime, runsRes] = await Promise.all([
|
||||
const [traffic, serversApi, uptime, internetPath, runsRes] = await Promise.all([
|
||||
apiFetch<CollectorSettingsDto>("/api/traffic/settings"),
|
||||
apiFetch<CollectorSettingsDto>("/api/servers-api-ping/settings"),
|
||||
apiFetch<UptimeSettingsDto>("/api/uptime/settings"),
|
||||
apiFetch<CollectorSettingsDto>("/api/internet-path/settings"),
|
||||
apiFetch<{ runs: SchedulerRunRowDto[] }>(`/api/scheduler/runs${runsQuery}`),
|
||||
])
|
||||
setTrafficCollector(traffic)
|
||||
setServersApiCollector(serversApi)
|
||||
setUptimeCollector(uptime)
|
||||
setInternetPathCollector(internetPath)
|
||||
setSchedulerRuns(runsRes.runs ?? [])
|
||||
setTrafficIntervalDraft(String(traffic.intervalSec))
|
||||
setTrafficRetentionDraft(String(traffic.retentionDays))
|
||||
@@ -705,6 +738,8 @@ export default function DataCollectionPage() {
|
||||
setDraftResourcesEnabled(!!(uptime.resourcesEnabled ?? uptime.enabled))
|
||||
setDraftPingEnabled(!!(uptime.pingEnabled ?? uptime.enabled))
|
||||
setDraftSpeedEnabled(!!(uptime.speedEnabled ?? uptime.enabled))
|
||||
setDraftInternetPathEnabled(!!internetPath.enabled)
|
||||
setInternetPathIntervalDraft(String(internetPath.intervalSec ?? 300))
|
||||
} catch (e) {
|
||||
setCollectorError(e instanceof Error ? e.message : "Не удалось загрузить данные")
|
||||
} finally {
|
||||
@@ -717,6 +752,7 @@ export default function DataCollectionPage() {
|
||||
setTrafficCollector(null)
|
||||
setServersApiCollector(null)
|
||||
setUptimeCollector(null)
|
||||
setInternetPathCollector(null)
|
||||
setSchedulerRuns([])
|
||||
return
|
||||
}
|
||||
@@ -744,8 +780,10 @@ export default function DataCollectionPage() {
|
||||
if (draftResourcesEnabled) n += 1
|
||||
if (draftPingEnabled) n += 1
|
||||
if (draftSpeedEnabled) n += 1
|
||||
if (draftInternetPathEnabled) n += 1
|
||||
return n
|
||||
}, [
|
||||
draftInternetPathEnabled,
|
||||
draftPingEnabled,
|
||||
draftResourcesEnabled,
|
||||
draftServersApiEnabled,
|
||||
@@ -905,44 +943,52 @@ export default function DataCollectionPage() {
|
||||
? draftTrafficEnabled
|
||||
: jobKey === "servers_rest_ping"
|
||||
? draftServersApiEnabled
|
||||
: jobKey === "uptime_resources"
|
||||
: jobKey === "uptime_resources"
|
||||
? draftResourcesEnabled
|
||||
: jobKey === "uptime_ping"
|
||||
? draftPingEnabled
|
||||
: draftSpeedEnabled
|
||||
: jobKey === "uptime_speed"
|
||||
? draftSpeedEnabled
|
||||
: draftInternetPathEnabled
|
||||
const iv = fixedSchedule
|
||||
? String(j?.intervalSec ?? (jobKey === "gre_bgp" ? 30 : 20))
|
||||
: jobKey === "traffic"
|
||||
? trafficIntervalDraft
|
||||
: jobKey === "servers_rest_ping"
|
||||
? serversApiIntervalDraft
|
||||
: jobKey === "uptime_resources"
|
||||
: jobKey === "uptime_resources"
|
||||
? uptimeResourceIntervalDraft
|
||||
: jobKey === "uptime_ping"
|
||||
? uptimeIntervalDraft
|
||||
: uptimeSpeedIntervalDraft
|
||||
: jobKey === "uptime_speed"
|
||||
? uptimeSpeedIntervalDraft
|
||||
: internetPathIntervalDraft
|
||||
const setIv = fixedSchedule
|
||||
? () => {}
|
||||
: jobKey === "traffic"
|
||||
? setTrafficIntervalDraft
|
||||
: jobKey === "servers_rest_ping"
|
||||
? setServersApiIntervalDraft
|
||||
: jobKey === "uptime_resources"
|
||||
: jobKey === "uptime_resources"
|
||||
? setUptimeResourceIntervalDraft
|
||||
: jobKey === "uptime_ping"
|
||||
? setUptimeIntervalDraft
|
||||
: setUptimeSpeedIntervalDraft
|
||||
: jobKey === "uptime_speed"
|
||||
? setUptimeSpeedIntervalDraft
|
||||
: setInternetPathIntervalDraft
|
||||
const defSec = fixedSchedule
|
||||
? Number(j?.intervalSec ?? (jobKey === "gre_bgp" ? 30 : 20))
|
||||
: jobKey === "traffic"
|
||||
? 30
|
||||
: jobKey === "servers_rest_ping"
|
||||
? 120
|
||||
: jobKey === "uptime_resources"
|
||||
: jobKey === "uptime_resources"
|
||||
? 300
|
||||
: jobKey === "uptime_ping"
|
||||
? 15
|
||||
: 60
|
||||
: jobKey === "uptime_speed"
|
||||
? 60
|
||||
: 300
|
||||
return (
|
||||
<tr key={jobKey} className="hover:bg-muted/40">
|
||||
<td className="px-5 py-3 align-top">
|
||||
@@ -962,7 +1008,8 @@ export default function DataCollectionPage() {
|
||||
else if (jobKey === "servers_rest_ping") setDraftServersApiEnabled(v)
|
||||
else if (jobKey === "uptime_resources") setDraftResourcesEnabled(v)
|
||||
else if (jobKey === "uptime_ping") setDraftPingEnabled(v)
|
||||
else setDraftSpeedEnabled(v)
|
||||
else if (jobKey === "uptime_speed") setDraftSpeedEnabled(v)
|
||||
else setDraftInternetPathEnabled(v)
|
||||
}}
|
||||
/>
|
||||
</span>
|
||||
@@ -1082,6 +1129,7 @@ export default function DataCollectionPage() {
|
||||
const uSpd = Math.max(10, Number.parseInt(uptimeSpeedIntervalDraft, 10) || 60)
|
||||
const uRet = Math.max(1, Number.parseInt(uptimeRetentionDraft, 10) || 14)
|
||||
const sApiInt = Math.max(10, Number.parseInt(serversApiIntervalDraft, 10) || 120)
|
||||
const ipInt = Math.max(30, Number.parseInt(internetPathIntervalDraft, 10) || 300)
|
||||
await apiFetch("/api/traffic/settings", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
@@ -1109,6 +1157,13 @@ export default function DataCollectionPage() {
|
||||
retentionDays: uRet,
|
||||
}),
|
||||
})
|
||||
await apiFetch("/api/internet-path/settings", {
|
||||
method: "PUT",
|
||||
body: JSON.stringify({
|
||||
enabled: draftInternetPathEnabled,
|
||||
intervalSec: ipInt,
|
||||
}),
|
||||
})
|
||||
await loadCollectors()
|
||||
} catch (e) {
|
||||
setCollectorError(e instanceof Error ? e.message : "Не удалось сохранить")
|
||||
@@ -1163,6 +1218,18 @@ export default function DataCollectionPage() {
|
||||
<p className={cn(uptimeCollector?.lastError ? "text-destructive" : "")}>
|
||||
{uptimeCollector?.lastError ? `Uptime: ${uptimeCollector.lastError}` : "Uptime: ошибок нет"}
|
||||
</p>
|
||||
<p>
|
||||
Internet Path snapshot:{" "}
|
||||
{internetPathCollector?.lastCollectedAt
|
||||
? new Date(internetPathCollector.lastCollectedAt).toLocaleString("ru-RU")
|
||||
: "—"}{" "}
|
||||
· {internetPathCollector?.lastDurationMs != null ? `${internetPathCollector.lastDurationMs} мс` : "—"}
|
||||
</p>
|
||||
<p className={cn(internetPathCollector?.lastError ? "text-destructive" : "")}>
|
||||
{internetPathCollector?.lastError
|
||||
? `Internet Path: ${internetPathCollector.lastError}`
|
||||
: "Internet Path: ошибок нет"}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</CardContent>
|
||||
|
||||
Reference in New Issue
Block a user