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.ts establishes a persistent connection to the Clash core's /traffic endpoint and buffers ClashTraffic objects up to MAX_TRAFFIC_HISTORY.
  • React Context Provider: clash-ws-provider.tsx distributes traffic data throughout the application and supports pausing collection via the recordTraffic flag.
  • Chart Rendering: data-panel.tsx consumes the traffic hook and renders separate line charts for download and upload rates using the mapped up and down fields.
  • Data Formatting: parse-traffic.ts converts raw byte counts into human-readable units (KB, MB, GB) for UI display.
  • User Control: The traffic_graph configuration 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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →