From 0dfa8be316462b32ecbd2b26754fcf4f7099a32c Mon Sep 17 00:00:00 2001 From: Tunglies <77394545+Tunglies@users.noreply.github.com> Date: Wed, 28 Oct 2026 09:59:44 +0800 Subject: [PATCH] refactor(traffic): drop unreachable inline monitor fallback The inline traffic monitor duplicated the worker's message loop, snapshot throttling and aging logic but only runs when Worker is undefined or its constructor throws, which no supported Tauri webview or browser hits. Keep the worker as the single implementation and remove the mode switch and the pending-message queue that could only ever buffer the init message. --- src/hooks/use-traffic-monitor.ts | 248 ++++--------------------------- 1 file changed, 32 insertions(+), 216 deletions(-) diff --git a/src/hooks/use-traffic-monitor.ts b/src/hooks/use-traffic-monitor.ts index 97fe30f7c..242fedaa1 100644 --- a/src/hooks/use-traffic-monitor.ts +++ b/src/hooks/use-traffic-monitor.ts @@ -3,7 +3,6 @@ import { Traffic } from 'tauri-plugin-mihomo-api' import { useVisibility } from '@/hooks/use-visibility' import { debugLog } from '@/utils/debug' -import { TrafficDataSampler, isSameTrafficData } from '@/utils/traffic-sampler' // 引用计数管理器 class ReferenceCounter { @@ -32,119 +31,11 @@ const WORKER_CONFIG = { defaultRangeMinutes: 10, } -class InlineTrafficMonitor { - private config = { ...WORKER_CONFIG } - private sampler = new TrafficDataSampler(this.config) - private throttleTimer: ReturnType | null = null - private agingTimer: ReturnType | null = null - private currentRange = this.config.defaultRangeMinutes - private lastTimestamp: number | undefined - private lastBroadcast: ITrafficDataPoint[] = [] - - constructor( - private emit: (snapshot: ITrafficWorkerSnapshotMessage) => void, - ) {} - - start(rangeMinutes?: number) { - this.currentRange = rangeMinutes ?? this.currentRange - this.handle({ - type: 'init', - config: { - ...this.config, - defaultRangeMinutes: this.currentRange, - }, - }) - } - - stop() { - if (this.throttleTimer !== null) { - clearTimeout(this.throttleTimer) - this.throttleTimer = null - } - if (this.agingTimer !== null) { - clearInterval(this.agingTimer) - this.agingTimer = null - } - this.sampler.clear() - this.lastTimestamp = undefined - } - - handle(message: TrafficWorkerRequestMessage) { - switch (message.type) { - case 'init': { - this.config = { ...message.config } - this.sampler = new TrafficDataSampler(this.config) - this.currentRange = message.config.defaultRangeMinutes - // Re-broadcast when points age out of the range, not on every tick - this.agingTimer = setInterval(() => { - if (this.throttleTimer !== null) return - const slice = this.sampler.getDataForTimeRange(this.currentRange) - if (!isSameTrafficData(this.lastBroadcast, slice)) { - this.emitSnapshot() - } - }, 1000) - this.emitSnapshot() - break - } - case 'append': { - const timestamp = message.payload.timestamp ?? Date.now() - const dataPoint: ITrafficDataPoint = { - up: message.payload.up || 0, - down: message.payload.down || 0, - timestamp, - } - - this.lastTimestamp = timestamp - this.sampler.addDataPoint(dataPoint) - this.scheduleSnapshot() - break - } - case 'setRange': { - if (this.currentRange !== message.minutes) { - this.currentRange = message.minutes - this.emitSnapshot() - } - break - } - case 'requestSnapshot': { - this.emitSnapshot() - break - } - default: - break - } - } - - private emitSnapshot() { - const dataPoints = this.sampler.getDataForTimeRange(this.currentRange) - - this.emit({ - type: 'snapshot', - dataPoints, - samplerStats: this.sampler.getStats(), - lastTimestamp: this.lastTimestamp, - }) - this.lastBroadcast = dataPoints - } - - private scheduleSnapshot() { - if (this.throttleTimer !== null) return - this.throttleTimer = setTimeout(() => { - this.throttleTimer = null - this.emitSnapshot() - }, this.config.snapshotIntervalMs) - } -} - class TrafficWorkerClient { private worker: Worker | null = null - private inlineMonitor: InlineTrafficMonitor | null = null - private mode: 'worker' | 'inline' | null = null private listeners = new Set< (snapshot: ITrafficWorkerSnapshotMessage) => void >() - private pendingMessages: TrafficWorkerRequestMessage[] = [] - private ready = false private currentRange = WORKER_CONFIG.defaultRangeMinutes start(rangeMinutes?: number) { @@ -155,101 +46,52 @@ class TrafficWorkerClient { this.currentRange = rangeMinutes ?? this.currentRange - if (this.ready) return + if (this.worker) return const initMessage: TrafficWorkerRequestMessage = { type: 'init', - config: { - rawDataMinutes: WORKER_CONFIG.rawDataMinutes, - compressedDataMinutes: WORKER_CONFIG.compressedDataMinutes, - compressionRatio: WORKER_CONFIG.compressionRatio, - snapshotIntervalMs: WORKER_CONFIG.snapshotIntervalMs, - defaultRangeMinutes: this.currentRange, - }, + config: { ...WORKER_CONFIG, defaultRangeMinutes: this.currentRange }, } - if (typeof Worker !== 'undefined') { - try { - this.worker = new Worker( - new URL('../services/traffic-monitor-worker.ts', import.meta.url), - { type: 'module' }, - ) - this.mode = 'worker' + this.worker = new Worker( + new URL('../services/traffic-monitor-worker.ts', import.meta.url), + { type: 'module' }, + ) - this.worker.onmessage = ( - event: MessageEvent, - ) => { - const message = event.data - if (message.type === 'snapshot') { - if (import.meta.env.MODE === 'perf') { - document.documentElement.dataset.perfWorker = String( - message.lastTimestamp ?? 0, - ) - document.documentElement.dataset.perfPoints = String( - message.dataPoints.length, - ) - const last = message.dataPoints.at(-1) - document.documentElement.dataset.perfLastUp = String( - last?.up ?? 0, - ) - document.documentElement.dataset.perfLastDown = String( - last?.down ?? 0, - ) - } - this.listeners.forEach((listener) => { - listener(message) - }) - } + this.worker.onmessage = ( + event: MessageEvent, + ) => { + const message = event.data + if (message.type === 'snapshot') { + if (import.meta.env.MODE === 'perf') { + document.documentElement.dataset.perfWorker = String( + message.lastTimestamp ?? 0, + ) + document.documentElement.dataset.perfPoints = String( + message.dataPoints.length, + ) + const last = message.dataPoints.at(-1) + document.documentElement.dataset.perfLastUp = String(last?.up ?? 0) + document.documentElement.dataset.perfLastDown = String( + last?.down ?? 0, + ) } - - this.worker.onerror = (error) => { - debugLog(`[TrafficWorkerClient] Worker error: ${String(error)}`) - } - - this.ready = true - this.post(initMessage) - this.flushQueue() - return - } catch (error) { - debugLog( - `[TrafficWorkerClient] Worker initialization failed, falling back to inline sampler: ${String(error)}`, - ) - this.worker = null - this.mode = null + this.listeners.forEach((listener) => { + listener(message) + }) } - } else { - debugLog( - '[TrafficWorkerClient] Worker not supported, using inline sampler', - ) } - this.startInline(initMessage) - } + this.worker.onerror = (error) => { + debugLog(`[TrafficWorkerClient] Worker error: ${String(error)}`) + } - private startInline(initMessage: TrafficWorkerRequestMessage) { - this.inlineMonitor = new InlineTrafficMonitor((snapshot) => { - this.listeners.forEach((listener) => { - listener(snapshot) - }) - }) - this.mode = 'inline' - this.ready = true this.post(initMessage) - this.flushQueue() } stop() { - if (this.worker) { - this.worker.terminate() - } - if (this.inlineMonitor) { - this.inlineMonitor.stop() - } + this.worker?.terminate() this.worker = null - this.inlineMonitor = null - this.mode = null - this.ready = false - this.pendingMessages = [] } onSnapshot(listener: (snapshot: ITrafficWorkerSnapshotMessage) => void) { @@ -260,37 +102,11 @@ class TrafficWorkerClient { } private post(message: TrafficWorkerRequestMessage) { - if (!this.ready) { - this.pendingMessages.push(message) - return - } - - if (this.mode === 'worker' && this.worker) { - this.worker.postMessage(message) - return - } - - if (this.mode === 'inline' && this.inlineMonitor) { - this.inlineMonitor.handle(message) - return - } - - this.pendingMessages.push(message) - } - - private flushQueue() { - if (!this.ready || this.pendingMessages.length === 0) { - return - } - const queued = [...this.pendingMessages] - this.pendingMessages = [] - queued.forEach((message) => { - this.post(message) - }) + this.worker?.postMessage(message) } private ensureStarted() { - if (!this.ready) { + if (!this.worker) { this.start(this.currentRange) } }