feat(route-optimizer): refactor bandwidth scoring and enhance speed display in UI for improved clarity
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m38s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 1m38s
This commit is contained in:
@@ -77,7 +77,7 @@ function latencyScore(pingMs, aiSettings) {
|
||||
return clamp(normalized, 0, 1);
|
||||
}
|
||||
|
||||
function bandwidthScore(speedMbps, aiSettings) {
|
||||
function normalizeBandwidthValue(speedMbps, aiSettings) {
|
||||
if (typeof speedMbps !== 'number' || speedMbps <= 0) return aiSettings.noSpeedScore;
|
||||
// log-scale to avoid dominance by very high channels
|
||||
const normalized = Math.log10(1 + speedMbps) / Math.log10(1001);
|
||||
@@ -96,11 +96,29 @@ function freshnessScore(cacheUpdatedAt, aiSettings) {
|
||||
return aiSettings.staleScore;
|
||||
}
|
||||
|
||||
function buildSegmentScore({ pingMs, speedMbps, cacheUpdatedAt, aiSettings }) {
|
||||
function bandwidthScore({ speedDownloadMbps, speedUploadMbps, aiSettings }) {
|
||||
// DL/UL considered separately with equal 50/50 contribution.
|
||||
const dl = normalizeBandwidthValue(speedDownloadMbps, aiSettings);
|
||||
const ul = normalizeBandwidthValue(speedUploadMbps, aiSettings);
|
||||
return clamp((dl + ul) / 2, 0, 1);
|
||||
}
|
||||
|
||||
function buildSegmentScore({
|
||||
pingMs,
|
||||
speedMbps,
|
||||
speedDownloadMbps,
|
||||
speedUploadMbps,
|
||||
cacheUpdatedAt,
|
||||
aiSettings,
|
||||
}) {
|
||||
const l = latencyScore(pingMs, aiSettings);
|
||||
const b = bandwidthScore(speedMbps, aiSettings);
|
||||
const b = bandwidthScore({ speedDownloadMbps, speedUploadMbps, aiSettings });
|
||||
const f = freshnessScore(cacheUpdatedAt, aiSettings);
|
||||
const metricPresence = (typeof pingMs === 'number' ? 1 : 0) + (typeof speedMbps === 'number' ? 1 : 0);
|
||||
const hasAnySpeed =
|
||||
typeof speedMbps === 'number' ||
|
||||
typeof speedDownloadMbps === 'number' ||
|
||||
typeof speedUploadMbps === 'number';
|
||||
const metricPresence = (typeof pingMs === 'number' ? 1 : 0) + (hasAnySpeed ? 1 : 0);
|
||||
const confidence = metricPresence === 2 ? 1 : metricPresence === 1 ? 0.65 : 0.35;
|
||||
const score =
|
||||
l * aiSettings.latencyWeight +
|
||||
@@ -329,10 +347,24 @@ function buildInterfaceCandidates({ servers, tunnelInterfaces, pingMap, speedMap
|
||||
const speedEntry = asObject(speedMap[skey]);
|
||||
const downBps = toNumber(speedEntry.tcpDownloadBps);
|
||||
const upBps = toNumber(speedEntry.tcpUploadBps);
|
||||
const speedMbps = downBps != null || upBps != null
|
||||
? Math.max(downBps || 0, upBps || 0) / 1e6
|
||||
: null;
|
||||
const scoring = buildSegmentScore({ pingMs, speedMbps, cacheUpdatedAt, aiSettings });
|
||||
const speedDownloadMbps = downBps != null ? downBps / 1e6 : null;
|
||||
const speedUploadMbps = upBps != null ? upBps / 1e6 : null;
|
||||
const speedMbps =
|
||||
speedDownloadMbps != null && speedUploadMbps != null
|
||||
? (speedDownloadMbps + speedUploadMbps) / 2
|
||||
: speedDownloadMbps != null
|
||||
? speedDownloadMbps
|
||||
: speedUploadMbps != null
|
||||
? speedUploadMbps
|
||||
: null;
|
||||
const scoring = buildSegmentScore({
|
||||
pingMs,
|
||||
speedMbps,
|
||||
speedDownloadMbps,
|
||||
speedUploadMbps,
|
||||
cacheUpdatedAt,
|
||||
aiSettings,
|
||||
});
|
||||
|
||||
const base = {
|
||||
interfaceName: iface.name || null,
|
||||
@@ -340,8 +372,8 @@ function buildInterfaceCandidates({ servers, tunnelInterfaces, pingMap, speedMap
|
||||
remoteIp: iface.remoteIp || null,
|
||||
pingMs,
|
||||
speedMbps: speedMbps != null ? Number(speedMbps.toFixed(2)) : null,
|
||||
speedDownloadMbps: downBps != null ? Number((downBps / 1e6).toFixed(2)) : null,
|
||||
speedUploadMbps: upBps != null ? Number((upBps / 1e6).toFixed(2)) : null,
|
||||
speedDownloadMbps: speedDownloadMbps != null ? Number(speedDownloadMbps.toFixed(2)) : null,
|
||||
speedUploadMbps: speedUploadMbps != null ? Number(speedUploadMbps.toFixed(2)) : null,
|
||||
score: Number(scoring.score.toFixed(4)),
|
||||
confidence: Number(scoring.confidence.toFixed(4)),
|
||||
};
|
||||
@@ -639,6 +671,8 @@ function buildCommunityOptimization({
|
||||
probabilityOptimal: currentCandidate.probabilityOptimal,
|
||||
pingMs: currentCandidate.pingMs,
|
||||
speedMbps: currentCandidate.speedMbps,
|
||||
speedDownloadMbps: currentCandidate.speedDownloadMbps,
|
||||
speedUploadMbps: currentCandidate.speedUploadMbps,
|
||||
} : null,
|
||||
recommended: recommendedCandidate ? {
|
||||
gateway: recommendedCandidate.recursiveGateway || recommendedCandidate.gatewayIpForJumphost || null,
|
||||
@@ -650,6 +684,8 @@ function buildCommunityOptimization({
|
||||
probabilityOptimal: recommendedCandidate.probabilityOptimal,
|
||||
pingMs: recommendedCandidate.pingMs,
|
||||
speedMbps: recommendedCandidate.speedMbps,
|
||||
speedDownloadMbps: recommendedCandidate.speedDownloadMbps,
|
||||
speedUploadMbps: recommendedCandidate.speedUploadMbps,
|
||||
} : null,
|
||||
pinnedGateway: pinned?.gateway || null,
|
||||
pinnedBySettings: Boolean(pinned),
|
||||
@@ -721,6 +757,8 @@ async function getRouteOptimizer(req, res) {
|
||||
interfaceName: hj.interfaceName,
|
||||
pingMs: hj.pingMs,
|
||||
speedMbps: hj.speedMbps,
|
||||
speedDownloadMbps: hj.speedDownloadMbps,
|
||||
speedUploadMbps: hj.speedUploadMbps,
|
||||
score: hj.score,
|
||||
confidence: hj.confidence,
|
||||
},
|
||||
@@ -728,6 +766,8 @@ async function getRouteOptimizer(req, res) {
|
||||
interfaceName: jhExit.interfaceName,
|
||||
pingMs: jhExit.pingMs,
|
||||
speedMbps: jhExit.speedMbps,
|
||||
speedDownloadMbps: jhExit.speedDownloadMbps,
|
||||
speedUploadMbps: jhExit.speedUploadMbps,
|
||||
score: jhExit.score,
|
||||
confidence: jhExit.confidence,
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user