feat(InterfaceSpeedTest, MikrotikConfigRoutes): enhance speed test functionality with cache handling and force refresh options
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m53s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m53s
This commit is contained in:
@@ -851,7 +851,7 @@ function parseSpeedToBps(val) {
|
||||
*/
|
||||
async function speedTestViaTunnel(req, res) {
|
||||
try {
|
||||
const { serverId, interfaceName } = req.body || {};
|
||||
const { serverId, interfaceName, cacheOnly, forceRefresh } = req.body || {};
|
||||
let { durationSeconds } = req.body || {};
|
||||
|
||||
if (!serverId || !interfaceName) {
|
||||
@@ -864,6 +864,39 @@ async function speedTestViaTunnel(req, res) {
|
||||
}
|
||||
|
||||
const uiSettings = await loadUiSettings();
|
||||
const cacheMinutes = Math.max(
|
||||
0,
|
||||
parseInt(uiSettings.interfaceSpeedTestCacheMinutes, 10) || 0
|
||||
);
|
||||
const cacheKey =
|
||||
cacheMinutes > 0
|
||||
? speedTestCacheKey(serverId, interfaceName)
|
||||
: null;
|
||||
|
||||
// При выборе сервера/интерфейса — только кеш. При нажатии «Замерить» — принудительно новый замер (forceRefresh).
|
||||
const skipCacheRead = forceRefresh === true;
|
||||
|
||||
if (!skipCacheRead && cacheKey) {
|
||||
try {
|
||||
const raw = await readS3TextObject(cacheKey).catch(() => null);
|
||||
if (raw?.body) {
|
||||
const cached = JSON.parse(raw.body);
|
||||
const cachedAt =
|
||||
typeof cached.cachedAt === 'number' ? cached.cachedAt : 0;
|
||||
const ttlMs = cacheMinutes * 60 * 1000;
|
||||
if (cachedAt && Date.now() - cachedAt < ttlMs) {
|
||||
return res.json({ ...cached, cached: true });
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
// Если кеш не прочитался — продолжаем без него
|
||||
}
|
||||
}
|
||||
|
||||
if (cacheOnly === true) {
|
||||
return res.json({ ok: false, notInCache: true });
|
||||
}
|
||||
|
||||
const defaultDuration = Math.max(
|
||||
1,
|
||||
Math.min(
|
||||
@@ -882,32 +915,6 @@ async function speedTestViaTunnel(req, res) {
|
||||
)
|
||||
);
|
||||
|
||||
const cacheMinutes = Math.max(
|
||||
0,
|
||||
parseInt(uiSettings.interfaceSpeedTestCacheMinutes, 10) || 0
|
||||
);
|
||||
const cacheKey =
|
||||
cacheMinutes > 0
|
||||
? speedTestCacheKey(serverId, interfaceName)
|
||||
: null;
|
||||
|
||||
if (cacheKey) {
|
||||
try {
|
||||
const raw = await readS3TextObject(cacheKey).catch(() => null);
|
||||
if (raw?.body) {
|
||||
const cached = JSON.parse(raw.body);
|
||||
const cachedAt =
|
||||
typeof cached.cachedAt === 'number' ? cached.cachedAt : 0;
|
||||
const ttlMs = cacheMinutes * 60 * 1000;
|
||||
if (cachedAt && Date.now() - cachedAt < ttlMs) {
|
||||
return res.json({ ...cached, cached: true });
|
||||
}
|
||||
}
|
||||
} catch (_) {
|
||||
// Если кеш не прочитался — продолжаем без него
|
||||
}
|
||||
}
|
||||
|
||||
const config = await loadNetworkConfig();
|
||||
const tunnelIfaces = Array.isArray(config.tunnelInterfaces)
|
||||
? config.tunnelInterfaces
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useEffect, useMemo, useState } from 'react';
|
||||
import { useCallback, useEffect, useMemo, useState } from 'react';
|
||||
import api from './lib/api.js';
|
||||
import { useNotify } from './components/NotifyProvider.jsx';
|
||||
import PageHeader from './components/PageHeader.jsx';
|
||||
@@ -167,6 +167,33 @@ export default function InterfaceSpeedTest() {
|
||||
return `${mbps.toFixed(2)} Мбит/с`;
|
||||
};
|
||||
|
||||
/** Запросить только кеш (без замера). При выборе сервера/интерфейса показываем кеш, если есть. */
|
||||
const fetchCachedResult = useCallback(async () => {
|
||||
if (!serverId || !selectedInterfaceName) {
|
||||
setSpeedResult(null);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const res = await api.post('/mikrotik/speed-test', {
|
||||
serverId,
|
||||
interfaceName: selectedInterfaceName,
|
||||
cacheOnly: true,
|
||||
});
|
||||
const data = res?.data || {};
|
||||
if (data.ok !== false && !data.notInCache && (data.tcpDownloadBps != null || data.tcpUploadBps != null)) {
|
||||
setSpeedResult(data);
|
||||
} else {
|
||||
setSpeedResult(null);
|
||||
}
|
||||
} catch {
|
||||
setSpeedResult(null);
|
||||
}
|
||||
}, [serverId, selectedInterfaceName]);
|
||||
|
||||
useEffect(() => {
|
||||
fetchCachedResult();
|
||||
}, [fetchCachedResult]);
|
||||
|
||||
const handleRunTest = async () => {
|
||||
if (!serverId) {
|
||||
notify.error('Выберите сервер (jumphost/home) для замера скорости');
|
||||
@@ -185,9 +212,9 @@ export default function InterfaceSpeedTest() {
|
||||
serverId,
|
||||
interfaceName: selectedInterfaceName,
|
||||
durationSeconds: speedSettings.durationSeconds,
|
||||
forceRefresh: true,
|
||||
};
|
||||
const res = await api.post('/mikrotik/speed-test', body, {
|
||||
// speed-test может занимать дольше стандартных 30 секунд
|
||||
timeout: 120000,
|
||||
});
|
||||
const data = res?.data || {};
|
||||
|
||||
Reference in New Issue
Block a user