connections.tsx 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { useEffect, useMemo, useState } from "react";
  2. import { useLockFn } from "ahooks";
  3. import { Box, Button, Paper, TextField } from "@mui/material";
  4. import { Virtuoso } from "react-virtuoso";
  5. import { useTranslation } from "react-i18next";
  6. import { ApiType } from "../services/types";
  7. import { closeAllConnections, getInformation } from "../services/api";
  8. import BasePage from "../components/base/base-page";
  9. import ConnectionItem from "../components/connection/connection-item";
  10. const initConn = { uploadTotal: 0, downloadTotal: 0, connections: [] };
  11. const ConnectionsPage = () => {
  12. const { t } = useTranslation();
  13. const [filterText, setFilterText] = useState("");
  14. const [connData, setConnData] = useState<ApiType.Connections>(initConn);
  15. const filterConn = useMemo(() => {
  16. return connData.connections.filter((conn) =>
  17. (conn.metadata.host || conn.metadata.destinationIP)?.includes(filterText)
  18. );
  19. }, [connData, filterText]);
  20. useEffect(() => {
  21. let ws: WebSocket | null = null;
  22. getInformation().then((result) => {
  23. const { server = "", secret = "" } = result;
  24. ws = new WebSocket(`ws://${server}/connections?token=${secret}`);
  25. ws.addEventListener("message", (event) => {
  26. const data = JSON.parse(event.data) as ApiType.Connections;
  27. // 与前一次connections的展示顺序尽量保持一致
  28. setConnData((old) => {
  29. const oldConn = old.connections;
  30. const maxLen = data.connections.length;
  31. const connections: typeof oldConn = [];
  32. const rest = data.connections.filter((each) => {
  33. const index = oldConn.findIndex((o) => o.id === each.id);
  34. if (index >= 0 && index < maxLen) {
  35. const old = oldConn[index];
  36. each.curUpload = each.upload - old.upload;
  37. each.curDownload = each.download - old.download;
  38. connections[index] = each;
  39. return false;
  40. }
  41. return true;
  42. });
  43. for (let i = 0; i < maxLen; ++i) {
  44. if (!connections[i] && rest.length > 0) {
  45. connections[i] = rest.shift()!;
  46. connections[i].curUpload = 0;
  47. connections[i].curDownload = 0;
  48. }
  49. }
  50. return { ...data, connections };
  51. });
  52. });
  53. });
  54. return () => ws?.close();
  55. }, []);
  56. const onCloseAll = useLockFn(closeAllConnections);
  57. return (
  58. <BasePage
  59. title={t("Connections")}
  60. contentStyle={{ height: "100%" }}
  61. header={
  62. <Button
  63. size="small"
  64. sx={{ mt: 1 }}
  65. variant="contained"
  66. onClick={onCloseAll}
  67. >
  68. {t("Close All")}
  69. </Button>
  70. }
  71. >
  72. <Paper sx={{ boxShadow: 2, height: "100%" }}>
  73. <Box
  74. sx={{
  75. pt: 1,
  76. mb: 0.5,
  77. mx: "12px",
  78. height: "36px",
  79. display: "flex",
  80. alignItems: "center",
  81. }}
  82. >
  83. {/* <Select
  84. size="small"
  85. autoComplete="off"
  86. value={logState}
  87. onChange={(e) => setLogState(e.target.value)}
  88. sx={{ width: 120, mr: 1, '[role="button"]': { py: 0.65 } }}
  89. >
  90. <MenuItem value="all">ALL</MenuItem>
  91. <MenuItem value="info">INFO</MenuItem>
  92. <MenuItem value="warn">WARN</MenuItem>
  93. </Select> */}
  94. <TextField
  95. hiddenLabel
  96. fullWidth
  97. size="small"
  98. autoComplete="off"
  99. variant="outlined"
  100. placeholder="Filter conditions"
  101. value={filterText}
  102. onChange={(e) => setFilterText(e.target.value)}
  103. sx={{ input: { py: 0.65, px: 1.25 } }}
  104. />
  105. </Box>
  106. <Box height="calc(100% - 50px)">
  107. <Virtuoso
  108. data={filterConn}
  109. itemContent={(index, item) => <ConnectionItem value={item} />}
  110. />
  111. </Box>
  112. </Paper>
  113. </BasePage>
  114. );
  115. };
  116. export default ConnectionsPage;