mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-30 02:14:43 +08:00
Refactor/simplify proxy logs (#585)
* refactor(proxy): simplify logging for better readability - Delete 17 verbose debug logs from handlers, streaming, and response_processor - Convert excessive INFO logs to DEBUG level for internal processing details - Add 2 critical INFO logs in forwarder.rs for failover scenarios: - Log when switching to next provider after failure - Log when all providers have been exhausted - Fix clippy uninlined_format_args warning This reduces log noise while maintaining visibility into key user-facing decisions. * fix: replace unsafe unwrap() calls with proper error handling - database/dao/mcp.rs: Use map_err for serde_json serialization - database/dao/providers.rs: Use map_err for settings_config and meta serialization - commands/misc.rs: Use expect() for compile-time regex pattern - services/prompt.rs: Use unwrap_or_default() for SystemTime - deeplink/provider.rs: Replace unwrap() with is_none_or pattern for Option checks Reduces potential panic points from 26 to 1 (static regex init, safe). * refactor(proxy): simplify verbose logging output - Remove response JSON full output logging in response_processor - Remove per-request INFO logs in provider_router (failover status, provider selection) - Change model mapping log from INFO to DEBUG - Change usage logging failure from INFO to WARN - Remove redundant debug logs for circuit breaker operations Reduces log noise significantly while preserving important warnings and errors. * feat(proxy): add structured log codes for i18n support Add error code system to proxy module logs for multi-language support: - CB-001~006: Circuit breaker state transitions and triggers - SRV-001~004: Proxy server lifecycle events - FWD-001~002: Request forwarding and failover - FO-001~005: Failover switch operations - USG-001~002: Usage logging errors Log format: [CODE] Chinese message Frontend/log tools can map codes to any language. New file: src/proxy/log_codes.rs - centralized code definitions * chore: bump version to 3.9.1 * style: format code with prettier and rustfmt * fix(ui): allow number inputs to be fully cleared before saving - Convert numeric state to string type for controlled inputs - Use isNaN() check instead of || fallback to allow 0 values - Apply fix to ProxyPanel, CircuitBreakerConfigPanel, AutoFailoverConfigPanel, and ModelTestConfigPanel * feat(pricing): support @ separator in model name matching - Refactor model name cleaning into chained method calls - Add @ to - replacement (e.g., gpt-5.2-codex@low → gpt-5.2-codex-low) - Add test case for @ separator matching * fix(proxy): improve validation and error handling in proxy config panels - Add StopTimeout/StopFailed error types for proper stop() error reporting - Replace silent clamp with validation-and-block in config panels - Add listenAddress format validation in ProxyPanel - Use log_codes constants instead of hardcoded strings - Use once_cell::Lazy for regex precompilation * fix(proxy): harden error handling and input validation - Handle RwLock poisoning in settings.rs with unwrap_or_else - Add fallback for dirs::home_dir() in config modules - Normalize localhost to 127.0.0.1 in ProxyPanel - Format IPv6 addresses with brackets for valid URLs - Strict port validation with pure digit regex - Treat NaN as validation failure in config panels - Log warning on cost_multiplier parse failure - Align timeoutSeconds range to [0, 300] across all panels
This commit is contained in:
@@ -38,15 +38,15 @@ export function ProxyPanel() {
|
||||
const { data: globalConfig } = useGlobalProxyConfig();
|
||||
const updateGlobalConfig = useUpdateGlobalProxyConfig();
|
||||
|
||||
// 监听地址/端口的本地状态
|
||||
// 监听地址/端口的本地状态(端口用字符串以支持完全清空)
|
||||
const [listenAddress, setListenAddress] = useState("127.0.0.1");
|
||||
const [listenPort, setListenPort] = useState(15721);
|
||||
const [listenPort, setListenPort] = useState("15721");
|
||||
|
||||
// 同步全局配置到本地状态
|
||||
useEffect(() => {
|
||||
if (globalConfig) {
|
||||
setListenAddress(globalConfig.listenAddress);
|
||||
setListenPort(globalConfig.listenPort);
|
||||
setListenPort(String(globalConfig.listenPort));
|
||||
}
|
||||
}, [globalConfig]);
|
||||
|
||||
@@ -102,12 +102,57 @@ export function ProxyPanel() {
|
||||
|
||||
const handleSaveBasicConfig = async () => {
|
||||
if (!globalConfig) return;
|
||||
|
||||
// 校验地址格式(简单的 IP 地址或 localhost 校验)
|
||||
const addressTrimmed = listenAddress.trim();
|
||||
const ipv4Regex = /^(\d{1,3}\.){3}\d{1,3}$/;
|
||||
// 规范化 localhost 为 127.0.0.1
|
||||
const normalizedAddress =
|
||||
addressTrimmed === "localhost" ? "127.0.0.1" : addressTrimmed;
|
||||
const isValidAddress =
|
||||
normalizedAddress === "0.0.0.0" ||
|
||||
(ipv4Regex.test(normalizedAddress) &&
|
||||
normalizedAddress.split(".").every((n) => {
|
||||
const num = parseInt(n);
|
||||
return num >= 0 && num <= 255;
|
||||
}));
|
||||
if (!isValidAddress) {
|
||||
toast.error(
|
||||
t("proxy.settings.invalidAddress", {
|
||||
defaultValue:
|
||||
"地址无效,请输入有效的 IP 地址(如 127.0.0.1)或 localhost",
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// 严格校验端口:必须是纯数字
|
||||
const portTrimmed = listenPort.trim();
|
||||
if (!/^\d+$/.test(portTrimmed)) {
|
||||
toast.error(
|
||||
t("proxy.settings.invalidPort", {
|
||||
defaultValue: "端口无效,请输入 1024-65535 之间的数字",
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
const port = parseInt(portTrimmed);
|
||||
if (isNaN(port) || port < 1024 || port > 65535) {
|
||||
toast.error(
|
||||
t("proxy.settings.invalidPort", {
|
||||
defaultValue: "端口无效,请输入 1024-65535 之间的数字",
|
||||
}),
|
||||
);
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await updateGlobalConfig.mutateAsync({
|
||||
...globalConfig,
|
||||
listenAddress,
|
||||
listenPort,
|
||||
listenAddress: normalizedAddress,
|
||||
listenPort: port,
|
||||
});
|
||||
// 同步更新本地状态为规范化后的值
|
||||
setListenAddress(normalizedAddress);
|
||||
toast.success(
|
||||
t("proxy.settings.configSaved", { defaultValue: "代理配置已保存" }),
|
||||
{ closeButton: true },
|
||||
@@ -133,6 +178,13 @@ export function ProxyPanel() {
|
||||
}
|
||||
};
|
||||
|
||||
// 格式化地址用于 URL(IPv6 需要方括号)
|
||||
const formatAddressForUrl = (address: string, port: number): string => {
|
||||
const isIPv6 = address.includes(":");
|
||||
const host = isIPv6 ? `[${address}]` : address;
|
||||
return `http://${host}:${port}`;
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
<section className="space-y-6">
|
||||
@@ -147,14 +199,14 @@ export function ProxyPanel() {
|
||||
</p>
|
||||
<div className="flex flex-col gap-2 sm:flex-row sm:items-center">
|
||||
<code className="flex-1 text-sm bg-background px-3 py-2 rounded border border-border/60">
|
||||
http://{status.address}:{status.port}
|
||||
{formatAddressForUrl(status.address, status.port)}
|
||||
</code>
|
||||
<Button
|
||||
size="sm"
|
||||
variant="outline"
|
||||
onClick={() => {
|
||||
navigator.clipboard.writeText(
|
||||
`http://${status.address}:${status.port}`,
|
||||
formatAddressForUrl(status.address, status.port),
|
||||
);
|
||||
toast.success(
|
||||
t("proxy.panel.addressCopied", {
|
||||
@@ -389,9 +441,12 @@ export function ProxyPanel() {
|
||||
id="listen-address"
|
||||
value={listenAddress}
|
||||
onChange={(e) => setListenAddress(e.target.value)}
|
||||
placeholder={t("proxy.settings.fields.listenAddress.placeholder", {
|
||||
defaultValue: "127.0.0.1",
|
||||
})}
|
||||
placeholder={t(
|
||||
"proxy.settings.fields.listenAddress.placeholder",
|
||||
{
|
||||
defaultValue: "127.0.0.1",
|
||||
},
|
||||
)}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{t("proxy.settings.fields.listenAddress.description", {
|
||||
@@ -411,12 +466,13 @@ export function ProxyPanel() {
|
||||
id="listen-port"
|
||||
type="number"
|
||||
value={listenPort}
|
||||
onChange={(e) =>
|
||||
setListenPort(parseInt(e.target.value) || 15721)
|
||||
}
|
||||
placeholder={t("proxy.settings.fields.listenPort.placeholder", {
|
||||
defaultValue: "15721",
|
||||
})}
|
||||
onChange={(e) => setListenPort(e.target.value)}
|
||||
placeholder={t(
|
||||
"proxy.settings.fields.listenPort.placeholder",
|
||||
{
|
||||
defaultValue: "15721",
|
||||
},
|
||||
)}
|
||||
/>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
{t("proxy.settings.fields.listenPort.description", {
|
||||
|
||||
Reference in New Issue
Block a user