import { useEffect, useRef, useState } from "react"; import { Box, Typography } from "@mui/material"; import { ArrowDownward, ArrowUpward } from "@mui/icons-material"; import { useClashInfo } from "@/hooks/use-clash"; import { useVerge } from "@/hooks/use-verge"; import { TrafficGraph, type TrafficRef } from "./traffic-graph"; import { useLogSetup } from "./use-log-setup"; import parseTraffic from "@/utils/parse-traffic"; // setup the traffic const LayoutTraffic = () => { const { clashInfo } = useClashInfo(); // whether hide traffic graph const { verge } = useVerge(); const trafficGraph = verge?.traffic_graph ?? true; const trafficRef = useRef(null); const [traffic, setTraffic] = useState({ up: 0, down: 0 }); const wsRef = useRef(null); const [refresh, setRefresh] = useState({}); // setup log ws during layout useLogSetup(); useEffect(() => { if (!clashInfo) return; const { server = "", secret = "" } = clashInfo; const ws = new WebSocket(`ws://${server}/traffic?token=${secret}`); ws.addEventListener("message", (event) => { const data = JSON.parse(event.data) as ITrafficItem; trafficRef.current?.appendData(data); setTraffic(data); }); ws.addEventListener("error", () => { setTimeout(() => { if (document.visibilityState === "visible") { setRefresh({}); } }, 1000); }); ws.addEventListener("close", () => { setTimeout(() => { if (document.visibilityState === "visible") { setRefresh({}); } }, 1000); }); wsRef.current = ws; return () => { ws?.close(); wsRef.current = null; }; }, [clashInfo, refresh]); useEffect(() => { const handleVisibleChange = () => { if (document.visibilityState === "visible") { // reconnect websocket if ( wsRef.current && wsRef.current.readyState !== WebSocket.CONNECTING ) { setRefresh({}); } } }; document.addEventListener("visibilitychange", handleVisibleChange); return () => { document.removeEventListener("visibilitychange", handleVisibleChange); }; }, []); const [up, upUnit] = parseTraffic(traffic.up); const [down, downUnit] = parseTraffic(traffic.down); const valStyle: any = { component: "span", color: "primary", textAlign: "center", sx: { flex: "1 1 54px", userSelect: "none" }, }; const unitStyle: any = { component: "span", color: "grey.500", fontSize: "12px", textAlign: "right", sx: { flex: "0 1 27px", userSelect: "none" }, }; return ( {trafficGraph && (
)} 0 ? "primary" : "disabled"} /> {up} {upUnit}/s 0 ? "primary" : "disabled"} /> {down} {downUnit}/s
); }; export default LayoutTraffic;