From 7be790c6fb61b8058dc7e6159e6524787c6883e1 Mon Sep 17 00:00:00 2001 From: oomeow Date: Sun, 19 Oct 2025 16:34:26 +0800 Subject: [PATCH] chore: remove unused file and improve traffic monitor --- src/components/layout/traffic-graph.tsx | 11 +- src/hooks/use-log-data-new.ts | 162 -------------------- src/hooks/use-log-data.ts | 168 +++++++++++++++++++-- src/hooks/use-traffic-data.ts | 10 +- src/hooks/use-traffic-monitor.ts | 144 ++---------------- src/pages/_layout.tsx | 2 +- src/pages/logs.tsx | 6 +- src/services/global-log-service.ts | 191 ------------------------ src/services/ipc-log-service.ts | 67 --------- 9 files changed, 188 insertions(+), 573 deletions(-) delete mode 100644 src/hooks/use-log-data-new.ts delete mode 100644 src/services/global-log-service.ts delete mode 100644 src/services/ipc-log-service.ts diff --git a/src/components/layout/traffic-graph.tsx b/src/components/layout/traffic-graph.tsx index c8dc5731..6fdd2a30 100644 --- a/src/components/layout/traffic-graph.tsx +++ b/src/components/layout/traffic-graph.tsx @@ -1,5 +1,6 @@ import { useTheme } from "@mui/material"; import { useEffect, useImperativeHandle, useRef, type Ref } from "react"; +import { Traffic } from "tauri-plugin-mihomo-api"; const maxPoint = 30; @@ -14,10 +15,8 @@ const downLineWidth = 4; const defaultList = Array(maxPoint + 2).fill({ up: 0, down: 0 }); -type TrafficData = { up: number; down: number }; - export interface TrafficRef { - appendData: (data: TrafficData) => void; + appendData: (data: Traffic) => void; toggleStyle: () => void; } @@ -27,15 +26,15 @@ export interface TrafficRef { export function TrafficGraph({ ref }: { ref?: Ref }) { const countRef = useRef(0); const styleRef = useRef(true); - const listRef = useRef(defaultList); + const listRef = useRef(defaultList); const canvasRef = useRef(null!); - const cacheRef = useRef(null); + const cacheRef = useRef(null); const { palette } = useTheme(); useImperativeHandle(ref, () => ({ - appendData: (data: TrafficData) => { + appendData: (data: Traffic) => { cacheRef.current = data; }, toggleStyle: () => { diff --git a/src/hooks/use-log-data-new.ts b/src/hooks/use-log-data-new.ts deleted file mode 100644 index f7f90d7b..00000000 --- a/src/hooks/use-log-data-new.ts +++ /dev/null @@ -1,162 +0,0 @@ -import dayjs from "dayjs"; -import { useLocalStorage } from "foxact/use-local-storage"; -import { useEffect, useRef } from "react"; -import { mutate } from "swr"; -import useSWRSubscription from "swr/subscription"; -import { MihomoWebSocket } from "tauri-plugin-mihomo-api"; - -import { getClashLogs } from "@/services/cmds"; -import { useClashLog } from "@/services/states"; - -const MAX_LOG_NUM = 1000; - -export const useLogData = () => { - const [clashLog] = useClashLog(); - const enableLog = clashLog.enable; - const logLevel = clashLog.logLevel; - - const [date, setDate] = useLocalStorage("mihomo_logs_date", Date.now()); - const subscriptKey = enableLog ? `getClashLog-${date}` : null; - - const ws = useRef(null); - const wsFirstConnection = useRef(true); - const timeoutRef = useRef>(null); - - const response = useSWRSubscription( - subscriptKey, - (_key, { next }) => { - const reconnect = async () => { - await ws.current?.close(); - ws.current = null; - timeoutRef.current = setTimeout(async () => await connect(), 500); - }; - - const connect = () => - MihomoWebSocket.connect_logs(logLevel) - .then(async (ws_) => { - ws.current = ws_; - if (timeoutRef.current) clearTimeout(timeoutRef.current); - - const logs = await getClashLogs(); - let filterLogs: ILogItem[] = []; - switch (logLevel) { - case "debug": - filterLogs = logs.filter((i) => - ["debug", "info", "warning", "error"].includes(i.type), - ); - break; - case "info": - filterLogs = logs.filter((i) => - ["info", "warning", "error"].includes(i.type), - ); - break; - case "warning": - filterLogs = logs.filter((i) => - ["warning", "error"].includes(i.type), - ); - break; - case "error": - filterLogs = logs.filter((i) => i.type === "error"); - break; - case "silent": - filterLogs = []; - break; - default: - filterLogs = logs; - break; - } - next(null, filterLogs); - - const buffer: ILogItem[] = []; - let flushTimer: ReturnType | null = null; - const flush = () => { - if (buffer.length > 0) { - next(null, (l) => { - let newList = [...(l ?? []), ...buffer.splice(0)]; - if (newList.length > MAX_LOG_NUM) { - newList = newList.slice( - -Math.min(MAX_LOG_NUM, newList.length), - ); - } - return newList; - }); - } - flushTimer = null; - }; - ws_.addListener(async (msg) => { - if (msg.type === "Text") { - if (msg.data.startsWith("Websocket error")) { - next(msg.data); - await reconnect(); - } else { - const data = JSON.parse(msg.data) as ILogItem; - data.time = dayjs().format("MM-DD HH:mm:ss"); - buffer.push(data); - - // flush data - if (!flushTimer) { - flushTimer = setTimeout(flush, 50); - } - } - } - }); - }) - .catch((_) => { - if (!ws.current) { - timeoutRef.current = setTimeout(async () => await connect(), 500); - } - }); - - if ( - wsFirstConnection.current || - (ws.current && !wsFirstConnection.current) - ) { - wsFirstConnection.current = false; - if (ws.current) { - ws.current.close(); - ws.current = null; - } - connect(); - } - - return () => { - ws.current?.close(); - }; - }, - { - fallbackData: [], - keepPreviousData: true, - }, - ); - - useEffect(() => { - mutate(`$sub$${subscriptKey}`); - }, [date, subscriptKey]); - - const previousLogLevel = useRef(undefined); - - useEffect(() => { - if (!logLevel) { - previousLogLevel.current = logLevel ?? undefined; - return; - } - - if (previousLogLevel.current === logLevel) { - return; - } - - previousLogLevel.current = logLevel; - ws.current?.close(); - setDate(Date.now()); - }, [logLevel, setDate]); - - const refreshGetClashLog = (clear = false) => { - if (clear) { - mutate(`$sub$${subscriptKey}`, []); - } else { - setDate(Date.now()); - } - }; - - return { response, refreshGetClashLog }; -}; diff --git a/src/hooks/use-log-data.ts b/src/hooks/use-log-data.ts index f1ed1458..f7f90d7b 100644 --- a/src/hooks/use-log-data.ts +++ b/src/hooks/use-log-data.ts @@ -1,12 +1,162 @@ -import { - useGlobalLogData, - clearGlobalLogs, - // LogLevel, -} from "@/services/global-log-service"; +import dayjs from "dayjs"; +import { useLocalStorage } from "foxact/use-local-storage"; +import { useEffect, useRef } from "react"; +import { mutate } from "swr"; +import useSWRSubscription from "swr/subscription"; +import { MihomoWebSocket } from "tauri-plugin-mihomo-api"; -// 为了向后兼容,导出相同的类型 -// export type { LogLevel }; +import { getClashLogs } from "@/services/cmds"; +import { useClashLog } from "@/services/states"; -export const useLogData = useGlobalLogData; +const MAX_LOG_NUM = 1000; -export const clearLogs = clearGlobalLogs; +export const useLogData = () => { + const [clashLog] = useClashLog(); + const enableLog = clashLog.enable; + const logLevel = clashLog.logLevel; + + const [date, setDate] = useLocalStorage("mihomo_logs_date", Date.now()); + const subscriptKey = enableLog ? `getClashLog-${date}` : null; + + const ws = useRef(null); + const wsFirstConnection = useRef(true); + const timeoutRef = useRef>(null); + + const response = useSWRSubscription( + subscriptKey, + (_key, { next }) => { + const reconnect = async () => { + await ws.current?.close(); + ws.current = null; + timeoutRef.current = setTimeout(async () => await connect(), 500); + }; + + const connect = () => + MihomoWebSocket.connect_logs(logLevel) + .then(async (ws_) => { + ws.current = ws_; + if (timeoutRef.current) clearTimeout(timeoutRef.current); + + const logs = await getClashLogs(); + let filterLogs: ILogItem[] = []; + switch (logLevel) { + case "debug": + filterLogs = logs.filter((i) => + ["debug", "info", "warning", "error"].includes(i.type), + ); + break; + case "info": + filterLogs = logs.filter((i) => + ["info", "warning", "error"].includes(i.type), + ); + break; + case "warning": + filterLogs = logs.filter((i) => + ["warning", "error"].includes(i.type), + ); + break; + case "error": + filterLogs = logs.filter((i) => i.type === "error"); + break; + case "silent": + filterLogs = []; + break; + default: + filterLogs = logs; + break; + } + next(null, filterLogs); + + const buffer: ILogItem[] = []; + let flushTimer: ReturnType | null = null; + const flush = () => { + if (buffer.length > 0) { + next(null, (l) => { + let newList = [...(l ?? []), ...buffer.splice(0)]; + if (newList.length > MAX_LOG_NUM) { + newList = newList.slice( + -Math.min(MAX_LOG_NUM, newList.length), + ); + } + return newList; + }); + } + flushTimer = null; + }; + ws_.addListener(async (msg) => { + if (msg.type === "Text") { + if (msg.data.startsWith("Websocket error")) { + next(msg.data); + await reconnect(); + } else { + const data = JSON.parse(msg.data) as ILogItem; + data.time = dayjs().format("MM-DD HH:mm:ss"); + buffer.push(data); + + // flush data + if (!flushTimer) { + flushTimer = setTimeout(flush, 50); + } + } + } + }); + }) + .catch((_) => { + if (!ws.current) { + timeoutRef.current = setTimeout(async () => await connect(), 500); + } + }); + + if ( + wsFirstConnection.current || + (ws.current && !wsFirstConnection.current) + ) { + wsFirstConnection.current = false; + if (ws.current) { + ws.current.close(); + ws.current = null; + } + connect(); + } + + return () => { + ws.current?.close(); + }; + }, + { + fallbackData: [], + keepPreviousData: true, + }, + ); + + useEffect(() => { + mutate(`$sub$${subscriptKey}`); + }, [date, subscriptKey]); + + const previousLogLevel = useRef(undefined); + + useEffect(() => { + if (!logLevel) { + previousLogLevel.current = logLevel ?? undefined; + return; + } + + if (previousLogLevel.current === logLevel) { + return; + } + + previousLogLevel.current = logLevel; + ws.current?.close(); + setDate(Date.now()); + }, [logLevel, setDate]); + + const refreshGetClashLog = (clear = false) => { + if (clear) { + mutate(`$sub$${subscriptKey}`, []); + } else { + setDate(Date.now()); + } + }; + + return { response, refreshGetClashLog }; +}; diff --git a/src/hooks/use-traffic-data.ts b/src/hooks/use-traffic-data.ts index 56c1b44b..73cc40b8 100644 --- a/src/hooks/use-traffic-data.ts +++ b/src/hooks/use-traffic-data.ts @@ -2,15 +2,20 @@ import { useLocalStorage } from "foxact/use-local-storage"; import { useEffect, useRef } from "react"; import { mutate } from "swr"; import useSWRSubscription from "swr/subscription"; -import { MihomoWebSocket } from "tauri-plugin-mihomo-api"; +import { MihomoWebSocket, Traffic } from "tauri-plugin-mihomo-api"; import { TrafficRef } from "@/components/layout/traffic-graph"; +import { useTrafficMonitorEnhanced } from "./use-traffic-monitor"; + export const useTrafficData = () => { const [date, setDate] = useLocalStorage("mihomo_traffic_date", Date.now()); const subscriptKey = `getClashTraffic-${date}`; const trafficRef = useRef(null); + const { + graphData: { appendData }, + } = useTrafficMonitorEnhanced(); const ws = useRef(null); const wsFirstConnection = useRef(true); const timeoutRef = useRef>(null); @@ -36,8 +41,9 @@ export const useTrafficData = () => { next(msg.data, { up: 0, down: 0 }); await reconnect(); } else { - const data = JSON.parse(msg.data) as ITrafficItem; + const data = JSON.parse(msg.data) as Traffic; trafficRef.current?.appendData(data); + appendData(data); next(null, data); } } diff --git a/src/hooks/use-traffic-monitor.ts b/src/hooks/use-traffic-monitor.ts index 24c6bcb1..de9ae52a 100644 --- a/src/hooks/use-traffic-monitor.ts +++ b/src/hooks/use-traffic-monitor.ts @@ -1,9 +1,5 @@ import { useEffect, useRef, useCallback, useReducer } from "react"; - -// import { useClashInfo } from "@/hooks/use-clash"; -// import { useVisibility } from "@/hooks/use-visibility"; - -import { useTrafficData } from "./use-traffic-data"; +import { Traffic } from "tauri-plugin-mihomo-api"; // 增强的流量数据点接口 export interface ITrafficDataPoint { @@ -175,18 +171,11 @@ class TrafficDataSampler { // 全局单例 const refCounter = new ReferenceCounter(); let globalSampler: TrafficDataSampler | null = null; -// let lastValidData: ISystemMonitorOverview | null = null; /** * 增强的流量监控Hook - 支持数据压缩、采样和引用计数 */ export const useTrafficMonitorEnhanced = () => { - // const { clashInfo } = useClashInfo(); - // const pageVisible = useVisibility(); - const { - response: { data: traffic }, - } = useTrafficData(); - // 初始化采样器 if (!globalSampler) { globalSampler = new TrafficDataSampler({ @@ -232,8 +221,17 @@ export const useTrafficMonitorEnhanced = () => { refCounter.onCountChange(handleCountChange); }, []); - // const monitorData = useRef(null); - useEffect(() => { + // 获取指定时间范围的数据 + const getDataForTimeRange = useCallback( + (minutes: number): ITrafficDataPoint[] => { + if (!globalSampler) return []; + return globalSampler.getDataForTimeRange(minutes); + }, + [], + ); + + // 添加流量数据 + const appendData = useCallback((traffic: Traffic) => { if (globalSampler) { // 添加到采样器 const timestamp = Date.now(); @@ -250,77 +248,7 @@ export const useTrafficMonitorEnhanced = () => { }; globalSampler.addDataPoint(dataPoint); } - }, [traffic]); - - // const { data: monitorData, error } = useSWR( - // shouldFetch ? "getSystemMonitorOverviewSafe" : null, - // getSystemMonitorOverviewSafe, - // { - // refreshInterval: shouldFetch ? 1000 : 0, // 只有在需要时才刷新 - // keepPreviousData: true, - // onSuccess: (data) => { - // // console.log("[TrafficMonitorEnhanced] 获取到监控数据:", data); - - // if (data?.traffic?.raw && globalSampler) { - // // 保存最后有效数据 - // lastValidData = data; - - // // 添加到采样器 - // const timestamp = Date.now(); - // const dataPoint: ITrafficDataPoint = { - // up: data.traffic.raw.up_rate || 0, - // down: data.traffic.raw.down_rate || 0, - // timestamp, - // name: new Date(timestamp).toLocaleTimeString("en-US", { - // hour12: false, - // hour: "2-digit", - // minute: "2-digit", - // second: "2-digit", - // }), - // }; - - // globalSampler.addDataPoint(dataPoint); - // triggerUpdate(); - // } - // }, - // onError: (error) => { - // console.error( - // "[TrafficMonitorEnhanced] 网络错误,使用最后有效数据. 错误详情:", - // { - // message: error?.message || "未知错误", - // stack: error?.stack || "无堆栈信息", - // }, - // ); - // // 网络错误时不清空数据,继续使用最后有效值 - // // 但是添加一个错误标记的数据点(流量为0) - // if (globalSampler) { - // const timestamp = Date.now(); - // const errorPoint: ITrafficDataPoint = { - // up: 0, - // down: 0, - // timestamp, - // name: new Date(timestamp).toLocaleTimeString("en-US", { - // hour12: false, - // hour: "2-digit", - // minute: "2-digit", - // second: "2-digit", - // }), - // }; - // globalSampler.addDataPoint(errorPoint); - // triggerUpdate(); - // } - // }, - // }, - // ); - - // 获取指定时间范围的数据 - const getDataForTimeRange = useCallback( - (minutes: number): ITrafficDataPoint[] => { - if (!globalSampler) return []; - return globalSampler.getDataForTimeRange(minutes); - }, - [], - ); + }, []); // 清空数据 const clearData = useCallback(() => { @@ -342,64 +270,20 @@ export const useTrafficMonitorEnhanced = () => { ); }, []); - // 构建返回的监控数据,优先使用当前数据,fallback到最后有效数据 - // const currentData = monitorData.current || lastValidData; - // const trafficMonitorData = { - // traffic: currentData?.traffic || { - // raw: { up: 0, down: 0, up_rate: 0, down_rate: 0 }, - // formatted: { - // up_rate: "0B", - // down_rate: "0B", - // total_up: "0B", - // total_down: "0B", - // }, - // is_fresh: false, - // }, - // memory: currentData?.memory || { - // raw: { inuse: 0, oslimit: 0, usage_percent: 0 }, - // formatted: { inuse: "0B", oslimit: "0B", usage_percent: 0 }, - // is_fresh: false, - // }, - // }; - return { - // 监控数据 - // monitorData: trafficMonitorData, - // 图表数据管理 graphData: { dataPoints: globalSampler?.getDataForTimeRange(60) || [], // 默认获取1小时数据 getDataForTimeRange, + appendData, clearData, }, - - // 状态信息 - // isLoading: !currentData, - // isDataFresh: currentData?.traffic?.is_fresh || false, - // hasValidData: !!lastValidData, - // 性能统计 samplerStats: getSamplerStats(), referenceCount: refCounter.getCount(), }; }; -/** - * 轻量级流量数据Hook - */ -// export const useTrafficDataEnhanced = () => { -// const { monitorData, isLoading, isDataFresh, hasValidData } = -// useTrafficMonitorEnhanced(); - -// return { -// traffic: monitorData.traffic, -// memory: monitorData.memory, -// isLoading, -// isDataFresh, -// hasValidData, -// }; -// }; - /** * 图表数据Hook */ diff --git a/src/pages/_layout.tsx b/src/pages/_layout.tsx index 19e36fd3..1af59d0f 100644 --- a/src/pages/_layout.tsx +++ b/src/pages/_layout.tsx @@ -22,7 +22,7 @@ import { useCustomTheme } from "@/components/layout/use-custom-theme"; import { useConnectionData } from "@/hooks/use-connection-data"; import { useI18n } from "@/hooks/use-i18n"; import { useListen } from "@/hooks/use-listen"; -import { useLogData } from "@/hooks/use-log-data-new"; +import { useLogData } from "@/hooks/use-log-data"; import { useMemoryData } from "@/hooks/use-memory-data"; import { useTrafficData } from "@/hooks/use-traffic-data"; import { useVerge } from "@/hooks/use-verge"; diff --git a/src/pages/logs.tsx b/src/pages/logs.tsx index 9fc97ddd..4e49df3a 100644 --- a/src/pages/logs.tsx +++ b/src/pages/logs.tsx @@ -12,8 +12,7 @@ import { BaseSearchBox } from "@/components/base/base-search-box"; import { SearchState } from "@/components/base/base-search-box"; import { BaseStyledSelect } from "@/components/base/base-styled-select"; import LogItem from "@/components/log/log-item"; -import { useLogData } from "@/hooks/use-log-data-new"; -import { toggleLogEnabled } from "@/services/global-log-service"; +import { useLogData } from "@/hooks/use-log-data"; import { LogFilter, useClashLog } from "@/services/states"; const LogPage = () => { @@ -52,11 +51,9 @@ const LogPage = () => { const handleLogLevelChange = (newLevel: string) => { setClashLog((pre: any) => ({ ...pre, logFilter: newLevel })); - // changeLogLevel(newLevel); }; const handleToggleLog = async () => { - await toggleLogEnabled(); setClashLog((pre: any) => ({ ...pre, enable: !enableLog })); }; @@ -90,7 +87,6 @@ const LogPage = () => { variant="contained" onClick={() => { refreshGetClashLog(true); - // clearGlobalLogs(); }} > {t("Clear")} diff --git a/src/services/global-log-service.ts b/src/services/global-log-service.ts deleted file mode 100644 index 3c238153..00000000 --- a/src/services/global-log-service.ts +++ /dev/null @@ -1,191 +0,0 @@ -// 全局日志服务,使应用在任何页面都能收集日志 -import { create } from "zustand"; - -import { - fetchLogsViaIPC, - stopLogsStreaming, - clearLogs as clearLogsIPC, -} from "@/services/ipc-log-service"; - -// 最大日志数量 -const MAX_LOG_NUM = 1000; - -export type LogLevel = "debug" | "info" | "warning" | "error" | "all"; - -interface ILogItem { - time?: string; - type: string; - payload: string; - [key: string]: any; -} - -interface GlobalLogStore { - logs: ILogItem[]; - enabled: boolean; - isConnected: boolean; - currentLevel: LogLevel; - setEnabled: (enabled: boolean) => void; - setCurrentLevel: (level: LogLevel) => void; - clearLogs: () => void; - appendLog: (log: ILogItem) => void; - setLogs: (logs: ILogItem[]) => void; -} - -// 创建全局状态存储 -export const useGlobalLogStore = create((set) => ({ - logs: [], - enabled: false, - isConnected: false, - currentLevel: "info", - setEnabled: (enabled) => set({ enabled }), - setCurrentLevel: (currentLevel) => set({ currentLevel }), - clearLogs: () => set({ logs: [] }), - appendLog: (log: ILogItem) => - set((state) => { - const newLogs = - state.logs.length >= MAX_LOG_NUM - ? [...state.logs.slice(1), log] - : [...state.logs, log]; - return { logs: newLogs }; - }), - setLogs: (logs: ILogItem[]) => set({ logs }), -})); - -// IPC 日志获取函数 -export const fetchLogsViaIPCPeriodically = async () => { - try { - const logs = await fetchLogsViaIPC(); - useGlobalLogStore.getState().setLogs(logs); - console.log(`[GlobalLog-IPC] 成功获取 ${logs.length} 条日志`); - } catch (error) { - console.error("[GlobalLog-IPC] 获取日志失败:", error); - } -}; - -// 初始化全局日志服务 (仅IPC模式) -let ipcPollingInterval: ReturnType | null = null; -let isInitializing = false; // 添加初始化标志 - -export const initGlobalLogService = ( - enabled: boolean = false, - logLevel: LogLevel = "info", -) => { - // 防止重复初始化 - if (isInitializing) { - console.log("[GlobalLog-IPC] 正在初始化中,跳过重复调用"); - return; - } - - const { setEnabled, setCurrentLevel } = useGlobalLogStore.getState(); - - // 更新启用状态 - setEnabled(enabled); - setCurrentLevel(logLevel); - - // 如果不启用,则不初始化 - if (!enabled) { - clearIpcPolling(); - useGlobalLogStore.setState({ isConnected: false }); - return; - } - - isInitializing = true; - - // 使用IPC流式模式 - console.log("[GlobalLog-IPC] 启用IPC流式日志服务"); - - // 启动流式监控 - // startLogsStreaming(logLevel); - - // 立即获取一次日志 - fetchLogsViaIPCPeriodically(); - - // 设置定期轮询来同步流式缓存的数据 - clearIpcPolling(); - ipcPollingInterval = setInterval(() => { - fetchLogsViaIPCPeriodically(); - }, 1000); // 每1秒同步一次流式缓存 - - // 设置连接状态 - useGlobalLogStore.setState({ isConnected: true }); - - isInitializing = false; -}; - -// 清除IPC轮询 -const clearIpcPolling = () => { - if (ipcPollingInterval) { - clearInterval(ipcPollingInterval); - ipcPollingInterval = null; - console.log("[GlobalLog-IPC] 轮询已停止"); - } -}; - -// 停止日志监控 (仅IPC模式) -export const stopGlobalLogMonitoring = async () => { - clearIpcPolling(); - isInitializing = false; // 重置初始化标志 - - // 调用后端停止监控 - await stopLogsStreaming(); - - useGlobalLogStore.setState({ isConnected: false }); - console.log("[GlobalLog-IPC] 日志监控已停止"); -}; - -// 关闭全局日志连接 (仅IPC模式) - 保持向后兼容 -export const closeGlobalLogConnection = async () => { - await stopGlobalLogMonitoring(); -}; - -// 切换日志级别 (仅IPC模式) -export const changeLogLevel = (level: LogLevel) => { - const { enabled } = useGlobalLogStore.getState(); - useGlobalLogStore.setState({ currentLevel: level }); - - // 如果正在初始化,则跳过,避免重复启动 - if (isInitializing) { - console.log("[GlobalLog-IPC] 正在初始化中,跳过级别变更流启动"); - return; - } - - if (enabled) { - // IPC流式模式下重新启动监控 - // startLogsStreaming(level); - fetchLogsViaIPCPeriodically(); - } -}; - -// 切换启用状态 (仅IPC模式) -export const toggleLogEnabled = async () => { - const { enabled, currentLevel } = useGlobalLogStore.getState(); - const newEnabled = !enabled; - - useGlobalLogStore.setState({ enabled: newEnabled }); - - if (newEnabled) { - // IPC模式下直接启动 - initGlobalLogService(newEnabled, currentLevel); - } else { - await stopGlobalLogMonitoring(); - } -}; - -// 获取日志清理函数 - 只清理前端日志,不停止监控 -export const clearGlobalLogs = () => { - useGlobalLogStore.getState().clearLogs(); - // 同时清理后端缓存的日志,但不停止监控 - clearLogsIPC(); -}; - -// 自定义钩子,用于获取过滤后的日志数据 -export const useGlobalLogData = (logLevel: LogLevel = "info") => { - const logs = useGlobalLogStore((state) => state.logs); - - // 根据当前选择的日志等级过滤日志 - if (logLevel === "info") { - return logs; - } else { - return logs.filter((log) => log.type.toLowerCase() === logLevel); - } -}; diff --git a/src/services/ipc-log-service.ts b/src/services/ipc-log-service.ts deleted file mode 100644 index 995ea01c..00000000 --- a/src/services/ipc-log-service.ts +++ /dev/null @@ -1,67 +0,0 @@ -// IPC-based log service using Tauri commands with streaming support - -import { clearLogs as clearLogsCmd } from "@/services/cmds"; - -type LogLevel = "debug" | "info" | "warning" | "error" | "all"; - -interface ILogItem { - time?: string; - type: string; - payload: string; - [key: string]: any; -} - -// Start logs monitoring with specified level -export const startLogsStreaming = async (logLevel: LogLevel = "info") => { - try { - // await startLogsMonitoring(logLevel === "all" ? undefined : logLevel); - console.log( - `[IPC-LogService] Started logs monitoring with level: ${logLevel}`, - ); - } catch (error) { - console.error("[IPC-LogService] Failed to start logs monitoring:", error); - } -}; - -// Stop logs monitoring -export const stopLogsStreaming = async () => { - try { - // await stopLogsMonitoring(); - console.log("[IPC-LogService] Stopped logs monitoring"); - } catch (error) { - console.error("[IPC-LogService] Failed to stop logs monitoring:", error); - } -}; - -// Fetch logs using IPC command (now from streaming cache) -export const fetchLogsViaIPC = async (): Promise => { - try { - // Server-side filtering handles the level via /logs?level={level} - // We just fetch all cached logs regardless of the logLevel parameter - // const response = await getClashLogs(); - - // // The response should be in the format expected by the frontend - // // Transform the logs to match the expected format - // if (Array.isArray(response)) { - // return response.map((log: any) => ({ - // ...log, - // time: log.time || dayjs().format("HH:mm:ss"), - // })); - // } - - return []; - } catch (error) { - console.error("[IPC-LogService] Failed to fetch logs:", error); - return []; - } -}; - -// Clear logs -export const clearLogs = async () => { - try { - await clearLogsCmd(); - console.log("[IPC-LogService] Logs cleared"); - } catch (error) { - console.error("[IPC-LogService] Failed to clear logs:", error); - } -};