mirror of
https://github.com/Sagit-chu/flvx.git
synced 2026-09-28 07:36:38 +08:00
fix: use custom probe targets for diagnostics
Move custom probe target controls into the tunnel advanced settings and reuse the configured target in tunnel diagnosis output.
This commit is contained in:
@@ -978,6 +978,7 @@ func (h *Handler) prepareTunnelDiagnosis(tunnelID int64) (string, string, []diag
|
|||||||
|
|
||||||
ipPreference := h.repo.GetTunnelIPPreference(tunnelID)
|
ipPreference := h.repo.GetTunnelIPPreference(tunnelID)
|
||||||
protocol := strings.ToLower(strings.TrimSpace(tunnel.Protocol))
|
protocol := strings.ToLower(strings.TrimSpace(tunnel.Protocol))
|
||||||
|
probeTarget := effectiveTunnelProbeTargetValues(tunnel.ProbeTargetHost, tunnel.ProbeTargetPort)
|
||||||
inNodes, chainHops, outNodes := splitChainNodeGroups(chainRows)
|
inNodes, chainHops, outNodes := splitChainNodeGroups(chainRows)
|
||||||
workItems := make([]diagnosisWorkItem, 0, len(chainRows)*2)
|
workItems := make([]diagnosisWorkItem, 0, len(chainRows)*2)
|
||||||
|
|
||||||
@@ -987,8 +988,8 @@ func (h *Handler) prepareTunnelDiagnosis(tunnelID int64) (string, string, []diag
|
|||||||
description := fmt.Sprintf("入口(%s)->外网", inNode.NodeName)
|
description := fmt.Sprintf("入口(%s)->外网", inNode.NodeName)
|
||||||
workItems = append(workItems, diagnosisWorkItem{
|
workItems = append(workItems, diagnosisWorkItem{
|
||||||
fromNodeID: inNode.NodeID,
|
fromNodeID: inNode.NodeID,
|
||||||
targetIP: "www.bing.com",
|
targetIP: probeTarget.Host,
|
||||||
targetPort: 443,
|
targetPort: probeTarget.Port,
|
||||||
description: description,
|
description: description,
|
||||||
protocol: "tcp",
|
protocol: "tcp",
|
||||||
metadata: map[string]interface{}{
|
metadata: map[string]interface{}{
|
||||||
@@ -1079,8 +1080,8 @@ func (h *Handler) prepareTunnelDiagnosis(tunnelID int64) (string, string, []diag
|
|||||||
description := fmt.Sprintf("出口(%s)->外网", outNode.NodeName)
|
description := fmt.Sprintf("出口(%s)->外网", outNode.NodeName)
|
||||||
workItems = append(workItems, diagnosisWorkItem{
|
workItems = append(workItems, diagnosisWorkItem{
|
||||||
fromNodeID: outNode.NodeID,
|
fromNodeID: outNode.NodeID,
|
||||||
targetIP: "www.bing.com",
|
targetIP: probeTarget.Host,
|
||||||
targetPort: 443,
|
targetPort: probeTarget.Port,
|
||||||
description: description,
|
description: description,
|
||||||
protocol: "tcp",
|
protocol: "tcp",
|
||||||
metadata: map[string]interface{}{
|
metadata: map[string]interface{}{
|
||||||
@@ -1093,8 +1094,8 @@ func (h *Handler) prepareTunnelDiagnosis(tunnelID int64) (string, string, []diag
|
|||||||
description := fmt.Sprintf("入口(%s)->外网", inNode.NodeName)
|
description := fmt.Sprintf("入口(%s)->外网", inNode.NodeName)
|
||||||
workItems = append(workItems, diagnosisWorkItem{
|
workItems = append(workItems, diagnosisWorkItem{
|
||||||
fromNodeID: inNode.NodeID,
|
fromNodeID: inNode.NodeID,
|
||||||
targetIP: "www.bing.com",
|
targetIP: probeTarget.Host,
|
||||||
targetPort: 443,
|
targetPort: probeTarget.Port,
|
||||||
description: description,
|
description: description,
|
||||||
protocol: "tcp",
|
protocol: "tcp",
|
||||||
metadata: map[string]interface{}{
|
metadata: map[string]interface{}{
|
||||||
|
|||||||
@@ -209,6 +209,22 @@ func TestTunnelUpdateInvalidProbeTargetDoesNotCleanFederationBindings(t *testing
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTunnelDiagnosisUsesConfiguredProbeTarget(t *testing.T) {
|
||||||
|
h := setupProbeTargetTunnelHandler(t)
|
||||||
|
seedProbeTargetTunnel(t, h, 90, "diagnosis-target", "speed.example.com", 8443)
|
||||||
|
|
||||||
|
_, _, workItems, err := h.prepareTunnelDiagnosis(90)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("prepare tunnel diagnosis: %v", err)
|
||||||
|
}
|
||||||
|
if len(workItems) != 1 {
|
||||||
|
t.Fatalf("expected one diagnosis item, got %d", len(workItems))
|
||||||
|
}
|
||||||
|
if workItems[0].targetIP != "speed.example.com" || workItems[0].targetPort != 8443 {
|
||||||
|
t.Fatalf("expected custom diagnosis target speed.example.com:8443, got %s:%d", workItems[0].targetIP, workItems[0].targetPort)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func setupProbeTargetTunnelHandler(t *testing.T) *Handler {
|
func setupProbeTargetTunnelHandler(t *testing.T) *Handler {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
r, err := repo.Open(filepath.Join(t.TempDir(), "panel.db"))
|
r, err := repo.Open(filepath.Join(t.TempDir(), "panel.db"))
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ import { Alert } from "@/shadcn-bridge/heroui/alert";
|
|||||||
import { Checkbox } from "@/shadcn-bridge/heroui/checkbox";
|
import { Checkbox } from "@/shadcn-bridge/heroui/checkbox";
|
||||||
import { Progress } from "@/shadcn-bridge/heroui/progress";
|
import { Progress } from "@/shadcn-bridge/heroui/progress";
|
||||||
import { Radio, RadioGroup } from "@/shadcn-bridge/heroui/radio";
|
import { Radio, RadioGroup } from "@/shadcn-bridge/heroui/radio";
|
||||||
|
import { Accordion, AccordionItem } from "@/shadcn-bridge/heroui/accordion";
|
||||||
import {
|
import {
|
||||||
Table,
|
Table,
|
||||||
TableHeader,
|
TableHeader,
|
||||||
@@ -137,6 +138,14 @@ interface Tunnel {
|
|||||||
createdTime: string;
|
createdTime: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEFAULT_PROBE_TARGET_HOST = "www.bing.com";
|
||||||
|
const DEFAULT_PROBE_TARGET_PORT = 443;
|
||||||
|
|
||||||
|
const getTunnelDiagnosisTarget = (tunnel: Tunnel) => ({
|
||||||
|
targetIp: tunnel.probeTargetHost || DEFAULT_PROBE_TARGET_HOST,
|
||||||
|
targetPort: tunnel.probeTargetPort || DEFAULT_PROBE_TARGET_PORT,
|
||||||
|
});
|
||||||
|
|
||||||
interface Node {
|
interface Node {
|
||||||
id: number;
|
id: number;
|
||||||
name: string;
|
name: string;
|
||||||
@@ -902,6 +911,7 @@ export default function TunnelPage() {
|
|||||||
const handleDiagnose = async (tunnel: Tunnel) => {
|
const handleDiagnose = async (tunnel: Tunnel) => {
|
||||||
diagnosisAbortRef.current?.abort();
|
diagnosisAbortRef.current?.abort();
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
|
const diagnosisTarget = getTunnelDiagnosisTarget(tunnel);
|
||||||
|
|
||||||
diagnosisAbortRef.current = abortController;
|
diagnosisAbortRef.current = abortController;
|
||||||
|
|
||||||
@@ -1043,6 +1053,7 @@ export default function TunnelPage() {
|
|||||||
tunnelType: tunnel.type,
|
tunnelType: tunnel.type,
|
||||||
description: "诊断失败",
|
description: "诊断失败",
|
||||||
message: response.msg || "诊断过程中发生错误",
|
message: response.msg || "诊断过程中发生错误",
|
||||||
|
...diagnosisTarget,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
setDiagnosisProgress({
|
setDiagnosisProgress({
|
||||||
@@ -1074,6 +1085,7 @@ export default function TunnelPage() {
|
|||||||
tunnelType: tunnel.type,
|
tunnelType: tunnel.type,
|
||||||
description: "网络错误",
|
description: "网络错误",
|
||||||
message: "无法连接到服务器",
|
message: "无法连接到服务器",
|
||||||
|
...diagnosisTarget,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
setDiagnosisProgress({
|
setDiagnosisProgress({
|
||||||
@@ -2335,54 +2347,67 @@ export default function TunnelPage() {
|
|||||||
</Select>
|
</Select>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="rounded-xl border border-divider/60 bg-default-50/40 p-3 space-y-3">
|
<Accordion className="px-0" variant="light">
|
||||||
<div>
|
<AccordionItem
|
||||||
<div className="text-sm font-medium">质量检测目标</div>
|
key="advanced"
|
||||||
<p className="text-xs text-default-500 mt-0.5">
|
aria-label="高级设置"
|
||||||
用于实时隧道质量检测和 best 最优出口评分,留空使用
|
className="border-b-0 [&_[data-slot=accordion-trigger]]:no-underline [&_[data-slot=accordion-trigger]]:hover:no-underline"
|
||||||
www.bing.com:443
|
title={
|
||||||
</p>
|
<span className="text-small text-default-500 font-medium">
|
||||||
</div>
|
高级设置
|
||||||
<div className="grid grid-cols-1 md:grid-cols-[1fr_140px] gap-3">
|
</span>
|
||||||
<Input
|
}
|
||||||
errorMessage={errors.probeTargetHost}
|
>
|
||||||
isInvalid={!!errors.probeTargetHost}
|
<div className="space-y-4 pb-2">
|
||||||
label="Host"
|
<div>
|
||||||
placeholder="www.bing.com"
|
<div className="text-sm font-medium">质量检测目标</div>
|
||||||
value={form.probeTargetHost || ""}
|
<p className="text-xs text-default-500 mt-0.5">
|
||||||
variant="bordered"
|
用于实时隧道质量检测、诊断目标和 best
|
||||||
onChange={(e) =>
|
最优出口评分,留空使用 www.bing.com:443
|
||||||
setForm((prev) => ({
|
</p>
|
||||||
...prev,
|
</div>
|
||||||
probeTargetHost: e.target.value,
|
<div className="grid grid-cols-1 md:grid-cols-[1fr_140px] gap-3">
|
||||||
}))
|
<Input
|
||||||
}
|
errorMessage={errors.probeTargetHost}
|
||||||
/>
|
isInvalid={!!errors.probeTargetHost}
|
||||||
<Input
|
label="Host"
|
||||||
errorMessage={errors.probeTargetPort}
|
placeholder="www.bing.com"
|
||||||
isInvalid={!!errors.probeTargetPort}
|
value={form.probeTargetHost || ""}
|
||||||
label="Port"
|
variant="bordered"
|
||||||
max={65535}
|
onChange={(e) =>
|
||||||
min={1}
|
setForm((prev) => ({
|
||||||
placeholder="443"
|
...prev,
|
||||||
type="number"
|
probeTargetHost: e.target.value,
|
||||||
value={
|
}))
|
||||||
form.probeTargetPort
|
}
|
||||||
? String(form.probeTargetPort)
|
/>
|
||||||
: ""
|
<Input
|
||||||
}
|
errorMessage={errors.probeTargetPort}
|
||||||
variant="bordered"
|
isInvalid={!!errors.probeTargetPort}
|
||||||
onChange={(e) =>
|
label="Port"
|
||||||
setForm((prev) => ({
|
max={65535}
|
||||||
...prev,
|
min={1}
|
||||||
probeTargetPort: e.target.value
|
placeholder="443"
|
||||||
? Number(e.target.value)
|
type="number"
|
||||||
: 0,
|
value={
|
||||||
}))
|
form.probeTargetPort
|
||||||
}
|
? String(form.probeTargetPort)
|
||||||
/>
|
: ""
|
||||||
</div>
|
}
|
||||||
</div>
|
variant="bordered"
|
||||||
|
onChange={(e) =>
|
||||||
|
setForm((prev) => ({
|
||||||
|
...prev,
|
||||||
|
probeTargetPort: e.target.value
|
||||||
|
? Number(e.target.value)
|
||||||
|
: 0,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</AccordionItem>
|
||||||
|
</Accordion>
|
||||||
|
|
||||||
<Divider />
|
<Divider />
|
||||||
<h3 className="text-lg font-semibold">入口配置</h3>
|
<h3 className="text-lg font-semibold">入口配置</h3>
|
||||||
|
|||||||
@@ -27,6 +27,8 @@ export interface DiagnosisFallbackInput {
|
|||||||
tunnelType: number;
|
tunnelType: number;
|
||||||
description: string;
|
description: string;
|
||||||
message: string;
|
message: string;
|
||||||
|
targetIp?: string;
|
||||||
|
targetPort?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const buildDiagnosisFallbackResult = ({
|
export const buildDiagnosisFallbackResult = ({
|
||||||
@@ -34,6 +36,8 @@ export const buildDiagnosisFallbackResult = ({
|
|||||||
tunnelType,
|
tunnelType,
|
||||||
description,
|
description,
|
||||||
message,
|
message,
|
||||||
|
targetIp = "-",
|
||||||
|
targetPort = 443,
|
||||||
}: DiagnosisFallbackInput): DiagnosisResult => {
|
}: DiagnosisFallbackInput): DiagnosisResult => {
|
||||||
return {
|
return {
|
||||||
tunnelName,
|
tunnelName,
|
||||||
@@ -45,8 +49,8 @@ export const buildDiagnosisFallbackResult = ({
|
|||||||
description,
|
description,
|
||||||
nodeName: "-",
|
nodeName: "-",
|
||||||
nodeId: "-",
|
nodeId: "-",
|
||||||
targetIp: "-",
|
targetIp,
|
||||||
targetPort: 443,
|
targetPort,
|
||||||
message,
|
message,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
Reference in New Issue
Block a user