refactor(NetworkMap): unify ping handling by implementing edge-based keying for ping timestamps in NetworkMapDashboard and NetworkMapUnifi components
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m59s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m59s
This commit is contained in:
@@ -139,11 +139,13 @@ export default function NetworkMapDashboard() {
|
|||||||
}
|
}
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
/** Один ключ пинга на ребро (маршруты статичны — одна сторона) */
|
||||||
|
const edgePingKey = (a, b) => [String(a), String(b)].sort().join(':');
|
||||||
|
|
||||||
const requestPings = useCallback(async () => {
|
const requestPings = useCallback(async () => {
|
||||||
if (connections.length === 0) return;
|
if (connections.length === 0) return;
|
||||||
pingAbortRef.current = false;
|
pingAbortRef.current = false;
|
||||||
setPingLoading(true);
|
setPingLoading(true);
|
||||||
const key = (a, b) => `${a}:${b}`;
|
|
||||||
const ttlMs = Math.max(0, (pingCacheSeconds || 0) * 1000);
|
const ttlMs = Math.max(0, (pingCacheSeconds || 0) * 1000);
|
||||||
|
|
||||||
const tasks = [];
|
const tasks = [];
|
||||||
@@ -158,26 +160,12 @@ export default function NetworkMapDashboard() {
|
|||||||
const canPingTo =
|
const canPingTo =
|
||||||
srcTo && ['jumphost', 'home'].includes(String(srcTo.type || '').toLowerCase()) && c.internalToFrom;
|
srcTo && ['jumphost', 'home'].includes(String(srcTo.type || '').toLowerCase()) && c.internalToFrom;
|
||||||
|
|
||||||
// Проверка кеша: если TTL не истёк, не запускаем новый запрос
|
const ekey = edgePingKey(from, to);
|
||||||
const keyFromTo = key(from, to);
|
if (ttlMs > 0 && pingTimestampsRef.current[ekey] && Date.now() - pingTimestampsRef.current[ekey] < ttlMs) {
|
||||||
const keyToFrom = key(to, from);
|
return;
|
||||||
const now = Date.now();
|
|
||||||
if (ttlMs > 0) {
|
|
||||||
const tsFrom = pingTimestampsRef.current[keyFromTo];
|
|
||||||
if (tsFrom && now - tsFrom < ttlMs) {
|
|
||||||
// уже есть актуальное значение для from->to
|
|
||||||
} else if (!canPingFrom) {
|
|
||||||
// если пинговать нельзя, но кеша нет — оставляем как есть
|
|
||||||
}
|
|
||||||
const tsTo = pingTimestampsRef.current[keyToFrom];
|
|
||||||
if (tsTo && now - tsTo < ttlMs) {
|
|
||||||
// уже есть актуальное значение для to->from
|
|
||||||
} else if (!canPingTo) {
|
|
||||||
// нельзя пинговать и кеша нет — пропускаем
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Пингуем по ВНУТРЕННИМ адресам туннеля из /network-config
|
// Один пинг на ребро — с той стороны, где есть jumphost
|
||||||
if (canPingFrom) {
|
if (canPingFrom) {
|
||||||
tasks.push(async () => {
|
tasks.push(async () => {
|
||||||
if (pingAbortRef.current) return;
|
if (pingAbortRef.current) return;
|
||||||
@@ -189,16 +177,14 @@ export default function NetworkMapDashboard() {
|
|||||||
count: 3,
|
count: 3,
|
||||||
});
|
});
|
||||||
const ms = typeof data?.avgMs === 'number' ? Math.round(data.avgMs) : null;
|
const ms = typeof data?.avgMs === 'number' ? Math.round(data.avgMs) : null;
|
||||||
pingTimestampsRef.current[keyFromTo] = Date.now();
|
pingTimestampsRef.current[ekey] = Date.now();
|
||||||
setPingMap((prev) => ({ ...prev, [keyFromTo]: ms }));
|
setPingMap((prev) => ({ ...prev, [ekey]: ms }));
|
||||||
} catch {
|
} catch {
|
||||||
pingTimestampsRef.current[keyFromTo] = Date.now();
|
pingTimestampsRef.current[ekey] = Date.now();
|
||||||
setPingMap((prev) => ({ ...prev, [keyFromTo]: null }));
|
setPingMap((prev) => ({ ...prev, [ekey]: null }));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
} else if (canPingTo) {
|
||||||
|
|
||||||
if (canPingTo) {
|
|
||||||
tasks.push(async () => {
|
tasks.push(async () => {
|
||||||
if (pingAbortRef.current) return;
|
if (pingAbortRef.current) return;
|
||||||
try {
|
try {
|
||||||
@@ -209,11 +195,11 @@ export default function NetworkMapDashboard() {
|
|||||||
count: 3,
|
count: 3,
|
||||||
});
|
});
|
||||||
const ms = typeof data?.avgMs === 'number' ? Math.round(data.avgMs) : null;
|
const ms = typeof data?.avgMs === 'number' ? Math.round(data.avgMs) : null;
|
||||||
pingTimestampsRef.current[keyToFrom] = Date.now();
|
pingTimestampsRef.current[ekey] = Date.now();
|
||||||
setPingMap((prev) => ({ ...prev, [keyToFrom]: ms }));
|
setPingMap((prev) => ({ ...prev, [ekey]: ms }));
|
||||||
} catch {
|
} catch {
|
||||||
pingTimestampsRef.current[keyToFrom] = Date.now();
|
pingTimestampsRef.current[ekey] = Date.now();
|
||||||
setPingMap((prev) => ({ ...prev, [keyToFrom]: null }));
|
setPingMap((prev) => ({ ...prev, [ekey]: null }));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,18 +183,16 @@ export default function NetworkMapUnifi({ servers = [], connections = [], pingMa
|
|||||||
[getSvgCoords, positions]
|
[getSvgCoords, positions]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const edgePingKey = (a, b) => [String(a), String(b)].sort().join(':');
|
||||||
|
|
||||||
const edgesWithPing = useMemo(() => {
|
const edgesWithPing = useMemo(() => {
|
||||||
return (connections || []).map((c) => {
|
return (connections || []).map((c) => {
|
||||||
const from = String(c.from);
|
const from = String(c.from);
|
||||||
const to = String(c.to);
|
const to = String(c.to);
|
||||||
const p1 = positions[from];
|
const p1 = positions[from];
|
||||||
const p2 = positions[to];
|
const p2 = positions[to];
|
||||||
const fwd = pingMap[`${from}:${to}`];
|
const ms = pingMap[edgePingKey(from, to)];
|
||||||
const rev = pingMap[`${to}:${from}`];
|
const pingLabel = typeof ms === 'number' ? `${ms} ms` : null;
|
||||||
const parts = [];
|
|
||||||
if (typeof fwd === 'number') parts.push(`→ ${fwd} ms`);
|
|
||||||
if (typeof rev === 'number') parts.push(`← ${rev} ms`);
|
|
||||||
const pingLabel = parts.length ? parts.join(' ') : null;
|
|
||||||
const sk = speedKey(c.fromKey, c.toKey);
|
const sk = speedKey(c.fromKey, c.toKey);
|
||||||
const speed = speedMap[sk];
|
const speed = speedMap[sk];
|
||||||
const speedLabel =
|
const speedLabel =
|
||||||
@@ -435,8 +433,7 @@ export default function NetworkMapUnifi({ servers = [], connections = [], pingMa
|
|||||||
{selectedEdge && (() => {
|
{selectedEdge && (() => {
|
||||||
const fromServer = servers.find((s) => String(s.ip) === selectedEdge.from);
|
const fromServer = servers.find((s) => String(s.ip) === selectedEdge.from);
|
||||||
const toServer = servers.find((s) => String(s.ip) === selectedEdge.to);
|
const toServer = servers.find((s) => String(s.ip) === selectedEdge.to);
|
||||||
const fwd = pingMap[`${selectedEdge.from}:${selectedEdge.to}`];
|
const pingMs = pingMap[edgePingKey(selectedEdge.from, selectedEdge.to)];
|
||||||
const rev = pingMap[`${selectedEdge.to}:${selectedEdge.from}`];
|
|
||||||
const sk = speedKey(selectedEdge.raw?.fromKey, selectedEdge.raw?.toKey);
|
const sk = speedKey(selectedEdge.raw?.fromKey, selectedEdge.raw?.toKey);
|
||||||
const speed = speedMap[sk] ?? selectedEdge.speed;
|
const speed = speedMap[sk] ?? selectedEdge.speed;
|
||||||
return (
|
return (
|
||||||
@@ -520,14 +517,7 @@ export default function NetworkMapUnifi({ servers = [], connections = [], pingMa
|
|||||||
Пинг
|
Пинг
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<div>
|
{typeof pingMs === 'number' ? `${pingMs} ms` : 'нет данных'}
|
||||||
<span className="text-muted">→ </span>
|
|
||||||
{typeof fwd === 'number' ? `${fwd} ms` : 'нет данных'}
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<span className="text-muted">← </span>
|
|
||||||
{typeof rev === 'number' ? `${rev} ms` : 'нет данных'}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{speed && (speed.tcpDownloadBps != null || speed.tcpUploadBps != null) && (
|
{speed && (speed.tcpDownloadBps != null || speed.tcpUploadBps != null) && (
|
||||||
|
|||||||
Reference in New Issue
Block a user