refactor: invock mihomo api by use tauri-plugin-mihomo (#4926)

* 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
This commit is contained in:
oomeow
2025-10-08 12:32:40 +08:00
committed by GitHub
parent 72aa56007c
commit 7fc238c27b
85 changed files with 1780 additions and 3344 deletions

View File

@@ -53,7 +53,7 @@ export const ClashInfoCard = () => {
{t("Mixed Port")}
</Typography>
<Typography variant="body2" fontWeight="medium">
{clashConfig["mixed-port"] || "-"}
{clashConfig.mixedPort || "-"}
</Typography>
</Stack>
<Divider />

View File

@@ -7,10 +7,11 @@ import { Box, Paper, Stack, Typography } from "@mui/material";
import { useLockFn } from "ahooks";
import { useMemo } from "react";
import { useTranslation } from "react-i18next";
import { closeAllConnections } from "tauri-plugin-mihomo-api";
import { useVerge } from "@/hooks/use-verge";
import { useAppData } from "@/providers/app-data-context";
import { closeAllConnections, patchClashMode } from "@/services/cmds";
import { patchClashMode } from "@/services/cmds";
export const ClashModeCard = () => {
const { t } = useTranslation();

View File

@@ -36,8 +36,8 @@ import { EnhancedCard } from "@/components/home/enhanced-card";
import { useProxySelection } from "@/hooks/use-proxy-selection";
import { useVerge } from "@/hooks/use-verge";
import { useAppData } from "@/providers/app-data-context";
import { getGroupProxyDelays, providerHealthCheck } from "@/services/cmds";
import delayManager from "@/services/delay";
import { delayGroup, healthcheckProxyProvider } from "tauri-plugin-mihomo-api";
// 本地存储的键名
const STORAGE_KEY_GROUP = "clash-verge-selected-proxy-group";
@@ -466,7 +466,7 @@ export const CurrentProxyCard = () => {
if (providers.size > 0) {
console.log(`[CurrentProxyCard] 开始测试提供者节点`);
await Promise.allSettled(
[...providers].map((p) => providerHealthCheck(p)),
[...providers].map((p) => healthcheckProxyProvider(p)),
);
}
@@ -478,7 +478,7 @@ export const CurrentProxyCard = () => {
try {
await Promise.race([
delayManager.checkListDelay(proxyNames, groupName, timeout),
getGroupProxyDelays(groupName, url, timeout),
delayGroup(groupName, url, timeout),
]);
console.log(`[CurrentProxyCard] 延迟测试完成,组: ${groupName}`);
} catch (error) {

View File

@@ -92,7 +92,7 @@ export const EnhancedCanvasTrafficGraph = memo(
const { t } = useTranslation();
// 使用增强版全局流量数据管理
const { dataPoints, getDataForTimeRange, isDataFresh, samplerStats } =
const { dataPoints, getDataForTimeRange, samplerStats } =
useTrafficGraphDataEnhanced();
// 基础状态
@@ -865,6 +865,7 @@ export const EnhancedCanvasTrafficGraph = memo(
}}
onMouseMove={handleMouseMove}
onMouseLeave={handleMouseLeave}
onClick={toggleStyle}
/>
{/* 控制层覆盖 */}
@@ -962,8 +963,8 @@ export const EnhancedCanvasTrafficGraph = memo(
lineHeight: 1.2,
}}
>
Points: {displayData.length} | Fresh: {isDataFresh ? "✓" : "✗"} |
Compressed: {samplerStats.compressedBufferSize}
Points: {displayData.length} | Compressed:{" "}
{samplerStats.compressedBufferSize}
</Box>
{/* 悬浮提示框 */}
@@ -988,6 +989,7 @@ export const EnhancedCanvasTrafficGraph = memo(
boxShadow: "0 4px 12px rgba(0,0,0,0.15)",
backdropFilter: "none",
opacity: 1,
whiteSpace: "nowrap",
}}
>
<Box color="text.secondary" mb={0.2}>

View File

@@ -7,7 +7,6 @@ import {
MemoryRounded,
} from "@mui/icons-material";
import {
Box,
Grid,
PaletteColor,
Paper,
@@ -15,16 +14,16 @@ import {
alpha,
useTheme,
} from "@mui/material";
import { ReactNode, memo, useCallback, useMemo, useRef } from "react";
import { useRef, memo, useMemo } from "react";
import { ReactNode } from "react";
import { useTranslation } from "react-i18next";
import useSWR from "swr";
import { TrafficErrorBoundary } from "@/components/common/traffic-error-boundary";
import { useTrafficDataEnhanced } from "@/hooks/use-traffic-monitor";
import { useConnectionData } from "@/hooks/use-connection-data";
import { useMemoryData } from "@/hooks/use-memory-data";
import { useTrafficData } from "@/hooks/use-traffic-data";
import { useVerge } from "@/hooks/use-verge";
import { useVisibility } from "@/hooks/use-visibility";
import { useAppData } from "@/providers/app-data-context";
import { gc, isDebugEnabled } from "@/services/cmds";
import parseTraffic from "@/utils/parse-traffic";
import {
@@ -148,51 +147,33 @@ export const EnhancedTrafficStats = () => {
const trafficRef = useRef<EnhancedCanvasTrafficGraphRef>(null);
const pageVisible = useVisibility();
// 使用AppDataProvider
const { connections } = useAppData();
const {
response: { data: traffic },
} = useTrafficData();
// 使用增强版的统一流量数据Hook
const { traffic, memory, isLoading, isDataFresh, hasValidData } =
useTrafficDataEnhanced();
const {
response: { data: memory },
} = useMemoryData();
const {
response: { data: connections },
} = useConnectionData();
// 是否显示流量图表
const trafficGraph = verge?.traffic_graph ?? true;
// 检查是否支持调试
// TODO: merge this hook with layout-traffic.tsx
const { data: isDebug } = useSWR(
`clash-verge-rev-internal://isDebugEnabled`,
() => isDebugEnabled(),
{
// default value before is fetched
fallbackData: false,
},
);
// Canvas组件现在直接从全局Hook获取数据无需手动添加数据点
// 执行垃圾回收
const handleGarbageCollection = useCallback(async () => {
if (isDebug) {
try {
await gc();
console.log("[Debug] 垃圾回收已执行");
} catch (err) {
console.error("[Debug] 垃圾回收失败:", err);
}
}
}, [isDebug]);
// 使用useMemo计算解析后的流量数据
const parsedData = useMemo(() => {
const [up, upUnit] = parseTraffic(traffic?.raw?.up_rate || 0);
const [down, downUnit] = parseTraffic(traffic?.raw?.down_rate || 0);
const [inuse, inuseUnit] = parseTraffic(memory?.raw?.inuse || 0);
const [up, upUnit] = parseTraffic(traffic?.up || 0);
const [down, downUnit] = parseTraffic(traffic?.down || 0);
const [inuse, inuseUnit] = parseTraffic(memory?.inuse || 0);
const [uploadTotal, uploadTotalUnit] = parseTraffic(
connections.uploadTotal,
connections?.uploadTotal,
);
const [downloadTotal, downloadTotalUnit] = parseTraffic(
connections.downloadTotal,
connections?.downloadTotal,
);
return {
@@ -206,7 +187,7 @@ export const EnhancedTrafficStats = () => {
uploadTotalUnit,
downloadTotal,
downloadTotalUnit,
connectionsCount: connections.count,
connectionsCount: connections?.connections.length,
};
}, [traffic, memory, connections]);
@@ -228,33 +209,10 @@ export const EnhancedTrafficStats = () => {
>
<div style={{ height: "100%", position: "relative" }}>
<EnhancedCanvasTrafficGraph ref={trafficRef} />
{isDebug && (
<div
style={{
position: "absolute",
top: "2px",
left: "2px",
zIndex: 10,
backgroundColor: "rgba(0,0,0,0.5)",
color: "white",
fontSize: "8px",
padding: "2px 4px",
borderRadius: "4px",
}}
>
DEBUG: {trafficRef.current ? "图表已初始化" : "图表未初始化"}
<br />
: {isDataFresh ? "active" : "inactive"}
<br />
: {traffic?.is_fresh ? "Fresh" : "Stale"}
<br />
{new Date().toISOString().slice(11, 19)}
</div>
)}
</div>
</Paper>
);
}, [trafficGraph, pageVisible, theme.palette.divider, isDebug]);
}, [trafficGraph, pageVisible, theme.palette.divider]);
// 使用useMemo计算统计卡片配置
const statCards = useMemo(
@@ -300,10 +258,10 @@ export const EnhancedTrafficStats = () => {
value: parsedData.inuse,
unit: parsedData.inuseUnit,
color: "error" as const,
onClick: isDebug ? handleGarbageCollection : undefined,
onClick: undefined,
},
],
[t, parsedData, isDebug, handleGarbageCollection],
[t, parsedData],
);
return (
@@ -320,28 +278,11 @@ export const EnhancedTrafficStats = () => {
</Grid>
)}
{/* 统计卡片区域 */}
{statCards.map((card, index) => (
<Grid key={index} size={4}>
<CompactStatCard {...card} />
{statCards.map((card, _index) => (
<Grid key={card.title} size={4}>
<CompactStatCard {...(card as StatCardProps)} />
</Grid>
))}
{/* 数据状态指示器(调试用)*/}
{isDebug && (
<Grid size={12}>
<Box
sx={{
p: 1,
bgcolor: "action.hover",
borderRadius: 1,
fontSize: "0.75rem",
}}
>
: {isDataFresh ? "新鲜" : "过期"} | :{" "}
{hasValidData ? "是" : "否"} | : {isLoading ? "是" : "否"}
</Box>
</Grid>
)}
</Grid>
</TrafficErrorBoundary>
);