mirror of
https://github.com/clash-verge-rev/clash-verge-rev.git
synced 2026-10-14 21:20:48 +08:00
refactor(frontend): drop dead code in traffic and ws pipelines
Removes zero-consumer surface verified by repo-wide grep: the reference-count render machinery, the never-called clearData chain, unread snapshot fields (rangeMinutes, reason), dead refresh callbacks on the connection hooks, the write-only wsRef sync, and the worker's unreachable DEFAULT_CONFIG placeholder (now definite assignment under the init-first client contract). No behavior change; the compressed sampler path, samplerStats diagnostics, and lastTimestamp perf contract stay. Net -120 lines across six files.
This commit is contained in:
@@ -39,17 +39,6 @@ interface StatCardProps {
|
||||
onClick?: () => void
|
||||
}
|
||||
|
||||
// 全局变量类型定义
|
||||
declare global {
|
||||
interface Window {
|
||||
animationFrameId?: number
|
||||
lastTrafficData?: {
|
||||
up: number
|
||||
down: number
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 统计卡片组件 - 使用memo优化
|
||||
const CompactStatCard = memo(
|
||||
({ icon, title, value, unit, color, onClick }: StatCardProps) => {
|
||||
|
||||
@@ -258,7 +258,6 @@ const clearPendingMessage = () => {
|
||||
interface SocketSupervisor {
|
||||
start: () => void
|
||||
stopIfIdle: () => void
|
||||
reconnect: () => Promise<void>
|
||||
}
|
||||
|
||||
const createSocketSupervisor = (options: {
|
||||
@@ -349,7 +348,6 @@ const createSocketSupervisor = (options: {
|
||||
clearReconnectTimer()
|
||||
void closeSocket()
|
||||
},
|
||||
reconnect,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -405,15 +403,6 @@ const subscribeConnectionSummary = (listener: ConnectionListener) => {
|
||||
}
|
||||
}
|
||||
|
||||
const refreshConnectionData = () => {
|
||||
clearPendingMessage()
|
||||
void connectionSupervisor.reconnect()
|
||||
}
|
||||
|
||||
const refreshConnectionSummary = () => {
|
||||
void summarySupervisor.reconnect()
|
||||
}
|
||||
|
||||
const clearClosedConnectionData = () => {
|
||||
if (connectionData.closedConnections.length === 0) return
|
||||
connectionData = {
|
||||
@@ -436,16 +425,12 @@ export const useConnectionData = (options?: { enabled?: boolean }) => {
|
||||
getConnectionSnapshot,
|
||||
)
|
||||
const response = useMemo(() => ({ data }), [data])
|
||||
const refreshGetClashConnection = useCallback(() => {
|
||||
refreshConnectionData()
|
||||
}, [])
|
||||
const clearClosedConnections = useCallback(() => {
|
||||
clearClosedConnectionData()
|
||||
}, [])
|
||||
|
||||
return {
|
||||
response,
|
||||
refreshGetClashConnection,
|
||||
clearClosedConnections,
|
||||
}
|
||||
}
|
||||
@@ -463,12 +448,8 @@ export const useConnectionSummaryData = (options?: { enabled?: boolean }) => {
|
||||
getConnectionSummarySnapshot,
|
||||
)
|
||||
const response = useMemo(() => ({ data }), [data])
|
||||
const refreshGetClashConnectionSummary = useCallback(() => {
|
||||
refreshConnectionSummary()
|
||||
}, [])
|
||||
|
||||
return {
|
||||
response,
|
||||
refreshGetClashConnectionSummary,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { useLocalStorage } from 'foxact/use-local-storage'
|
||||
import { type MutableRefObject, useCallback, useEffect, useRef } from 'react'
|
||||
import { useCallback, useEffect, useRef } from 'react'
|
||||
import { type Message, type MihomoWebSocket } from 'tauri-plugin-mihomo-api'
|
||||
|
||||
import {
|
||||
@@ -22,7 +22,6 @@ interface SharedSubscriptionEntry {
|
||||
ws: MihomoWebSocket | null
|
||||
reconnectTimer: ReturnType<typeof setTimeout> | null
|
||||
connecting: boolean
|
||||
refHolders: Set<MutableRefObject<MihomoWebSocket | null>>
|
||||
owners: Set<SharedSubscriptionOwner>
|
||||
activeOwner: SharedSubscriptionOwner | null
|
||||
closed: boolean
|
||||
@@ -42,12 +41,6 @@ const writeSubscriptionSnapshot = <T>(key: string, data: T) => {
|
||||
void setCacheData<T>([key], data)
|
||||
}
|
||||
|
||||
const syncSharedWsRefs = (entry: SharedSubscriptionEntry) => {
|
||||
entry.refHolders.forEach((ref) => {
|
||||
ref.current = entry.ws
|
||||
})
|
||||
}
|
||||
|
||||
const pickActiveOwner = (entry: SharedSubscriptionEntry) => {
|
||||
if (entry.activeOwner?.isMounted()) return entry.activeOwner
|
||||
|
||||
@@ -67,7 +60,6 @@ const closeSharedSocket = async (entry: SharedSubscriptionEntry) => {
|
||||
if (!ws) return
|
||||
|
||||
entry.ws = null
|
||||
syncSharedWsRefs(entry)
|
||||
await ws.close()
|
||||
}
|
||||
|
||||
@@ -79,7 +71,6 @@ const createSharedSubscriptionEntry = (
|
||||
ws: null,
|
||||
reconnectTimer: null,
|
||||
connecting: false,
|
||||
refHolders: new Set(),
|
||||
owners: new Set(),
|
||||
activeOwner: null,
|
||||
closed: false,
|
||||
@@ -121,7 +112,6 @@ const createSharedSubscriptionEntry = (
|
||||
})
|
||||
|
||||
entry.ws = ws
|
||||
syncSharedWsRefs(entry)
|
||||
clearReconnectTimer()
|
||||
} catch (ignoreError) {
|
||||
if (!entry.closed && !entry.ws) {
|
||||
@@ -207,8 +197,6 @@ export const useMihomoWsSubscription = <T>(
|
||||
const responseCacheKey =
|
||||
subscriptionCacheKey ?? lastSubscriptionCacheKeyRef.current
|
||||
|
||||
const wsRef = useRef<MihomoWebSocket | null>(null)
|
||||
|
||||
const resolveNextData = useCallback(
|
||||
(
|
||||
data: T | ((current?: T) => T | undefined) | undefined,
|
||||
@@ -246,8 +234,6 @@ export const useMihomoWsSubscription = <T>(
|
||||
}
|
||||
|
||||
entry.refs += 1
|
||||
entry.refHolders.add(wsRef)
|
||||
wsRef.current = entry.ws
|
||||
|
||||
let throttleCleanup: (() => void) | undefined
|
||||
let wrappedNext: NextFn<T>
|
||||
@@ -331,8 +317,6 @@ export const useMihomoWsSubscription = <T>(
|
||||
|
||||
return () => {
|
||||
isMounted = false
|
||||
entry.refHolders.delete(wsRef)
|
||||
wsRef.current = null
|
||||
entry.owners.delete(owner)
|
||||
owner.cleanup?.()
|
||||
|
||||
@@ -376,5 +360,5 @@ export const useMihomoWsSubscription = <T>(
|
||||
[responseCacheKey],
|
||||
)
|
||||
|
||||
return { response, refresh, setData, wsRef }
|
||||
return { response, refresh, setData }
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useEffect, useReducer, useRef, useState } from 'react'
|
||||
import { useCallback, useEffect, useRef, useState } from 'react'
|
||||
import { Traffic } from 'tauri-plugin-mihomo-api'
|
||||
|
||||
import { useVisibility } from '@/hooks/use-visibility'
|
||||
@@ -8,33 +8,17 @@ import { TrafficDataSampler, isSameTrafficData } from '@/utils/traffic-sampler'
|
||||
// 引用计数管理器
|
||||
class ReferenceCounter {
|
||||
private count = 0
|
||||
private callbacks = new Set<() => void>()
|
||||
|
||||
private notify() {
|
||||
this.callbacks.forEach((cb) => {
|
||||
cb()
|
||||
})
|
||||
}
|
||||
|
||||
increment(): () => void {
|
||||
this.count++
|
||||
debugLog(`[ReferenceCounter] 引用计数增加: ${this.count}`)
|
||||
|
||||
this.notify()
|
||||
|
||||
return () => {
|
||||
this.count--
|
||||
debugLog(`[ReferenceCounter] 引用计数减少: ${this.count}`)
|
||||
|
||||
this.notify()
|
||||
}
|
||||
}
|
||||
|
||||
onCountChange(callback: () => void) {
|
||||
this.callbacks.add(callback)
|
||||
return () => this.callbacks.delete(callback)
|
||||
}
|
||||
|
||||
getCount(): number {
|
||||
return this.count
|
||||
}
|
||||
@@ -96,10 +80,10 @@ class InlineTrafficMonitor {
|
||||
if (this.throttleTimer !== null) return
|
||||
const slice = this.sampler.getDataForTimeRange(this.currentRange)
|
||||
if (!isSameTrafficData(this.lastBroadcast, slice)) {
|
||||
this.emitSnapshot('interval')
|
||||
this.emitSnapshot()
|
||||
}
|
||||
}, 1000)
|
||||
this.emitSnapshot('init')
|
||||
this.emitSnapshot()
|
||||
break
|
||||
}
|
||||
case 'append': {
|
||||
@@ -112,24 +96,18 @@ class InlineTrafficMonitor {
|
||||
|
||||
this.lastTimestamp = timestamp
|
||||
this.sampler.addDataPoint(dataPoint)
|
||||
this.scheduleSnapshot('append-throttle')
|
||||
break
|
||||
}
|
||||
case 'clear': {
|
||||
this.sampler.clear()
|
||||
this.lastTimestamp = undefined
|
||||
this.emitSnapshot('clear')
|
||||
this.scheduleSnapshot()
|
||||
break
|
||||
}
|
||||
case 'setRange': {
|
||||
if (this.currentRange !== message.minutes) {
|
||||
this.currentRange = message.minutes
|
||||
this.emitSnapshot('range-change')
|
||||
this.emitSnapshot()
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'requestSnapshot': {
|
||||
this.emitSnapshot('request')
|
||||
this.emitSnapshot()
|
||||
break
|
||||
}
|
||||
default:
|
||||
@@ -137,25 +115,23 @@ class InlineTrafficMonitor {
|
||||
}
|
||||
}
|
||||
|
||||
private emitSnapshot(reason: ITrafficWorkerSnapshotMessage['reason']) {
|
||||
private emitSnapshot() {
|
||||
const dataPoints = this.sampler.getDataForTimeRange(this.currentRange)
|
||||
|
||||
this.emit({
|
||||
type: 'snapshot',
|
||||
dataPoints,
|
||||
samplerStats: this.sampler.getStats(),
|
||||
rangeMinutes: this.currentRange,
|
||||
lastTimestamp: this.lastTimestamp,
|
||||
reason,
|
||||
})
|
||||
this.lastBroadcast = dataPoints
|
||||
}
|
||||
|
||||
private scheduleSnapshot(reason: ITrafficWorkerSnapshotMessage['reason']) {
|
||||
private scheduleSnapshot() {
|
||||
if (this.throttleTimer !== null) return
|
||||
this.throttleTimer = setTimeout(() => {
|
||||
this.throttleTimer = null
|
||||
this.emitSnapshot(reason)
|
||||
this.emitSnapshot()
|
||||
}, this.config.snapshotIntervalMs)
|
||||
}
|
||||
}
|
||||
@@ -331,11 +307,6 @@ class TrafficWorkerClient {
|
||||
})
|
||||
}
|
||||
|
||||
clearData() {
|
||||
this.ensureStarted()
|
||||
this.post({ type: 'clear' })
|
||||
}
|
||||
|
||||
setRange(minutes: number) {
|
||||
this.currentRange = minutes
|
||||
this.post({ type: 'setRange', minutes })
|
||||
@@ -382,7 +353,6 @@ export const useTrafficMonitorEnhanced = (options?: {
|
||||
dataPoints: [],
|
||||
samplerStats: EMPTY_STATS,
|
||||
})
|
||||
const [, forceRefCountRender] = useReducer((value) => value + 1, 0)
|
||||
|
||||
const clientRef = useRef<TrafficWorkerClient | null>(getWorkerClient())
|
||||
const currentRangeRef = useRef<number>(WORKER_CONFIG.defaultRangeMinutes)
|
||||
@@ -396,9 +366,6 @@ export const useTrafficMonitorEnhanced = (options?: {
|
||||
const client = getWorkerClient()
|
||||
clientRef.current = client
|
||||
|
||||
const stopWatchRefCount = refCounter.onCountChange(() =>
|
||||
forceRefCountRender(),
|
||||
)
|
||||
const cleanup = refCounter.increment()
|
||||
client.start(currentRangeRef.current)
|
||||
|
||||
@@ -415,7 +382,6 @@ export const useTrafficMonitorEnhanced = (options?: {
|
||||
|
||||
return () => {
|
||||
unsubscribe?.()
|
||||
stopWatchRefCount()
|
||||
cleanup()
|
||||
if (refCounter.getCount() === 0) {
|
||||
client.stop()
|
||||
@@ -449,21 +415,13 @@ export const useTrafficMonitorEnhanced = (options?: {
|
||||
[enabled],
|
||||
)
|
||||
|
||||
// 清空数据
|
||||
const clearData = useCallback(() => {
|
||||
if (!enabled) return
|
||||
clientRef.current?.clearData()
|
||||
}, [enabled])
|
||||
|
||||
return {
|
||||
graphData: {
|
||||
dataPoints: enabled ? latestSnapshot.dataPoints : EMPTY_DATA,
|
||||
requestRange,
|
||||
appendData,
|
||||
clearData,
|
||||
},
|
||||
samplerStats: latestSnapshot.samplerStats,
|
||||
referenceCount: refCounter.getCount(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,12 +429,10 @@ export const useTrafficMonitorEnhanced = (options?: {
|
||||
* 图表数据Hook
|
||||
*/
|
||||
export const useTrafficGraphDataEnhanced = () => {
|
||||
const { graphData, samplerStats, referenceCount } =
|
||||
useTrafficMonitorEnhanced()
|
||||
const { graphData, samplerStats } = useTrafficMonitorEnhanced()
|
||||
|
||||
return {
|
||||
...graphData,
|
||||
samplerStats,
|
||||
referenceCount,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,16 +1,5 @@
|
||||
import { TrafficDataSampler, isSameTrafficData } from '../utils/traffic-sampler'
|
||||
|
||||
const DEFAULT_CONFIG: ISamplingConfig & {
|
||||
snapshotIntervalMs: number
|
||||
defaultRangeMinutes: number
|
||||
} = {
|
||||
rawDataMinutes: 10,
|
||||
compressedDataMinutes: 60,
|
||||
compressionRatio: 5,
|
||||
snapshotIntervalMs: 250,
|
||||
defaultRangeMinutes: 10,
|
||||
}
|
||||
|
||||
interface WorkerScope {
|
||||
postMessage: (message: unknown) => void
|
||||
onmessage: ((event: MessageEvent<TrafficWorkerRequestMessage>) => void) | null
|
||||
@@ -22,14 +11,16 @@ interface WorkerScope {
|
||||
|
||||
const ctx: WorkerScope = self as unknown as WorkerScope
|
||||
|
||||
let config = { ...DEFAULT_CONFIG }
|
||||
let sampler = new TrafficDataSampler(config)
|
||||
let currentRangeMinutes = config.defaultRangeMinutes
|
||||
// 'init' is the first message posted by the client, so these are always
|
||||
// assigned before first use.
|
||||
let config!: ITrafficWorkerInitMessage['config']
|
||||
let sampler!: TrafficDataSampler
|
||||
let currentRangeMinutes!: number
|
||||
let throttleTimer: ReturnType<typeof setTimeout> | null = null
|
||||
let lastTimestamp: number | undefined
|
||||
let lastBroadcast: ITrafficDataPoint[] = []
|
||||
|
||||
const broadcastSnapshot = (reason: ITrafficWorkerSnapshotMessage['reason']) => {
|
||||
const broadcastSnapshot = () => {
|
||||
const dataPoints = sampler.getDataForTimeRange(currentRangeMinutes)
|
||||
const samplerStats = sampler.getStats()
|
||||
|
||||
@@ -37,20 +28,18 @@ const broadcastSnapshot = (reason: ITrafficWorkerSnapshotMessage['reason']) => {
|
||||
type: 'snapshot',
|
||||
dataPoints,
|
||||
samplerStats,
|
||||
rangeMinutes: currentRangeMinutes,
|
||||
lastTimestamp,
|
||||
reason,
|
||||
}
|
||||
|
||||
ctx.postMessage(message)
|
||||
lastBroadcast = dataPoints
|
||||
}
|
||||
|
||||
const scheduleSnapshot = (reason: ITrafficWorkerSnapshotMessage['reason']) => {
|
||||
const scheduleSnapshot = () => {
|
||||
if (throttleTimer !== null) return
|
||||
throttleTimer = ctx.setTimeout(() => {
|
||||
throttleTimer = null
|
||||
broadcastSnapshot(reason)
|
||||
broadcastSnapshot()
|
||||
}, config.snapshotIntervalMs)
|
||||
}
|
||||
|
||||
@@ -68,10 +57,10 @@ ctx.onmessage = (event: MessageEvent<TrafficWorkerRequestMessage>) => {
|
||||
if (throttleTimer !== null) return
|
||||
const slice = sampler.getDataForTimeRange(currentRangeMinutes)
|
||||
if (!isSameTrafficData(lastBroadcast, slice)) {
|
||||
broadcastSnapshot('interval')
|
||||
broadcastSnapshot()
|
||||
}
|
||||
}, 1000)
|
||||
broadcastSnapshot('init')
|
||||
broadcastSnapshot()
|
||||
break
|
||||
}
|
||||
case 'append': {
|
||||
@@ -84,24 +73,18 @@ ctx.onmessage = (event: MessageEvent<TrafficWorkerRequestMessage>) => {
|
||||
|
||||
lastTimestamp = timestamp
|
||||
sampler.addDataPoint(dataPoint)
|
||||
scheduleSnapshot('append-throttle')
|
||||
break
|
||||
}
|
||||
case 'clear': {
|
||||
sampler.clear()
|
||||
lastTimestamp = undefined
|
||||
broadcastSnapshot('clear')
|
||||
scheduleSnapshot()
|
||||
break
|
||||
}
|
||||
case 'setRange': {
|
||||
if (currentRangeMinutes !== message.minutes) {
|
||||
currentRangeMinutes = message.minutes
|
||||
broadcastSnapshot('range-change')
|
||||
broadcastSnapshot()
|
||||
}
|
||||
break
|
||||
}
|
||||
case 'requestSnapshot': {
|
||||
broadcastSnapshot('request')
|
||||
broadcastSnapshot()
|
||||
break
|
||||
}
|
||||
default:
|
||||
|
||||
Vendored
-13
@@ -1005,10 +1005,6 @@ interface ITrafficWorkerAppendMessage {
|
||||
}
|
||||
}
|
||||
|
||||
interface ITrafficWorkerClearMessage {
|
||||
type: 'clear'
|
||||
}
|
||||
|
||||
interface ITrafficWorkerSetRangeMessage {
|
||||
type: 'setRange'
|
||||
minutes: number
|
||||
@@ -1021,7 +1017,6 @@ interface ITrafficWorkerRequestSnapshotMessage {
|
||||
type TrafficWorkerRequestMessage =
|
||||
| ITrafficWorkerInitMessage
|
||||
| ITrafficWorkerAppendMessage
|
||||
| ITrafficWorkerClearMessage
|
||||
| ITrafficWorkerSetRangeMessage
|
||||
| ITrafficWorkerRequestSnapshotMessage
|
||||
|
||||
@@ -1029,15 +1024,7 @@ interface ITrafficWorkerSnapshotMessage {
|
||||
type: 'snapshot'
|
||||
dataPoints: ITrafficDataPoint[]
|
||||
samplerStats: ISamplerStats
|
||||
rangeMinutes: number
|
||||
lastTimestamp?: number
|
||||
reason:
|
||||
| 'init'
|
||||
| 'interval'
|
||||
| 'range-change'
|
||||
| 'request'
|
||||
| 'append-throttle'
|
||||
| 'clear'
|
||||
}
|
||||
|
||||
interface ITrafficWorkerLogMessage {
|
||||
|
||||
Reference in New Issue
Block a user