layout-traffic.tsx 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. import { useEffect, useRef, useState } from "react";
  2. import { Box, Typography } from "@mui/material";
  3. import {
  4. ArrowDownward,
  5. ArrowUpward,
  6. MemoryOutlined,
  7. } from "@mui/icons-material";
  8. import { useClashInfo } from "@/hooks/use-clash";
  9. import { useVerge } from "@/hooks/use-verge";
  10. import { TrafficGraph, type TrafficRef } from "./traffic-graph";
  11. import { useLogSetup } from "./use-log-setup";
  12. import { useVisibility } from "@/hooks/use-visibility";
  13. import { useWebsocket } from "@/hooks/use-websocket";
  14. import parseTraffic from "@/utils/parse-traffic";
  15. // setup the traffic
  16. export const LayoutTraffic = () => {
  17. const { clashInfo } = useClashInfo();
  18. const { verge } = useVerge();
  19. // whether hide traffic graph
  20. const trafficGraph = verge?.traffic_graph ?? true;
  21. const trafficRef = useRef<TrafficRef>(null);
  22. const [traffic, setTraffic] = useState({ up: 0, down: 0 });
  23. const [memory, setMemory] = useState({ inuse: 0 });
  24. const pageVisible = useVisibility();
  25. // setup log ws during layout
  26. useLogSetup();
  27. const trafficWs = useWebsocket(
  28. (event) => {
  29. const data = JSON.parse(event.data) as ITrafficItem;
  30. trafficRef.current?.appendData(data);
  31. setTraffic(data);
  32. },
  33. { onError: () => setTraffic({ up: 0, down: 0 }), errorCount: 10 }
  34. );
  35. useEffect(() => {
  36. if (!clashInfo || !pageVisible) return;
  37. const { server = "", secret = "" } = clashInfo;
  38. trafficWs.connect(
  39. `ws://${server}/traffic?token=${encodeURIComponent(secret)}`
  40. );
  41. return () => trafficWs.disconnect();
  42. }, [clashInfo, pageVisible]);
  43. /* --------- meta memory information --------- */
  44. const isMetaCore = verge?.clash_core?.includes("clash-meta");
  45. const displayMemory = isMetaCore && (verge?.enable_memory_usage ?? true);
  46. const memoryWs = useWebsocket(
  47. (event) => {
  48. setMemory(JSON.parse(event.data));
  49. },
  50. { onError: () => setMemory({ inuse: 0 }), errorCount: 10 }
  51. );
  52. useEffect(() => {
  53. if (!clashInfo || !pageVisible || !displayMemory) return;
  54. const { server = "", secret = "" } = clashInfo;
  55. memoryWs.connect(
  56. `ws://${server}/memory?token=${encodeURIComponent(secret)}`
  57. );
  58. return () => memoryWs.disconnect();
  59. }, [clashInfo, pageVisible, displayMemory]);
  60. const [up, upUnit] = parseTraffic(traffic.up);
  61. const [down, downUnit] = parseTraffic(traffic.down);
  62. const [inuse, inuseUnit] = parseTraffic(memory.inuse);
  63. const iconStyle: any = {
  64. sx: { mr: "8px", fontSize: 16 },
  65. };
  66. const valStyle: any = {
  67. component: "span",
  68. // color: "primary",
  69. textAlign: "center",
  70. sx: { flex: "1 1 56px", userSelect: "none" },
  71. };
  72. const unitStyle: any = {
  73. component: "span",
  74. color: "grey.500",
  75. fontSize: "12px",
  76. textAlign: "right",
  77. sx: { flex: "0 1 27px", userSelect: "none" },
  78. };
  79. return (
  80. <Box position="relative" onClick={trafficRef.current?.toggleStyle}>
  81. {trafficGraph && pageVisible && (
  82. <div style={{ width: "100%", height: 60, marginBottom: 6 }}>
  83. <TrafficGraph ref={trafficRef} />
  84. </div>
  85. )}
  86. <Box display="flex" flexDirection="column" gap={0.75}>
  87. <Box display="flex" alignItems="center" whiteSpace="nowrap">
  88. <ArrowUpward
  89. {...iconStyle}
  90. color={+up > 0 ? "secondary" : "disabled"}
  91. />
  92. <Typography {...valStyle} color="secondary">
  93. {up}
  94. </Typography>
  95. <Typography {...unitStyle}>{upUnit}/s</Typography>
  96. </Box>
  97. <Box display="flex" alignItems="center" whiteSpace="nowrap">
  98. <ArrowDownward
  99. {...iconStyle}
  100. color={+down > 0 ? "primary" : "disabled"}
  101. />
  102. <Typography {...valStyle} color="primary">
  103. {down}
  104. </Typography>
  105. <Typography {...unitStyle}>{downUnit}/s</Typography>
  106. </Box>
  107. {displayMemory && (
  108. <Box
  109. display="flex"
  110. alignItems="center"
  111. whiteSpace="nowrap"
  112. title="Memory Usage"
  113. >
  114. <MemoryOutlined {...iconStyle} color="disabled" />
  115. <Typography {...valStyle}>{inuse}</Typography>
  116. <Typography {...unitStyle}>{inuseUnit}</Typography>
  117. </Box>
  118. )}
  119. </Box>
  120. </Box>
  121. );
  122. };