mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-28 16:56:16 +08:00
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:
@@ -40,6 +40,7 @@ interface ProviderCardProps {
|
||||
onTest?: (provider: Provider) => void;
|
||||
isTesting?: boolean;
|
||||
isProxyRunning: boolean;
|
||||
isProxyTakeover?: boolean; // 代理接管模式(Live配置已被接管,切换为热切换)
|
||||
proxyPriority?: number; // 代理目标的实际优先级 (1, 2, 3...)
|
||||
allProviders?: Provider[]; // 所有供应商列表,用于计算开启后的优先级
|
||||
dragHandleProps?: DragHandleProps;
|
||||
@@ -93,6 +94,7 @@ export function ProviderCard({
|
||||
onTest,
|
||||
isTesting,
|
||||
isProxyRunning,
|
||||
isProxyTakeover = false,
|
||||
proxyPriority,
|
||||
allProviders,
|
||||
dragHandleProps,
|
||||
@@ -231,7 +233,12 @@ export function ProviderCard({
|
||||
className={cn(
|
||||
"relative overflow-hidden rounded-xl border border-border p-4 transition-all duration-300",
|
||||
"bg-card text-card-foreground group hover:border-border-active",
|
||||
isCurrent ? "border-primary/50 shadow-sm" : "hover:shadow-sm",
|
||||
// 代理接管模式下当前供应商使用绿色边框
|
||||
isProxyTakeover && isCurrent
|
||||
? "border-emerald-500/60 shadow-sm shadow-emerald-500/10"
|
||||
: isCurrent
|
||||
? "border-primary/50 shadow-sm"
|
||||
: "hover:shadow-sm",
|
||||
dragHandleProps?.isDragging &&
|
||||
"cursor-grabbing border-primary shadow-lg scale-105 z-10",
|
||||
)}
|
||||
|
||||
@@ -27,6 +27,7 @@ interface ProviderListProps {
|
||||
onCreate?: () => void;
|
||||
isLoading?: boolean;
|
||||
isProxyRunning?: boolean; // 代理服务运行状态
|
||||
isProxyTakeover?: boolean; // 代理接管模式(Live配置已被接管)
|
||||
}
|
||||
|
||||
export function ProviderList({
|
||||
@@ -42,6 +43,7 @@ export function ProviderList({
|
||||
onCreate,
|
||||
isLoading = false,
|
||||
isProxyRunning = false, // 默认值为 false
|
||||
isProxyTakeover = false, // 默认值为 false
|
||||
}: ProviderListProps) {
|
||||
const { sortedProviders, sensors, handleDragEnd } = useDragSort(
|
||||
providers,
|
||||
@@ -122,6 +124,7 @@ export function ProviderList({
|
||||
onTest={handleTest}
|
||||
isTesting={isTesting(provider.id)}
|
||||
isProxyRunning={isProxyRunning}
|
||||
isProxyTakeover={isProxyTakeover}
|
||||
proxyPriority={proxyPriorityMap.get(provider.id)}
|
||||
allProviders={sortedProviders}
|
||||
/>
|
||||
@@ -145,6 +148,7 @@ interface SortableProviderCardProps {
|
||||
onTest: (provider: Provider) => void;
|
||||
isTesting: boolean;
|
||||
isProxyRunning: boolean;
|
||||
isProxyTakeover: boolean;
|
||||
proxyPriority?: number; // 代理目标的实际优先级 (1, 2, 3...)
|
||||
allProviders?: Provider[]; // 所有供应商列表
|
||||
}
|
||||
@@ -162,6 +166,7 @@ function SortableProviderCard({
|
||||
onTest,
|
||||
isTesting,
|
||||
isProxyRunning,
|
||||
isProxyTakeover,
|
||||
proxyPriority,
|
||||
allProviders,
|
||||
}: SortableProviderCardProps) {
|
||||
@@ -196,6 +201,7 @@ function SortableProviderCard({
|
||||
onTest={onTest}
|
||||
isTesting={isTesting}
|
||||
isProxyRunning={isProxyRunning}
|
||||
isProxyTakeover={isProxyTakeover}
|
||||
proxyPriority={proxyPriority}
|
||||
allProviders={allProviders}
|
||||
dragHandleProps={{
|
||||
|
||||
@@ -18,8 +18,11 @@ export interface AutoFailoverConfigPanelProps {
|
||||
|
||||
export function AutoFailoverConfigPanel({
|
||||
enabled,
|
||||
onEnabledChange,
|
||||
onEnabledChange: _onEnabledChange,
|
||||
}: AutoFailoverConfigPanelProps) {
|
||||
// Note: onEnabledChange is currently unused but kept in the interface
|
||||
// for potential future use by parent components
|
||||
void _onEnabledChange;
|
||||
const { t } = useTranslation();
|
||||
const { data: config, isLoading, error } = useCircuitBreakerConfig();
|
||||
const updateConfig = useUpdateCircuitBreakerConfig();
|
||||
@@ -262,7 +265,7 @@ export function AutoFailoverConfigPanel({
|
||||
</Button>
|
||||
<Button
|
||||
onClick={handleSave}
|
||||
disabled={updateConfig.isPending || !formData.enabled}
|
||||
disabled={updateConfig.isPending || !enabled}
|
||||
>
|
||||
{updateConfig.isPending ? (
|
||||
<>
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* 代理模式切换开关组件
|
||||
*
|
||||
* 放置在主界面头部,用于一键启用/关闭代理模式
|
||||
* 启用时自动接管 Live 配置,关闭时恢复原始配置
|
||||
*/
|
||||
|
||||
import { Radio, Loader2 } from "lucide-react";
|
||||
import { Switch } from "@/components/ui/switch";
|
||||
import { useProxyStatus } from "@/hooks/useProxyStatus";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
interface ProxyToggleProps {
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function ProxyToggle({ className }: ProxyToggleProps) {
|
||||
const {
|
||||
isRunning,
|
||||
isTakeoverActive,
|
||||
startWithTakeover,
|
||||
stopWithRestore,
|
||||
isPending,
|
||||
status,
|
||||
} = useProxyStatus();
|
||||
|
||||
const handleToggle = async (checked: boolean) => {
|
||||
if (checked) {
|
||||
await startWithTakeover();
|
||||
} else {
|
||||
await stopWithRestore();
|
||||
}
|
||||
};
|
||||
|
||||
const isActive = isRunning && isTakeoverActive;
|
||||
|
||||
const tooltipText = isActive
|
||||
? `代理模式运行中 - ${status?.address}:${status?.port}\n切换供应商为热切换`
|
||||
: "开启代理模式\n启用后自动接管 Live 配置";
|
||||
|
||||
return (
|
||||
<div
|
||||
className={cn(
|
||||
"flex items-center gap-2 px-3 py-1.5 rounded-lg transition-all cursor-default",
|
||||
isActive
|
||||
? "bg-emerald-500/10 border border-emerald-500/30"
|
||||
: "bg-muted/50 hover:bg-muted",
|
||||
className,
|
||||
)}
|
||||
title={tooltipText}
|
||||
>
|
||||
{isPending ? (
|
||||
<Loader2 className="h-4 w-4 animate-spin text-muted-foreground" />
|
||||
) : (
|
||||
<Radio
|
||||
className={cn(
|
||||
"h-4 w-4 transition-colors",
|
||||
isActive
|
||||
? "text-emerald-500 animate-pulse"
|
||||
: "text-muted-foreground",
|
||||
)}
|
||||
/>
|
||||
)}
|
||||
<span
|
||||
className={cn(
|
||||
"text-sm font-medium transition-colors select-none",
|
||||
isActive
|
||||
? "text-emerald-600 dark:text-emerald-400"
|
||||
: "text-muted-foreground",
|
||||
)}
|
||||
>
|
||||
Proxy
|
||||
</span>
|
||||
<Switch
|
||||
checked={isActive}
|
||||
onCheckedChange={handleToggle}
|
||||
disabled={isPending}
|
||||
className="ml-1"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -174,8 +174,8 @@ export function SettingsPage({
|
||||
|
||||
const {
|
||||
isRunning,
|
||||
start: startProxy,
|
||||
stop: stopProxy,
|
||||
startWithTakeover: startProxy,
|
||||
stopWithRestore: stopProxy,
|
||||
isPending: isProxyPending,
|
||||
} = useProxyStatus();
|
||||
const [failoverEnabled, setFailoverEnabled] = useState(true);
|
||||
|
||||
Reference in New Issue
Block a user