Files
MyGoNavi/frontend/src/utils/jvmConnectionConfig.ts
Syngnat 6f14e827ab feat(jvm): 完成资源治理与诊断增强
- 新增 JMX/Endpoint/Agent 三种 JVM 连接模式与配置归一化链路
- 支持资源浏览、变更预览、写入应用、审计记录与只读约束
- 接入 AI 结构化写入计划与诊断计划回填能力
- 新增 Agent Bridge、Arthas Tunnel、JMX Helper 诊断传输实现
- 增加诊断控制台、命令模板、输出历史与自动补全交互
- 补齐前后端契约、运行夹具与 JVM 相关回归测试
2026-04-24 16:45:34 +08:00

266 lines
7.9 KiB
TypeScript

import type { ConnectionConfig } from "../types";
const DEFAULT_JMX_PORT = 9010;
const DEFAULT_TIMEOUT_SECONDS = 30;
const DEFAULT_DIAGNOSTIC_TIMEOUT_SECONDS = 15;
const DEFAULT_ENVIRONMENT = "dev";
const JVM_MODES = ["jmx", "endpoint", "agent"] as const;
export const JVM_EDITABLE_MODES = ["jmx", "endpoint", "agent"] as const;
const JVM_DIAGNOSTIC_TRANSPORTS = ["agent-bridge", "arthas-tunnel"] as const;
type JVMMode = (typeof JVM_MODES)[number];
type JVMEditableMode = (typeof JVM_EDITABLE_MODES)[number];
type JVMDiagnosticTransport = (typeof JVM_DIAGNOSTIC_TRANSPORTS)[number];
type JVMEnvironment = "dev" | "uat" | "prod";
type JVMConnectionFormValues = Record<string, unknown>;
const isJVMMode = (value: string): value is JVMMode =>
JVM_MODES.includes(value as JVMMode);
const isJVMEditableMode = (value: string): value is JVMEditableMode =>
JVM_EDITABLE_MODES.includes(value as JVMEditableMode);
const isJVMDiagnosticTransport = (
value: string,
): value is JVMDiagnosticTransport =>
JVM_DIAGNOSTIC_TRANSPORTS.includes(value as JVMDiagnosticTransport);
const toStringValue = (value: unknown): string => {
if (typeof value === "string") {
return value.trim();
}
if (typeof value === "number" || typeof value === "boolean") {
return String(value).trim();
}
return "";
};
const toInteger = (value: unknown, fallback: number): number => {
if (value === undefined || value === null || value === "") {
return fallback;
}
const parsed = Number(value);
if (!Number.isFinite(parsed)) {
return fallback;
}
const intValue = Math.trunc(parsed);
return intValue > 0 ? intValue : fallback;
};
const normalizeModes = (value: unknown): JVMMode[] => {
if (!Array.isArray(value)) {
return ["jmx"];
}
const result: JVMMode[] = [];
const seen = new Set<JVMMode>();
for (const item of value) {
const mode = toStringValue(item).toLowerCase();
if (!isJVMMode(mode) || seen.has(mode)) {
continue;
}
seen.add(mode);
result.push(mode);
}
return result.length > 0 ? result : ["jmx"];
};
export const normalizeEditableJVMModes = (
value: unknown,
): JVMEditableMode[] => {
if (!Array.isArray(value)) {
return ["jmx"];
}
const result: JVMEditableMode[] = [];
const seen = new Set<JVMEditableMode>();
for (const item of value) {
const mode = toStringValue(item).toLowerCase();
if (!isJVMEditableMode(mode) || seen.has(mode)) {
continue;
}
seen.add(mode);
result.push(mode);
}
return result.length > 0 ? result : ["jmx"];
};
export const hasUnsupportedJVMEditableModes = ({
allowedModes,
preferredMode,
}: {
allowedModes: unknown;
preferredMode: unknown;
}): boolean => {
const allowed = Array.isArray(allowedModes)
? allowedModes
.map((item) => toStringValue(item).toLowerCase())
.filter((item) => item !== "")
: [];
const preferred = toStringValue(preferredMode).toLowerCase();
return (
allowed.some((mode) => !isJVMEditableMode(mode)) ||
(preferred !== "" && !isJVMEditableMode(preferred))
);
};
export const hasUnsupportedJVMDiagnosticTransport = (
value: unknown,
): boolean => {
const transport = toStringValue(value).toLowerCase();
return transport !== "" && !isJVMDiagnosticTransport(transport);
};
export const resolveEditableJVMModeSelection = ({
allowedModes,
preferredMode,
}: {
allowedModes: unknown;
preferredMode: unknown;
}): { allowedModes: string[]; preferredMode: string } => {
const normalizedAllowedModes = Array.isArray(allowedModes)
? allowedModes
.map((item) => toStringValue(item).toLowerCase())
.filter((item) => item !== "")
: [];
const normalizedPreferredMode = toStringValue(preferredMode).toLowerCase();
const resolvedAllowedModes =
normalizedAllowedModes.length > 0
? Array.from(new Set(normalizedAllowedModes))
: normalizedPreferredMode
? [normalizedPreferredMode]
: ["jmx"];
return {
allowedModes: resolvedAllowedModes,
preferredMode: normalizedPreferredMode || resolvedAllowedModes[0],
};
};
const normalizePreferredMode = (
value: unknown,
allowedModes: JVMMode[],
): JVMMode => {
const preferred = toStringValue(value).toLowerCase();
if (isJVMMode(preferred) && allowedModes.includes(preferred)) {
return preferred;
}
return allowedModes[0];
};
const normalizeEnvironment = (value: unknown): JVMEnvironment => {
const env = toStringValue(value).toLowerCase();
if (env === "uat" || env === "prod") {
return env;
}
return DEFAULT_ENVIRONMENT;
};
const normalizeReadOnly = (value: unknown): boolean => {
if (typeof value === "boolean") {
return value;
}
return true;
};
const normalizeDiagnosticTransport = (
value: unknown,
): JVMDiagnosticTransport => {
const transport = toStringValue(value).toLowerCase();
if (isJVMDiagnosticTransport(transport)) {
return transport;
}
return "agent-bridge";
};
export const buildDefaultJVMConnectionValues = () => ({
type: "jvm",
host: "localhost",
port: DEFAULT_JMX_PORT,
jvmReadOnly: true,
jvmAllowedModes: ["jmx"],
jvmPreferredMode: "jmx",
jvmEnvironment: DEFAULT_ENVIRONMENT,
jvmEndpointEnabled: false,
jvmEndpointBaseUrl: "",
jvmEndpointApiKey: "",
jvmAgentEnabled: false,
jvmAgentBaseUrl: "",
jvmAgentApiKey: "",
jvmDiagnosticEnabled: false,
jvmDiagnosticTransport: "agent-bridge",
jvmDiagnosticBaseUrl: "",
jvmDiagnosticTargetId: "",
jvmDiagnosticApiKey: "",
jvmDiagnosticAllowObserveCommands: true,
jvmDiagnosticAllowTraceCommands: false,
jvmDiagnosticAllowMutatingCommands: false,
jvmDiagnosticTimeoutSeconds: DEFAULT_DIAGNOSTIC_TIMEOUT_SECONDS,
});
export const buildJVMConnectionConfig = (
values: JVMConnectionFormValues,
): ConnectionConfig => {
const allowedModes = normalizeModes(values.jvmAllowedModes);
const preferredMode = normalizePreferredMode(
values.jvmPreferredMode,
allowedModes,
);
const port = toInteger(values.port, DEFAULT_JMX_PORT);
const timeout =
values.timeout === undefined ||
values.timeout === null ||
values.timeout === ""
? toInteger(values.jvmEndpointTimeoutSeconds, DEFAULT_TIMEOUT_SECONDS)
: toInteger(values.timeout, DEFAULT_TIMEOUT_SECONDS);
const diagnosticTimeout = toInteger(
values.jvmDiagnosticTimeoutSeconds,
DEFAULT_DIAGNOSTIC_TIMEOUT_SECONDS,
);
return {
type: "jvm",
host: toStringValue(values.host),
port,
user: "",
password: "",
timeout,
jvm: {
environment: normalizeEnvironment(values.jvmEnvironment),
readOnly: normalizeReadOnly(values.jvmReadOnly),
allowedModes,
preferredMode,
jmx: {
enabled: allowedModes.includes("jmx"),
host: toStringValue(values.jvmJmxHost) || toStringValue(values.host),
port: toInteger(values.jvmJmxPort, port),
username: toStringValue(values.jvmJmxUsername),
password: toStringValue(values.jvmJmxPassword),
},
endpoint: {
enabled: values.jvmEndpointEnabled === true,
baseUrl: toStringValue(values.jvmEndpointBaseUrl),
apiKey: toStringValue(values.jvmEndpointApiKey),
timeoutSeconds: timeout,
},
agent: {
enabled: values.jvmAgentEnabled === true,
baseUrl: toStringValue(values.jvmAgentBaseUrl),
apiKey: toStringValue(values.jvmAgentApiKey),
timeoutSeconds: timeout,
},
diagnostic: {
enabled: values.jvmDiagnosticEnabled === true,
transport: normalizeDiagnosticTransport(values.jvmDiagnosticTransport),
baseUrl: toStringValue(values.jvmDiagnosticBaseUrl),
targetId: toStringValue(values.jvmDiagnosticTargetId),
apiKey: toStringValue(values.jvmDiagnosticApiKey),
allowObserveCommands: values.jvmDiagnosticAllowObserveCommands !== false,
allowTraceCommands: values.jvmDiagnosticAllowTraceCommands === true,
allowMutatingCommands:
values.jvmDiagnosticAllowMutatingCommands === true,
timeoutSeconds: diagnosticTimeout,
},
},
};
};