* feat: add tauri-plugin-mihomo * refactor: invock mihomo api by use tauri-plugin-mihomo * chore: todo * chore: update * chore: update * chore: update * chore: update * fix: incorrect delay status and update pretty config * chore: update * chore: remove cache * chore: update * chore: update * fix: app freezed when change group proxy * chore: update * chore: update * chore: add rustfmt.toml to tauri-plugin-mihomo * chore: happy clippy * refactor: connect mihomo websocket * chore: update * chore: update * fix: parse bigint to number * chore: update * Revert "fix: parse bigint to number" This reverts commit 74c006522e23aa52cf8979a8fb47d2b1ae0bb043. * chore: use number instead of bigint * chore: cleanup * fix: rule data not refresh when switch profile * chore: update * chore: cleanup * chore: update * fix: traffic graph data display * feat: add ipc connection pool * chore: update * chore: clippy * fix: incorrect delay status * fix: typo * fix: empty proxies tray menu * chore: clippy * chore: import tauri-plugin-mihomo by using git repo * chore: cleanup * fix: mihomo api * fix: incorrect delay status * chore: update tauri-plugin-mihomo dep chore: update
143 lines
4.0 KiB
TypeScript
143 lines
4.0 KiB
TypeScript
import { useLockFn } from "ahooks";
|
|
import { useCallback, useMemo } from "react";
|
|
import {
|
|
closeConnections,
|
|
getConnections,
|
|
selectNodeForGroup,
|
|
} from "tauri-plugin-mihomo-api";
|
|
|
|
import { useProfiles } from "@/hooks/use-profiles";
|
|
import { useVerge } from "@/hooks/use-verge";
|
|
import { syncTrayProxySelection } from "@/services/cmds";
|
|
|
|
// 缓存连接清理
|
|
const cleanupConnections = async (previousProxy: string) => {
|
|
try {
|
|
const { connections } = await getConnections();
|
|
const cleanupPromises = (connections ?? [])
|
|
.filter((conn) => conn.chains.includes(previousProxy))
|
|
.map((conn) => closeConnections(conn.id));
|
|
|
|
if (cleanupPromises.length > 0) {
|
|
await Promise.allSettled(cleanupPromises);
|
|
console.log(`[ProxySelection] 清理了 ${cleanupPromises.length} 个连接`);
|
|
}
|
|
} catch (error) {
|
|
console.warn("[ProxySelection] 连接清理失败:", error);
|
|
}
|
|
};
|
|
|
|
interface ProxySelectionOptions {
|
|
onSuccess?: () => void;
|
|
onError?: (error: any) => void;
|
|
enableConnectionCleanup?: boolean;
|
|
}
|
|
|
|
// 代理选择 Hook
|
|
export const useProxySelection = (options: ProxySelectionOptions = {}) => {
|
|
const { current, patchCurrent } = useProfiles();
|
|
const { verge } = useVerge();
|
|
|
|
const { onSuccess, onError, enableConnectionCleanup = true } = options;
|
|
|
|
// 缓存
|
|
const config = useMemo(
|
|
() => ({
|
|
autoCloseConnection: verge?.auto_close_connection ?? false,
|
|
enableConnectionCleanup,
|
|
}),
|
|
[verge?.auto_close_connection, enableConnectionCleanup],
|
|
);
|
|
|
|
// 切换节点
|
|
const changeProxy = useLockFn(
|
|
async (
|
|
groupName: string,
|
|
proxyName: string,
|
|
previousProxy?: string,
|
|
skipConfigSave: boolean = false,
|
|
) => {
|
|
console.log(`[ProxySelection] 代理切换: ${groupName} -> ${proxyName}`);
|
|
|
|
try {
|
|
if (current && !skipConfigSave) {
|
|
if (!current.selected) current.selected = [];
|
|
|
|
const index = current.selected.findIndex(
|
|
(item) => item.name === groupName,
|
|
);
|
|
|
|
if (index < 0) {
|
|
current.selected.push({ name: groupName, now: proxyName });
|
|
} else {
|
|
current.selected[index] = { name: groupName, now: proxyName };
|
|
}
|
|
await patchCurrent({ selected: current.selected });
|
|
}
|
|
|
|
await selectNodeForGroup(groupName, proxyName);
|
|
await syncTrayProxySelection();
|
|
console.log(
|
|
`[ProxySelection] 代理和状态同步完成: ${groupName} -> ${proxyName}`,
|
|
);
|
|
|
|
onSuccess?.();
|
|
|
|
if (
|
|
config.enableConnectionCleanup &&
|
|
config.autoCloseConnection &&
|
|
previousProxy
|
|
) {
|
|
setTimeout(() => cleanupConnections(previousProxy), 0);
|
|
}
|
|
} catch (error) {
|
|
console.error(
|
|
`[ProxySelection] 代理切换失败: ${groupName} -> ${proxyName}`,
|
|
error,
|
|
);
|
|
|
|
try {
|
|
await selectNodeForGroup(groupName, proxyName);
|
|
await syncTrayProxySelection();
|
|
onSuccess?.();
|
|
console.log(
|
|
`[ProxySelection] 代理切换回退成功: ${groupName} -> ${proxyName}`,
|
|
);
|
|
} catch (fallbackError) {
|
|
console.error(
|
|
`[ProxySelection] 代理切换回退也失败: ${groupName} -> ${proxyName}`,
|
|
fallbackError,
|
|
);
|
|
onError?.(fallbackError);
|
|
}
|
|
}
|
|
},
|
|
);
|
|
|
|
const handleSelectChange = useCallback(
|
|
(
|
|
groupName: string,
|
|
previousProxy?: string,
|
|
skipConfigSave: boolean = false,
|
|
) =>
|
|
(event: { target: { value: string } }) => {
|
|
const newProxy = event.target.value;
|
|
changeProxy(groupName, newProxy, previousProxy, skipConfigSave);
|
|
},
|
|
[changeProxy],
|
|
);
|
|
|
|
const handleProxyGroupChange = useCallback(
|
|
(group: { name: string; now?: string }, proxy: { name: string }) => {
|
|
changeProxy(group.name, proxy.name, group.now);
|
|
},
|
|
[changeProxy],
|
|
);
|
|
|
|
return {
|
|
changeProxy,
|
|
handleSelectChange,
|
|
handleProxyGroupChange,
|
|
};
|
|
};
|