fix(proxy): resolve 404 error and auto-setup proxy targets

Issues fixed:
1. Route prefix mismatch - Live config was set to use /claude, /codex,
   /gemini prefixes but server only had routes without prefixes
2. Proxy targets not auto-configured - start_with_takeover only modified
   Live config but didn't set is_proxy_target=true for current providers

Changes:
- Add prefixed routes (/claude/v1/messages, /codex/v1/*, /gemini/v1beta/*)
  to server.rs for backward compatibility
- Remove URL prefixes from takeover_live_configs() - server can route
  by API endpoint path alone (/v1/messages=Claude, /v1/chat/completions=Codex)
- Add setup_proxy_targets() method that automatically sets current providers
  as proxy targets when starting proxy with takeover
- Unify proxy toggle in SettingsPage to use takeover mode (same as main UI)
- Fix error message extraction in useProxyStatus hooks
- Fix provider switch logic to check both takeover flag AND proxy running state
This commit is contained in:
Jason
2025-12-10 19:58:43 +08:00
parent 3cdce2eced
commit 5cc864c6aa
17 changed files with 831 additions and 47 deletions
+108 -7
View File
@@ -5,13 +5,16 @@
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { invoke } from "@tauri-apps/api/core";
import { toast } from "sonner";
import { useTranslation } from "react-i18next";
import type { ProxyStatus, ProxyServerInfo } from "@/types/proxy";
import { extractErrorMessage } from "@/utils/errorUtils";
/**
* 代理服务状态管理
*/
export function useProxyStatus() {
const queryClient = useQueryClient();
const { t } = useTranslation();
// 查询状态(自动轮询)
const { data: status, isLoading } = useQuery({
@@ -23,7 +26,13 @@ export function useProxyStatus() {
placeholderData: (previousData) => previousData,
});
// 启动服务器
// 查询接管状态
const { data: isTakeoverActive } = useQuery({
queryKey: ["proxyTakeoverActive"],
queryFn: () => invoke<boolean>("is_live_takeover_active"),
});
// 启动服务器(普通模式)
const startMutation = useMutation({
mutationFn: () => invoke<ProxyServerInfo>("start_proxy_server"),
onSuccess: (info) => {
@@ -31,11 +40,34 @@ export function useProxyStatus() {
queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
},
onError: (error: Error) => {
toast.error(`启动失败: ${error.message}`);
const detail = extractErrorMessage(error) || "未知错误";
toast.error(`启动失败: ${detail}`);
},
});
// 停止服务器
// 启动服务器(带 Live 配置接管)
const startWithTakeoverMutation = useMutation({
mutationFn: () => invoke<ProxyServerInfo>("start_proxy_with_takeover"),
onSuccess: (info) => {
toast.success(
t("proxy.startedWithTakeover", {
defaultValue: `代理模式已启用 - ${info.address}:${info.port}`,
}),
);
queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
queryClient.invalidateQueries({ queryKey: ["proxyTakeoverActive"] });
},
onError: (error: Error) => {
const detail = extractErrorMessage(error) || "未知错误";
toast.error(
t("proxy.startWithTakeoverFailed", {
defaultValue: `启动失败: ${detail}`,
}),
);
},
});
// 停止服务器(普通模式)
const stopMutation = useMutation({
mutationFn: () => invoke("stop_proxy_server"),
onSuccess: () => {
@@ -43,7 +75,48 @@ export function useProxyStatus() {
queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
},
onError: (error: Error) => {
toast.error(`停止失败: ${error.message}`);
const detail = extractErrorMessage(error) || "未知错误";
toast.error(`停止失败: ${detail}`);
},
});
// 停止服务器(恢复 Live 配置)
const stopWithRestoreMutation = useMutation({
mutationFn: () => invoke("stop_proxy_with_restore"),
onSuccess: () => {
toast.success(
t("proxy.stoppedWithRestore", {
defaultValue: "代理模式已关闭,配置已恢复",
}),
);
queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
queryClient.invalidateQueries({ queryKey: ["proxyTakeoverActive"] });
},
onError: (error: Error) => {
const detail = extractErrorMessage(error) || "未知错误";
toast.error(
t("proxy.stopWithRestoreFailed", {
defaultValue: `停止失败: ${detail}`,
}),
);
},
});
// 代理模式切换供应商(热切换)
const switchProxyProviderMutation = useMutation({
mutationFn: ({
appType,
providerId,
}: {
appType: string;
providerId: string;
}) => invoke("switch_proxy_provider", { appType, providerId }),
onSuccess: () => {
queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
},
onError: (error: Error) => {
const detail = extractErrorMessage(error) || "未知错误";
toast.error(`切换失败: ${detail}`);
},
});
@@ -56,15 +129,43 @@ export function useProxyStatus() {
}
};
// 检查接管状态
const checkTakeoverActive = async () => {
try {
return await invoke<boolean>("is_live_takeover_active");
} catch {
return false;
}
};
return {
status,
isLoading,
isRunning: status?.running || false,
isTakeoverActive: isTakeoverActive || false,
// 普通模式
start: startMutation.mutateAsync,
stop: stopMutation.mutateAsync,
// 接管模式(推荐使用)
startWithTakeover: startWithTakeoverMutation.mutateAsync,
stopWithRestore: stopWithRestoreMutation.mutateAsync,
// 代理模式下切换供应商
switchProxyProvider: switchProxyProviderMutation.mutateAsync,
// 状态检查
checkRunning,
isStarting: startMutation.isPending,
isStopping: stopMutation.isPending,
isPending: startMutation.isPending || stopMutation.isPending,
checkTakeoverActive,
// 加载状态
isStarting: startMutation.isPending || startWithTakeoverMutation.isPending,
isStopping: stopMutation.isPending || stopWithRestoreMutation.isPending,
isPending:
startMutation.isPending ||
stopMutation.isPending ||
startWithTakeoverMutation.isPending ||
stopWithRestoreMutation.isPending,
};
}