How Clash Nyanpasu Implements Traffic Monitoring and Data Visualization
Clash Nyanpasu gathers real-time network traffic statistics through a WebSocket connection to the Clash core, buffers the data in a React context provider, and renders interactive line charts using a custom hook and utility formatting functions.
The repository libnyanpasu/clash-nyanpasu implements a three-layer architecture for traffic monitoring and data visualization that bridges the Rust-based backend with a React frontend. This article examines the specific implementation details, file paths, and code patterns used to stream, store, and display network throughput metrics.
Backend WebSocket API Layer
The data acquisition starts in frontend/interface/src/ipc/use-clash-traffic.ts, where a custom hook opens a persistent WebSocket connection to the Clash core's /traffic endpoint.
The hook resolves the URL using resolveUrl('traffic'), then listens for incoming JSON messages containing ClashTraffic objects. Each message includes up and down fields representing bytes per second. The hook maintains a rolling buffer of traffic history, automatically truncating the array to MAX_TRAFFIC_HISTORY (defined in src/ipc/consts.ts) to prevent memory bloat.
// frontend/interface/src/ipc/use-clash-traffic.ts
export const useClashTraffic = () => {
const { trafficWS } = useWebSocket(resolveUrl('traffic'));
const [data, setData] = useState<ClashTraffic[]>([]);
useEffect(() => {
if (!trafficWS) return;
trafficWS.onmessage = (msg) => {
const traffic = JSON.parse(msg.data) as ClashTraffic;
setData((prev) => {
const next = [...prev, traffic];
// limit history length (MAX_TRAFFIC_HISTORY)
return next.length > MAX_TRAFFIC_HISTORY ? next.slice(-MAX_TRAFFIC_HISTORY) : next;
});
};
}, [trafficWS]);
return { data };
};
State Management and Context Provider
To share traffic data across the component tree without prop drilling, the application uses ClashWsProvider located in frontend/interface/src/provider/clash-ws-provider.tsx.
This React context provider consumes the useClashTraffic hook and exposes the traffic array to child components. It implements the recordTraffic boolean flag that allows users to pause data collection without closing the WebSocket connection. The provider also enforces the MAX_TRAFFIC_HISTORY limit at the context level, ensuring all dashboard components receive a consistently sized dataset.
// frontend/interface/src/provider/clash-ws-provider.tsx
// Consumes useClashTraffic and provides traffic data to the app
const ClashWsProvider = ({ children }) => {
const { data: trafficData } = useClashTraffic();
const [recordTraffic, setRecordTraffic] = useState(true);
// Filter or limit data based on recordTraffic flag
const activeTraffic = recordTraffic ? trafficData : [];
return (
<ClashWsContext.Provider value={{ traffic: activeTraffic, recordTraffic, setRecordTraffic }}>
{children}
</ClashWsContext.Provider>
);
};
Frontend Visualization Components
The dashboard UI renders traffic metrics using two primary components: DataPanel for the main charts and DataLine for compact tile views.
Data Panel and Chart Rendering
frontend/nyanpasu/src/components/dashboard/data-panel.tsx imports the useClashTraffic hook (exposed through the provider) and maps the traffic history into separate arrays for download and upload rates. It passes these arrays to the charting library as LineChart data props.
// frontend/nyanpasu/src/components/dashboard/data-panel.tsx
import { useClashTraffic } from '@/hooks/useClashTraffic';
export const DataPanel = () => {
const { data: traffic } = useClashTraffic();
return (
<div className="grid gap-4">
<LineChart
data={traffic.map(t => t.down)}
title={t('Download Traffic')}
/>
<LineChart
data={traffic.map(t => t.up)}
title={t('Upload Traffic')}
/>
</div>
);
};
Traffic Formatting Utility
Raw byte values are converted to human-readable strings (KB, MB, GB) by parseTraffic in frontend/nyanpasu/src/utils/parse-traffic.ts. This utility is used throughout the UI for tooltips, table cells, and the dashboard tiles.
// frontend/nyanpasu/src/utils/parse-traffic.ts
export default function parseTraffic(bytes: number): string[] {
if (bytes < 1024) return [bytes + ' B'];
const units = ['KB', 'MB', 'GB', 'TB'];
let i = -1;
do {
bytes /= 1024;
i++;
} while (bytes >= 1024 && i < units.length - 1);
return [bytes.toFixed(2), units[i]];
}
Compact Dashboard Tiles
For smaller UI surfaces, frontend/nyanpasu/src/components/dashboard/dataline.tsx displays the most recent traffic sample (data.at(-1)) or the full raw history depending on the type prop, using parseTraffic for formatting.
Configuration and Feature Toggles
Users can disable the traffic visualization through the traffic_graph setting defined in backend/tauri/src/config/nyanpasu/mod.rs. When set to false, the UI components conditionally skip rendering the chart elements, though the underlying WebSocket connection may remain active for other telemetry purposes.
Summary
- WebSocket Data Stream:
use-clash-traffic.tsestablishes a persistent connection to the Clash core's/trafficendpoint and buffersClashTrafficobjects up toMAX_TRAFFIC_HISTORY. - React Context Provider:
clash-ws-provider.tsxdistributes traffic data throughout the application and supports pausing collection via therecordTrafficflag. - Chart Rendering:
data-panel.tsxconsumes the traffic hook and renders separate line charts for download and upload rates using the mappedupanddownfields. - Data Formatting:
parse-traffic.tsconverts raw byte counts into human-readable units (KB, MB, GB) for UI display. - User Control: The
traffic_graphconfiguration option in the Rust backend allows users to toggle the visualization feature on or off.
Frequently Asked Questions
How does Clash Nyanpasu collect real-time traffic data?
Clash Nyanpasu opens a WebSocket connection to the Clash core's /traffic endpoint via the useClashTraffic hook in frontend/interface/src/ipc/use-clash-traffic.ts. This hook listens for JSON messages containing upload and download byte counts, parses them into typed ClashTraffic objects, and maintains a rolling history buffer limited by MAX_TRAFFIC_HISTORY.
What component renders the traffic charts in the dashboard?
The DataPanel component located at frontend/nyanpasu/src/components/dashboard/data-panel.tsx is responsible for rendering the traffic visualization. It imports the useClashTraffic hook to access the buffered traffic history, then maps the up and down fields into separate arrays passed as data props to line chart components for upload and download rates respectively.
How does the application format raw byte values for display?
Raw byte values are converted to human-readable strings using the parseTraffic utility in frontend/nyanpasu/src/utils/parse-traffic.ts. This function divides the byte count by 1024 iteratively through unit tiers (KB, MB, GB, TB) until the value falls below 1024, then returns a formatted string with two decimal places and the appropriate unit suffix.
Can users disable the traffic graph without stopping data collection?
Yes, users can toggle the traffic visualization through the traffic_graph configuration setting defined in backend/tauri/src/config/nyanpasu/mod.rs. When disabled, the UI components conditionally skip rendering the chart elements, but the underlying WebSocket connection managed by useClashTraffic typically remains active to support other telemetry features or immediate re-enabling of the graph.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →