mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-31 02:51:21 +08:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 483256ad92 |
+5
-3
@@ -29,7 +29,7 @@ import {
|
||||
import { getCurrentWindow } from "@tauri-apps/api/window";
|
||||
import type { Provider, VisibleApps } from "@/types";
|
||||
import type { EnvConflict } from "@/types/env";
|
||||
import { useProvidersQuery, useSettingsQuery } from "@/lib/query";
|
||||
import { proxyKeys, useProvidersQuery, useSettingsQuery } from "@/lib/query";
|
||||
import {
|
||||
providersApi,
|
||||
settingsApi,
|
||||
@@ -389,8 +389,10 @@ function App() {
|
||||
await queryClient.invalidateQueries({ queryKey: ["profiles"] });
|
||||
await queryClient.invalidateQueries({ queryKey: ["mcp", "all"] });
|
||||
await queryClient.invalidateQueries({ queryKey: ["skills"] });
|
||||
await queryClient.invalidateQueries({ queryKey: ["proxyTakeoverStatus"] });
|
||||
await queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: proxyKeys.takeoverStatus,
|
||||
});
|
||||
await queryClient.invalidateQueries({ queryKey: proxyKeys.status });
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["providers", "claude-desktop"],
|
||||
});
|
||||
|
||||
@@ -15,12 +15,12 @@ import { Switch } from "@/components/ui/switch";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { ToggleRow } from "@/components/ui/toggle-row";
|
||||
import { useProxyStatus } from "@/hooks/useProxyStatus";
|
||||
import { toast } from "sonner";
|
||||
import { useFailoverQueue } from "@/lib/query/failover";
|
||||
import { ProviderHealthBadge } from "@/components/providers/ProviderHealthBadge";
|
||||
import { useProviderHealth } from "@/lib/query/failover";
|
||||
import {
|
||||
useProxyStatusQuery,
|
||||
useProxyTakeoverStatus,
|
||||
useSetProxyTakeoverForApp,
|
||||
useGlobalProxyConfig,
|
||||
@@ -45,7 +45,8 @@ export function ProxyPanel({
|
||||
isProxyPending,
|
||||
}: ProxyPanelProps) {
|
||||
const { t } = useTranslation();
|
||||
const { status, isRunning } = useProxyStatus();
|
||||
const { data: status } = useProxyStatusQuery();
|
||||
const isRunning = status?.running ?? false;
|
||||
|
||||
// 获取应用接管状态
|
||||
const { data: takeoverStatus } = useProxyTakeoverStatus();
|
||||
|
||||
+19
-88
@@ -2,15 +2,15 @@
|
||||
* 代理服务状态管理 Hook
|
||||
*/
|
||||
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { toast } from "sonner";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type {
|
||||
ProxyStatus,
|
||||
ProxyServerInfo,
|
||||
ProxyTakeoverStatus,
|
||||
} from "@/types/proxy";
|
||||
import { proxyApi } from "@/lib/api/proxy";
|
||||
import {
|
||||
proxyKeys,
|
||||
useProxyStatusQuery,
|
||||
useProxyTakeoverStatus,
|
||||
} from "@/lib/query/proxy";
|
||||
import { extractErrorMessage } from "@/utils/errorUtils";
|
||||
|
||||
/**
|
||||
@@ -21,25 +21,14 @@ export function useProxyStatus() {
|
||||
const { t } = useTranslation();
|
||||
|
||||
// 查询状态(自动轮询)
|
||||
const { data: status, isLoading } = useQuery({
|
||||
queryKey: ["proxyStatus"],
|
||||
queryFn: () => invoke<ProxyStatus>("get_proxy_status"),
|
||||
// 仅在服务运行时轮询
|
||||
refetchInterval: (query) => (query.state.data?.running ? 2000 : false),
|
||||
// 保持之前的数据,避免闪烁
|
||||
placeholderData: (previousData) => previousData,
|
||||
});
|
||||
const { data: status } = useProxyStatusQuery();
|
||||
|
||||
// 查询各应用接管状态
|
||||
const { data: takeoverStatus } = useQuery({
|
||||
queryKey: ["proxyTakeoverStatus"],
|
||||
queryFn: () => invoke<ProxyTakeoverStatus>("get_proxy_takeover_status"),
|
||||
placeholderData: (previousData) => previousData,
|
||||
});
|
||||
const { data: takeoverStatus } = useProxyTakeoverStatus(false);
|
||||
|
||||
// 启动服务器(总开关:仅启动服务,不接管)
|
||||
const startProxyServerMutation = useMutation({
|
||||
mutationFn: () => invoke<ProxyServerInfo>("start_proxy_server"),
|
||||
mutationFn: () => proxyApi.startProxyServer(),
|
||||
onSuccess: (info) => {
|
||||
toast.success(
|
||||
t("proxy.server.started", {
|
||||
@@ -49,7 +38,7 @@ export function useProxyStatus() {
|
||||
}),
|
||||
{ closeButton: true },
|
||||
);
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
|
||||
queryClient.invalidateQueries({ queryKey: proxyKeys.status });
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
const detail =
|
||||
@@ -66,7 +55,7 @@ export function useProxyStatus() {
|
||||
|
||||
// 停止服务器(仅停止服务,不改写/恢复其它应用接管状态)
|
||||
const stopProxyServerMutation = useMutation({
|
||||
mutationFn: () => invoke("stop_proxy_server"),
|
||||
mutationFn: () => proxyApi.stopProxyServer(),
|
||||
onSuccess: () => {
|
||||
toast.success(
|
||||
t("proxy.server.stopped", {
|
||||
@@ -74,7 +63,7 @@ export function useProxyStatus() {
|
||||
}),
|
||||
{ closeButton: true },
|
||||
);
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
|
||||
queryClient.invalidateQueries({ queryKey: proxyKeys.status });
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
const detail =
|
||||
@@ -91,7 +80,7 @@ export function useProxyStatus() {
|
||||
|
||||
// 停止服务器(总开关关闭:强制恢复所有已接管的 Live 配置)
|
||||
const stopWithRestoreMutation = useMutation({
|
||||
mutationFn: () => invoke("stop_proxy_with_restore"),
|
||||
mutationFn: () => proxyApi.stopProxyWithRestore(),
|
||||
onSuccess: () => {
|
||||
toast.success(
|
||||
t("proxy.stoppedWithRestore", {
|
||||
@@ -99,8 +88,8 @@ export function useProxyStatus() {
|
||||
}),
|
||||
{ closeButton: true },
|
||||
);
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyTakeoverStatus"] });
|
||||
queryClient.invalidateQueries({ queryKey: proxyKeys.status });
|
||||
queryClient.invalidateQueries({ queryKey: proxyKeys.takeoverStatus });
|
||||
// 彻底删除所有供应商健康状态缓存(后端已清空数据库记录)
|
||||
queryClient.removeQueries({ queryKey: ["providerHealth"] });
|
||||
// 彻底删除所有熔断器统计缓存(代理停止后熔断器状态已重置)
|
||||
@@ -123,7 +112,7 @@ export function useProxyStatus() {
|
||||
// 按应用开启/关闭接管
|
||||
const setTakeoverForAppMutation = useMutation({
|
||||
mutationFn: ({ appType, enabled }: { appType: string; enabled: boolean }) =>
|
||||
invoke("set_proxy_takeover_for_app", { appType, enabled }),
|
||||
proxyApi.setProxyTakeoverForApp(appType, enabled),
|
||||
onSuccess: (_data, variables) => {
|
||||
const appLabel =
|
||||
variables.appType === "claude"
|
||||
@@ -149,8 +138,8 @@ export function useProxyStatus() {
|
||||
{ closeButton: true },
|
||||
);
|
||||
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyTakeoverStatus"] });
|
||||
queryClient.invalidateQueries({ queryKey: proxyKeys.status });
|
||||
queryClient.invalidateQueries({ queryKey: proxyKeys.takeoverStatus });
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
const detail =
|
||||
@@ -165,60 +154,10 @@ export function useProxyStatus() {
|
||||
},
|
||||
});
|
||||
|
||||
// 代理模式切换供应商(热切换)
|
||||
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) ||
|
||||
t("common.unknown", { defaultValue: "未知错误" });
|
||||
toast.error(
|
||||
t("proxy.switchFailed", {
|
||||
error: detail,
|
||||
defaultValue: `切换失败: ${detail}`,
|
||||
}),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
// 检查是否运行中
|
||||
const checkRunning = async () => {
|
||||
try {
|
||||
return await invoke<boolean>("is_proxy_running");
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
// 检查接管状态
|
||||
const checkTakeoverActive = async () => {
|
||||
try {
|
||||
return await invoke<boolean>("is_live_takeover_active");
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
return {
|
||||
status,
|
||||
isLoading,
|
||||
isRunning: status?.running || false,
|
||||
takeoverStatus,
|
||||
isTakeoverActive:
|
||||
takeoverStatus?.claude ||
|
||||
takeoverStatus?.codex ||
|
||||
takeoverStatus?.gemini ||
|
||||
takeoverStatus?.grokbuild ||
|
||||
false,
|
||||
|
||||
// 启动/停止(总开关)
|
||||
startProxyServer: startProxyServerMutation.mutateAsync,
|
||||
@@ -228,17 +167,9 @@ export function useProxyStatus() {
|
||||
// 按应用接管开关
|
||||
setTakeoverForApp: setTakeoverForAppMutation.mutateAsync,
|
||||
|
||||
// 代理模式下切换供应商
|
||||
switchProxyProvider: switchProxyProviderMutation.mutateAsync,
|
||||
|
||||
// 状态检查
|
||||
checkRunning,
|
||||
checkTakeoverActive,
|
||||
|
||||
// 加载状态
|
||||
isStarting: startProxyServerMutation.isPending,
|
||||
isStoppingServer: stopProxyServerMutation.isPending,
|
||||
isStopping: stopWithRestoreMutation.isPending,
|
||||
isPending:
|
||||
startProxyServerMutation.isPending ||
|
||||
stopProxyServerMutation.isPending ||
|
||||
|
||||
+5
-31
@@ -1,6 +1,5 @@
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import type {
|
||||
ProxyConfig,
|
||||
ProxyStatus,
|
||||
ProxyServerInfo,
|
||||
ProxyTakeoverStatus,
|
||||
@@ -16,6 +15,11 @@ export const proxyApi = {
|
||||
return invoke("start_proxy_server");
|
||||
},
|
||||
|
||||
// 停止代理服务器(不恢复已接管配置)
|
||||
async stopProxyServer(): Promise<void> {
|
||||
return invoke("stop_proxy_server");
|
||||
},
|
||||
|
||||
// 停止代理服务器并恢复配置
|
||||
async stopProxyWithRestore(): Promise<void> {
|
||||
return invoke("stop_proxy_with_restore");
|
||||
@@ -26,24 +30,6 @@ export const proxyApi = {
|
||||
return invoke("get_proxy_status");
|
||||
},
|
||||
|
||||
// 检查代理服务器是否正在运行
|
||||
async isProxyRunning(): Promise<boolean> {
|
||||
return invoke("is_proxy_running");
|
||||
},
|
||||
|
||||
// 检查是否处于接管模式
|
||||
async isLiveTakeoverActive(): Promise<boolean> {
|
||||
return invoke("is_live_takeover_active");
|
||||
},
|
||||
|
||||
// 代理模式下切换供应商
|
||||
async switchProxyProvider(
|
||||
appType: string,
|
||||
providerId: string,
|
||||
): Promise<void> {
|
||||
return invoke("switch_proxy_provider", { appType, providerId });
|
||||
},
|
||||
|
||||
// ========== 接管状态 API ==========
|
||||
|
||||
// 获取各应用接管状态
|
||||
@@ -59,18 +45,6 @@ export const proxyApi = {
|
||||
return invoke("set_proxy_takeover_for_app", { appType, enabled });
|
||||
},
|
||||
|
||||
// ========== Legacy 代理配置 API (兼容) ==========
|
||||
|
||||
// 获取代理配置(旧版 v2 兼容接口)
|
||||
async getProxyConfig(): Promise<ProxyConfig> {
|
||||
return invoke("get_proxy_config");
|
||||
},
|
||||
|
||||
// 更新代理配置(旧版 v2 兼容接口)
|
||||
async updateProxyConfig(config: ProxyConfig): Promise<void> {
|
||||
return invoke("update_proxy_config", { config });
|
||||
},
|
||||
|
||||
// ========== v3+ 全局/应用级配置 API ==========
|
||||
|
||||
// 获取全局代理配置
|
||||
|
||||
@@ -3,6 +3,7 @@ import { failoverApi } from "@/lib/api/failover";
|
||||
import { toast } from "sonner";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { extractErrorMessage } from "@/utils/errorUtils";
|
||||
import { proxyKeys } from "@/lib/query/proxy";
|
||||
|
||||
// ========== 熔断器 Hooks ==========
|
||||
|
||||
@@ -47,7 +48,7 @@ export function useResetCircuitBreaker() {
|
||||
});
|
||||
// 刷新代理状态(更新 active_targets)
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["proxyStatus"],
|
||||
queryKey: proxyKeys.status,
|
||||
});
|
||||
},
|
||||
});
|
||||
@@ -283,7 +284,7 @@ export function useSetAutoFailoverEnabled() {
|
||||
queryKey: ["providers", variables.appType],
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["proxyStatus"],
|
||||
queryKey: proxyKeys.status,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
@@ -9,6 +9,7 @@ import { extractErrorMessage } from "@/utils/errorUtils";
|
||||
import { generateUUID } from "@/utils/uuid";
|
||||
import { openclawKeys } from "@/hooks/useOpenClaw";
|
||||
import { invalidateHermesProviderCaches } from "@/hooks/useHermes";
|
||||
import { proxyKeys } from "@/lib/query/proxy";
|
||||
import { usageKeys } from "@/lib/query/usage";
|
||||
import {
|
||||
CODEX_OFFICIAL_PROVIDER_ID,
|
||||
@@ -286,7 +287,7 @@ export const useSwitchProviderMutation = (appId: AppId) => {
|
||||
onSuccess: async () => {
|
||||
await queryClient.invalidateQueries({ queryKey: ["providers", appId] });
|
||||
if (appId === "claude-desktop") {
|
||||
await queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
|
||||
await queryClient.invalidateQueries({ queryKey: proxyKeys.status });
|
||||
await queryClient.invalidateQueries({
|
||||
queryKey: ["claudeDesktopStatus"],
|
||||
});
|
||||
|
||||
+34
-136
@@ -2,90 +2,54 @@ import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { proxyApi } from "@/lib/api/proxy";
|
||||
import { toast } from "sonner";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import type { GlobalProxyConfig, AppProxyConfig } from "@/types/proxy";
|
||||
import type {
|
||||
GlobalProxyConfig,
|
||||
AppProxyConfig,
|
||||
ProxyTakeoverStatus,
|
||||
} from "@/types/proxy";
|
||||
|
||||
export const proxyKeys = {
|
||||
status: ["proxyStatus"] as const,
|
||||
takeoverStatus: ["proxyTakeoverStatus"] as const,
|
||||
globalConfig: ["globalProxyConfig"] as const,
|
||||
appConfig: (appType: string) => ["appProxyConfig", appType] as const,
|
||||
};
|
||||
|
||||
// ========== 代理服务器状态 Hooks ==========
|
||||
|
||||
/**
|
||||
* 获取代理服务器状态
|
||||
*/
|
||||
export function useProxyStatus() {
|
||||
export function useProxyStatusQuery() {
|
||||
return useQuery({
|
||||
queryKey: ["proxyStatus"],
|
||||
queryKey: proxyKeys.status,
|
||||
queryFn: () => proxyApi.getProxyStatus(),
|
||||
refetchInterval: 5000, // 每 5 秒刷新一次
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查代理服务器是否运行
|
||||
*/
|
||||
export function useIsProxyRunning() {
|
||||
return useQuery({
|
||||
queryKey: ["proxyRunning"],
|
||||
queryFn: () => proxyApi.isProxyRunning(),
|
||||
refetchInterval: 2000,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查是否处于接管模式
|
||||
*/
|
||||
export function useIsLiveTakeoverActive() {
|
||||
return useQuery({
|
||||
queryKey: ["liveTakeoverActive"],
|
||||
queryFn: () => proxyApi.isLiveTakeoverActive(),
|
||||
refetchInterval: 2000,
|
||||
// 仅在服务运行时轮询
|
||||
refetchInterval: (query) => (query.state.data?.running ? 2000 : false),
|
||||
// 保持之前的数据,避免闪烁
|
||||
placeholderData: (previousData) => previousData,
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取各应用接管状态
|
||||
*/
|
||||
export function useProxyTakeoverStatus() {
|
||||
export function useProxyTakeoverStatus(poll = true) {
|
||||
return useQuery({
|
||||
queryKey: ["proxyTakeoverStatus"],
|
||||
queryKey: proxyKeys.takeoverStatus,
|
||||
queryFn: () => proxyApi.getProxyTakeoverStatus(),
|
||||
refetchInterval: 2000,
|
||||
refetchInterval: poll ? 2000 : false,
|
||||
...(poll
|
||||
? {}
|
||||
: {
|
||||
placeholderData: (previousData: ProxyTakeoverStatus | undefined) =>
|
||||
previousData,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
// ========== 代理服务器控制 Hooks ==========
|
||||
|
||||
/**
|
||||
* 启动代理服务器
|
||||
*/
|
||||
export function useStartProxyServer() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: () => proxyApi.startProxyServer(),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyRunning"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["liveTakeoverActive"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyTakeoverStatus"] });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 停止代理服务器
|
||||
*/
|
||||
export function useStopProxyServer() {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: () => proxyApi.stopProxyWithRestore(),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyRunning"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["liveTakeoverActive"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyTakeoverStatus"] });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置应用接管状态
|
||||
*/
|
||||
@@ -96,75 +60,11 @@ export function useSetProxyTakeoverForApp() {
|
||||
mutationFn: ({ appType, enabled }: { appType: string; enabled: boolean }) =>
|
||||
proxyApi.setProxyTakeoverForApp(appType, enabled),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyTakeoverStatus"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["liveTakeoverActive"] });
|
||||
queryClient.invalidateQueries({ queryKey: proxyKeys.takeoverStatus });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 代理模式下切换供应商
|
||||
*/
|
||||
export function useSwitchProxyProvider() {
|
||||
const queryClient = useQueryClient();
|
||||
const { t } = useTranslation();
|
||||
|
||||
return useMutation({
|
||||
mutationFn: ({
|
||||
appType,
|
||||
providerId,
|
||||
}: {
|
||||
appType: string;
|
||||
providerId: string;
|
||||
}) => proxyApi.switchProxyProvider(appType, providerId),
|
||||
onSuccess: (_, variables) => {
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["providers", variables.appType],
|
||||
});
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
toast.error(t("proxy.switchFailed", { error: error.message }));
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
// ========== Legacy 代理配置 Hooks (兼容) ==========
|
||||
|
||||
/**
|
||||
* 获取代理配置(旧版)
|
||||
*/
|
||||
export function useProxyConfig() {
|
||||
const queryClient = useQueryClient();
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { data: config, isLoading } = useQuery({
|
||||
queryKey: ["proxyConfig"],
|
||||
queryFn: () => proxyApi.getProxyConfig(),
|
||||
});
|
||||
|
||||
const updateMutation = useMutation({
|
||||
mutationFn: proxyApi.updateProxyConfig,
|
||||
onSuccess: () => {
|
||||
toast.success(t("proxy.settings.toast.saved"), { closeButton: true });
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyConfig"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
toast.error(
|
||||
t("proxy.settings.toast.saveFailed", { error: error.message }),
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
config,
|
||||
isLoading,
|
||||
updateConfig: updateMutation.mutateAsync,
|
||||
isUpdating: updateMutation.isPending,
|
||||
};
|
||||
}
|
||||
|
||||
// ========== v3+ 全局/应用级配置 Hooks ==========
|
||||
|
||||
/**
|
||||
@@ -172,7 +72,7 @@ export function useProxyConfig() {
|
||||
*/
|
||||
export function useGlobalProxyConfig() {
|
||||
return useQuery({
|
||||
queryKey: ["globalProxyConfig"],
|
||||
queryKey: proxyKeys.globalConfig,
|
||||
queryFn: () => proxyApi.getGlobalProxyConfig(),
|
||||
});
|
||||
}
|
||||
@@ -189,9 +89,8 @@ export function useUpdateGlobalProxyConfig() {
|
||||
proxyApi.updateGlobalProxyConfig(config),
|
||||
onSuccess: () => {
|
||||
toast.success(t("proxy.settings.toast.saved"), { closeButton: true });
|
||||
queryClient.invalidateQueries({ queryKey: ["globalProxyConfig"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyConfig"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
|
||||
queryClient.invalidateQueries({ queryKey: proxyKeys.globalConfig });
|
||||
queryClient.invalidateQueries({ queryKey: proxyKeys.status });
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
toast.error(
|
||||
@@ -206,7 +105,7 @@ export function useUpdateGlobalProxyConfig() {
|
||||
*/
|
||||
export function useAppProxyConfig(appType: string) {
|
||||
return useQuery({
|
||||
queryKey: ["appProxyConfig", appType],
|
||||
queryKey: proxyKeys.appConfig(appType),
|
||||
queryFn: () => proxyApi.getProxyConfigForApp(appType),
|
||||
enabled: !!appType,
|
||||
});
|
||||
@@ -225,14 +124,13 @@ export function useUpdateAppProxyConfig() {
|
||||
onSuccess: (_, variables) => {
|
||||
toast.success(t("proxy.settings.toast.saved"), { closeButton: true });
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["appProxyConfig", variables.appType],
|
||||
queryKey: proxyKeys.appConfig(variables.appType),
|
||||
});
|
||||
queryClient.invalidateQueries({
|
||||
queryKey: ["autoFailoverEnabled", variables.appType],
|
||||
});
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyConfig"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["circuitBreakerConfig"] });
|
||||
queryClient.invalidateQueries({ queryKey: ["proxyStatus"] });
|
||||
queryClient.invalidateQueries({ queryKey: proxyKeys.status });
|
||||
},
|
||||
onError: (error: Error) => {
|
||||
toast.error(
|
||||
|
||||
@@ -22,17 +22,10 @@ vi.mock("react-i18next", () => ({
|
||||
|
||||
vi.mock("@/hooks/useProxyStatus", () => ({
|
||||
useProxyStatus: () => ({
|
||||
status: null,
|
||||
isLoading: false,
|
||||
isRunning: false,
|
||||
isTakeoverActive: false,
|
||||
startWithTakeover: vi.fn(),
|
||||
takeoverStatus: null,
|
||||
startProxyServer: vi.fn(),
|
||||
stopWithRestore: vi.fn(),
|
||||
switchProxyProvider: vi.fn(),
|
||||
checkRunning: vi.fn(),
|
||||
checkTakeoverActive: vi.fn(),
|
||||
isStarting: false,
|
||||
isStopping: false,
|
||||
isPending: false,
|
||||
}),
|
||||
}));
|
||||
|
||||
@@ -3,6 +3,7 @@ import { renderHook, act, waitFor } from "@testing-library/react";
|
||||
import { QueryClientProvider } from "@tanstack/react-query";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { useProxyStatus } from "@/hooks/useProxyStatus";
|
||||
import { proxyKeys } from "@/lib/query/proxy";
|
||||
import { createTestQueryClient } from "../utils/testQueryClient";
|
||||
|
||||
const toastSuccessMock = vi.fn();
|
||||
@@ -99,12 +100,19 @@ describe("useProxyStatus", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("keeps the established proxy query key shapes", () => {
|
||||
expect(proxyKeys.status).toEqual(["proxyStatus"]);
|
||||
expect(proxyKeys.takeoverStatus).toEqual(["proxyTakeoverStatus"]);
|
||||
expect(proxyKeys.globalConfig).toEqual(["globalProxyConfig"]);
|
||||
expect(proxyKeys.appConfig("claude")).toEqual(["appProxyConfig", "claude"]);
|
||||
});
|
||||
|
||||
it("shows interpolated address and port after proxy server starts", async () => {
|
||||
const { wrapper } = createWrapper();
|
||||
const { result } = renderHook(() => useProxyStatus(), { wrapper });
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.isLoading).toBe(false);
|
||||
expect(result.current.status).toBeDefined();
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
@@ -115,5 +123,12 @@ describe("useProxyStatus", () => {
|
||||
"代理服务已启动 - 127.0.0.1:15721",
|
||||
{ closeButton: true },
|
||||
);
|
||||
|
||||
await act(async () => {
|
||||
await result.current.stopProxyServer();
|
||||
});
|
||||
|
||||
expect(invokeMock).toHaveBeenCalledWith("start_proxy_server");
|
||||
expect(invokeMock).toHaveBeenCalledWith("stop_proxy_server");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user