From ffabc1ccbe107e14a0640f77974b055e0a97a81b Mon Sep 17 00:00:00 2001 From: liyuanhu Date: Fri, 18 Apr 2025 11:12:35 +0800 Subject: [PATCH] fix:bug --- __unconfig_vite.config.ts | 64 +++ package.json | 1 + pnpm-lock.yaml | 27 +- src/App.tsx | 111 ++++- src/hooks/useEventBus.ts | 26 ++ src/hooks/useStartupCheck.ts | 1 + src/layout/index.tsx | 10 +- .../components/ClearNodeDialog/index.tsx | 255 +++++------ .../components/world-geo.tsx | 3 +- .../components/ClearNodeDialog/index.tsx | 251 +++++------ .../components/FormAlertDialog/index.tsx | 396 +++++++++--------- .../components/world-geo.tsx | 4 +- .../components/ClearNodeDialog/index.tsx | 250 +++++------ src/pages/new-home/components/world-geo.tsx | 33 +- src/routes/index.tsx | 4 +- src/store/web3Slice.ts | 13 - src/utils/eventBus.ts | 23 + src/utils/webSocketClient.ts | 2 +- 18 files changed, 774 insertions(+), 700 deletions(-) create mode 100644 __unconfig_vite.config.ts create mode 100644 src/hooks/useEventBus.ts create mode 100644 src/utils/eventBus.ts diff --git a/__unconfig_vite.config.ts b/__unconfig_vite.config.ts new file mode 100644 index 0000000..d98dfee --- /dev/null +++ b/__unconfig_vite.config.ts @@ -0,0 +1,64 @@ + +let __unconfig_data; +let __unconfig_stub = function (data = {}) { __unconfig_data = data }; +__unconfig_stub.default = (data = {}) => { __unconfig_data = data }; +import { defineConfig } from 'vite' +import react from '@vitejs/plugin-react' +import AutoImport from 'unplugin-auto-import/vite' +import svgr from 'vite-plugin-svgr' +import { CodeInspectorPlugin } from 'code-inspector-plugin' + +import path from 'path' + +// const host = process.env.TAURI_DEV_HOST; +const host = '127.0.0.1' + +// https://vitejs.dev/config/ +const __unconfig_default = defineConfig(async () => ({ + plugins: [ + react(), + AutoImport({ + dts: './auto-imports.d.ts', //此文件配置保存后系统自动生成 + imports: [ + 'react', // 自动导入 React + ], + }), + svgr({ include: '**/*.svg?react' }), + CodeInspectorPlugin({ + bundler: 'vite', + }), + ], + resolve: { + alias: { + '@': path.resolve(__dirname, './src'), + 'package.json': path.resolve(__dirname, './package.json'), + }, + }, + + build: { + sourcemap: true, + }, + // Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build` + // + // 1. prevent vite from obscuring rust errors + clearScreen: false, + // 2. tauri expects a fixed port, fail if that port is not available + server: { + port: 1420, + strictPort: true, + host: host, + hmr: host + ? { + protocol: 'ws', + host, + port: 1421, + } + : undefined, + watch: { + // 3. tell vite to ignore watching `src-tauri` + ignored: ['**/src-tauri/**'], + }, + }, +})) + +if (typeof __unconfig_default === "function") __unconfig_default(...[{"command":"serve","mode":"development"}]);export default __unconfig_data; \ No newline at end of file diff --git a/package.json b/package.json index df64166..043376e 100644 --- a/package.json +++ b/package.json @@ -48,6 +48,7 @@ "i18next": "^24.2.0", "lodash-es": "^4.17.21", "lucide-react": "^0.469.0", + "mitt": "^3.0.1", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hook-form": "^7.54.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 24a7e6b..fb639db 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -119,6 +119,9 @@ importers: lucide-react: specifier: ^0.469.0 version: 0.469.0(react@18.3.1) + mitt: + specifier: ^3.0.1 + version: 3.0.1 react: specifier: ^18.2.0 version: 18.3.1 @@ -569,42 +572,36 @@ packages: engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm-musl@2.5.0': resolution: {integrity: sha512-6uHywSIzz8+vi2lAzFeltnYbdHsDm3iIB57d4g5oaB9vKwjb6N6dRIgZMujw4nm5r6v9/BQH0noq6DzHrqr2pA==} engines: {node: '>= 10.0.0'} cpu: [arm] os: [linux] - libc: [musl] '@parcel/watcher-linux-arm64-glibc@2.5.0': resolution: {integrity: sha512-BfNjXwZKxBy4WibDb/LDCriWSKLz+jJRL3cM/DllnHH5QUyoiUNEp3GmL80ZqxeumoADfCCP19+qiYiC8gUBjA==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-arm64-musl@2.5.0': resolution: {integrity: sha512-S1qARKOphxfiBEkwLUbHjCY9BWPdWnW9j7f7Hb2jPplu8UZ3nes7zpPOW9bkLbHRvWM0WDTsjdOTUgW0xLBN1Q==} engines: {node: '>= 10.0.0'} cpu: [arm64] os: [linux] - libc: [musl] '@parcel/watcher-linux-x64-glibc@2.5.0': resolution: {integrity: sha512-d9AOkusyXARkFD66S6zlGXyzx5RvY+chTP9Jp0ypSTC9d4lzyRs9ovGf/80VCxjKddcUvnsGwCHWuF2EoPgWjw==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [glibc] '@parcel/watcher-linux-x64-musl@2.5.0': resolution: {integrity: sha512-iqOC+GoTDoFyk/VYSFHwjHhYrk8bljW6zOhPuhi5t9ulqiYq1togGJB5e3PwYVFFfeVgc6pbz3JdQyDoBszVaA==} engines: {node: '>= 10.0.0'} cpu: [x64] os: [linux] - libc: [musl] '@parcel/watcher-win32-arm64@2.5.0': resolution: {integrity: sha512-twtft1d+JRNkM5YbmexfcH/N4znDtjgysFaV9zvZmmJezQsKpkfLYJ+JFV3uygugK6AtIM2oADPkB2AdhBrNig==} @@ -1320,55 +1317,46 @@ packages: resolution: {integrity: sha512-9OwUnK/xKw6DyRlgx8UizeqRFOfi9mf5TYCw1uolDaJSbUmBxP85DE6T4ouCMoN6pXw8ZoTeZCSEfSaYo+/s1w==} cpu: [arm] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.27.4': resolution: {integrity: sha512-Vgdo4fpuphS9V24WOV+KwkCVJ72u7idTgQaBoLRD0UxBAWTF9GWurJO9YD9yh00BzbkhpeXtm6na+MvJU7Z73A==} cpu: [arm] os: [linux] - libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.27.4': resolution: {integrity: sha512-pleyNgyd1kkBkw2kOqlBx+0atfIIkkExOTiifoODo6qKDSpnc6WzUY5RhHdmTdIJXBdSnh6JknnYTtmQyobrVg==} cpu: [arm64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.27.4': resolution: {integrity: sha512-caluiUXvUuVyCHr5DxL8ohaaFFzPGmgmMvwmqAITMpV/Q+tPoaHZ/PWa3t8B2WyoRcIIuu1hkaW5KkeTDNSnMA==} cpu: [arm64] os: [linux] - libc: [musl] '@rollup/rollup-linux-powerpc64le-gnu@4.27.4': resolution: {integrity: sha512-FScrpHrO60hARyHh7s1zHE97u0KlT/RECzCKAdmI+LEoC1eDh/RDji9JgFqyO+wPDb86Oa/sXkily1+oi4FzJQ==} cpu: [ppc64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.27.4': resolution: {integrity: sha512-qyyprhyGb7+RBfMPeww9FlHwKkCXdKHeGgSqmIXw9VSUtvyFZ6WZRtnxgbuz76FK7LyoN8t/eINRbPUcvXB5fw==} cpu: [riscv64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-s390x-gnu@4.27.4': resolution: {integrity: sha512-PFz+y2kb6tbh7m3A7nA9++eInGcDVZUACulf/KzDtovvdTizHpZaJty7Gp0lFwSQcrnebHOqxF1MaKZd7psVRg==} cpu: [s390x] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.27.4': resolution: {integrity: sha512-Ni8mMtfo+o/G7DVtweXXV/Ol2TFf63KYjTtoZ5f078AUgJTmaIJnj4JFU7TK/9SVWTaSJGxPi5zMDgK4w+Ez7Q==} cpu: [x64] os: [linux] - libc: [glibc] '@rollup/rollup-linux-x64-musl@4.27.4': resolution: {integrity: sha512-5AeeAF1PB9TUzD+3cROzFTnAJAcVUGLuR8ng0E0WXGkYhp6RD6L+6szYVX+64Rs0r72019KHZS1ka1q+zU/wUw==} cpu: [x64] os: [linux] - libc: [musl] '@rollup/rollup-win32-arm64-msvc@4.27.4': resolution: {integrity: sha512-yOpVsA4K5qVwu2CaS3hHxluWIK5HQTjNV4tWjQXluMiiiu4pJj4BN98CvxohNCpcjMeTXk/ZMJBRbgRg8HBB6A==} @@ -1490,28 +1478,24 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [glibc] '@tauri-apps/cli-linux-arm64-musl@2.1.0': resolution: {integrity: sha512-NzwqjUCilhnhJzusz3d/0i0F1GFrwCQbkwR6yAHUxItESbsGYkZRJk0yMEWkg3PzFnyK4cWTlQJMEU52TjhEzA==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - libc: [musl] '@tauri-apps/cli-linux-x64-gnu@2.1.0': resolution: {integrity: sha512-TyiIpMEtZxNOQmuFyfJwaaYbg3movSthpBJLIdPlKxSAB2BW0VWLY3/ZfIxm/G2YGHyREkjJvimzYE0i37PnMA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [glibc] '@tauri-apps/cli-linux-x64-musl@2.1.0': resolution: {integrity: sha512-/dQd0TlaxBdJACrR72DhynWftzHDaX32eBtS5WBrNJ+nnNb+znM3gON6nJ9tSE9jgDa6n1v2BkI/oIDtypfUXw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - libc: [musl] '@tauri-apps/cli-win32-arm64-msvc@2.1.0': resolution: {integrity: sha512-NdQJO7SmdYqOcE+JPU7bwg7+odfZMWO6g8xF9SXYCMdUzvM2Gv/AQfikNXz5yS7ralRhNFuW32i5dcHlxh4pDg==} @@ -2097,6 +2081,9 @@ packages: resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} engines: {node: '>=16 || 14 >=14.17'} + mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -4782,6 +4769,8 @@ snapshots: minipass@7.1.2: {} + mitt@3.0.1: {} + mkdirp@0.5.6: dependencies: minimist: 1.2.8 diff --git a/src/App.tsx b/src/App.tsx index 20845cd..179fcdd 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -2,14 +2,23 @@ import { useStartupCheck } from "@/hooks/useStartupCheck"; import { usePreventDefault } from "@/hooks/usePreventDefaultEventListener"; import { useGlobalShortcut } from "@/hooks/useGlobalShortcut"; import { useRecreateTheCircuit } from "@/hooks/useRecreateTheCircuit"; -import { useCoreConfig } from "./hooks/useCoreConfig"; -// import { commands } from '@/bindings' -import Titlebar from "@/components/Titlebar"; +import { useCoreConfig } from "@/hooks/useCoreConfig"; +import { useDispatch, useSelector } from "react-redux"; +import { + setProxyInfoProxies, + setProxiesList1, + setProxiesList2, + setProxiesLine, +} from "@/store/web3Slice"; +import type { AppDispatch, RootState } from "@/store"; +import eventBus, { eventTypes } from "@/utils/eventBus"; +import { WebSocketClient } from "@/utils/webSocketClient"; + +import Titlebar from "@/components/Titlebar"; import Layout from "@/layout"; import Tray from "@/components/Tray"; - function App() { // 执行启动自检 useStartupCheck(); @@ -22,7 +31,101 @@ function App() { // 读取配置,若文件不存在则持久化到本地 `%APPDATA%/com.paw.paw-gui` const { loadCoreConfig } = useCoreConfig(); loadCoreConfig(); + const dispatch = useDispatch(); + const { web3List, web3List2, proxy_info, path_list } = useSelector( + (state: RootState) => state.web3Reducer + ); + const webSocketClient = useRef(); + const openWsTraffic = async () => { + if (webSocketClient.current) return; + const { api_port } = await loadCoreConfig(); + // todo! 后面会把二级制文件启动的参数作为配置项,这里暂时写死 + webSocketClient.current = new WebSocketClient( + `ws://127.0.0.1:${api_port}/traffic`, + { + headers: { + Authorization: "Bearer secret", + }, + } + ); + + // 执行 WebSocket 操作 + await webSocketClient.current.connect(); + webSocketClient.current.addListener((msg: any) => { + if (msg.code === 0) { + switch (msg.event) { + case eventTypes.NODE_UP: + console.log("节点上线"); + break; + case eventTypes.NODE_DOWN: + // 添加下线节点到store 里面 + console.log("节点下线"); + break; + case eventTypes.MALICIOUS_NODE: + // 添加恶意节点到store 里面 + console.log("检测到恶意节点"); + break; + case eventTypes.NODE_INIT_COMPLATE: + console.log("节点预配置完成"); + break; + case eventTypes.NODE_REMOVE: + console.log("节点清除"); + break; + case eventTypes.NODE_ADD: + console.log("添加节点"); + break; + case eventTypes.NODE_INIT: + console.log("节点预配置"); + break; + default: + break; + } + } + }); + }; + + const createdSoketEventBus = async () => { + eventBus.on(eventTypes.NODE_INIT_COMPLATE, (data: any) => { + console.log("节点预配置完成", data); + webSocketClient.current?.sendMessage(data); + }); + eventBus.on(eventTypes.NODE_REMOVE, () => { + console.log("节点清除"); + webSocketClient.current?.sendMessage({ + code: 0, + event: eventTypes.NODE_REMOVE, + data: { + name: "proxy-xxx", + }, + }); + }); + }; + + const closeWsTraffic = async () => { + if (webSocketClient.current) { + await webSocketClient.current.disconnect(); + webSocketClient.current = null; + } + }; + + const removeSoketEventBus = () => { + eventBus.off(eventTypes.NODE_INIT_COMPLATE); + eventBus.off(eventTypes.NODE_REMOVE); + }; + + const initWebsocketsAndEventBus = async () => { + await openWsTraffic(); + await createdSoketEventBus(); + }; + + useEffect(() => { + // initWebsocketsAndEventBus(); + // return () => { + // closeWsTraffic(); + // removeSoketEventBus(); + // }; + }, []); return (
diff --git a/src/hooks/useEventBus.ts b/src/hooks/useEventBus.ts new file mode 100644 index 0000000..83f238e --- /dev/null +++ b/src/hooks/useEventBus.ts @@ -0,0 +1,26 @@ +// src/hooks/useEventBus.ts +import { useEffect } from 'react'; +import eventBus from '@/utils/eventBus'; + + +export function useEventBus( + event:any, + handler:any, +) { + useEffect(() => { + // 添加事件监听器 + eventBus.on(event, handler as any); + + // 清理函数 + return () => { + eventBus.off(event, handler as any); + }; + }, [event, handler]); // 依赖项包含 event 和 handler + + // 返回发布事件的函数 + return { + emit: (eventName:any, data: any) => { + eventBus.emit(eventName, data); + } + }; +} \ No newline at end of file diff --git a/src/hooks/useStartupCheck.ts b/src/hooks/useStartupCheck.ts index 6528070..43dcfa3 100644 --- a/src/hooks/useStartupCheck.ts +++ b/src/hooks/useStartupCheck.ts @@ -7,6 +7,7 @@ import { app } from '@tauri-apps/api' import { createCircuit } from '@/store/circuitSlice' import { setServiceStatus, getProxy, getVersion } from '@/store/serviceSlice' import { setNodes, setNodesError, clearNodes } from '@/store/nodesSlice' +// import {} from '@/store/web3Slice' // import { clearCircuitState } from '@/store/circuitSlice'; import { AppDispatch, RootState } from '@/store' diff --git a/src/layout/index.tsx b/src/layout/index.tsx index e75bd8e..c6e0c93 100644 --- a/src/layout/index.tsx +++ b/src/layout/index.tsx @@ -37,11 +37,11 @@ export default function Layout() { title: "面向溯源对抗的数据转发", icon: , }, - // { - // id: 'proxies', - // title: '节点池', - // icon: , - // }, + { + id: 'proxies', + title: '节点池', + icon: , + }, ]; const handleClickMenu = (index: number) => { diff --git a/src/pages/anti-forensics-forwarding/components/ClearNodeDialog/index.tsx b/src/pages/anti-forensics-forwarding/components/ClearNodeDialog/index.tsx index a7c627a..f0f2ee2 100644 --- a/src/pages/anti-forensics-forwarding/components/ClearNodeDialog/index.tsx +++ b/src/pages/anti-forensics-forwarding/components/ClearNodeDialog/index.tsx @@ -3,7 +3,7 @@ import { FormInstance } from "antd"; import { FormDialog } from "@/components/FormDialog"; import { useDispatch, useSelector } from "react-redux"; -import { nodeList,getRandomNodes } from "@/store/datas"; +import { nodeList, getRandomNodes } from "@/store/datas"; import "./index.scss"; import { EllipsisTooltip } from "@/components/Encapsulation"; import NotFailNodeIcon from "@/assets/svg/common/not-fail-node.svg?react"; @@ -11,170 +11,133 @@ import NotWarningNodeIcon from "@/assets/svg/common/not-warning-node.svg?react"; import { NODEDIALOGTYPE } from "../../index"; import { cn, getUrl } from "@/lib/utils"; -import { - setClearFailTimer, - setClearWarningTimer, -} from "@/store/web3Slice"; +import { } from "@/store/web3Slice"; import { AppDispatch, RootState } from "@/store"; import { isTimestampPlusTenMinutesBeforeNow } from "@/utils/tools"; export interface DialogConfig { - title: string; - desc: string; - successText: string; + title: string; + desc: string; + successText: string; } export const ProxyItem: React.FC<{ proxyInfo: any; clasName?: string }> = ( - props + props ) => { - const { name, code, exit = false } = props.proxyInfo; + const { name, code, exit = false } = props.proxyInfo; - return ( -
-
-
-
- -
- -
-
+ return ( +
+
+
+
+ +
+
- ); +
+
+ ); }; export const ClearNodeDialog = ({ - open, - setOpen, - successHandle, - dialogLoading, - form, - type, - canSubmit, + open, + setOpen, + successHandle, + dialogLoading, + form, + type, + canSubmit, }: { - open: boolean; - setOpen: (open: boolean) => void; - successHandle: () => void; - dialogLoading: boolean; - canSubmit: boolean; - form: FormInstance; - type: DialogConfig; + open: boolean; + setOpen: (open: boolean) => void; + successHandle: () => void; + dialogLoading: boolean; + canSubmit: boolean; + form: FormInstance; + type: DialogConfig; }) => { - const dispatch = useDispatch(); - const { clearWarningTimer, clearFailTimer } = useSelector( - (state: RootState) => state.web3Reducer - ); - const [isClear, setIsClear] = useState(false); - const showDialog = (open: boolean) => { - setOpen(open); - }; - const onSuccessHandle = () => { - successHandle(); - setIsClear(true); - if (type.title === NODEDIALOGTYPE.ClearFailNode.title) { - dispatch(setClearFailTimer(Date.now())); - } else if (type.title === NODEDIALOGTYPE.ClearWargingNode.title) { - dispatch(setClearWarningTimer(Date.now())); - } - // showDialog(false); - }; + const dispatch = useDispatch(); + const { } = useSelector( + (state: RootState) => state.web3Reducer + ); + const [isClear, setIsClear] = useState(false); + const showDialog = (open: boolean) => { + setOpen(open); + }; + const onSuccessHandle = () => { + successHandle(); + setIsClear(true); + if (type.title === NODEDIALOGTYPE.ClearFailNode.title) { + + } else if (type.title === NODEDIALOGTYPE.ClearWargingNode.title) { + + } + // showDialog(false); + }; - const proxyList = useMemo(() => { - const newData = getRandomNodes(nodeList); - if (open) { - if (isClear) return []; - if (type.title === NODEDIALOGTYPE.ClearFailNode.title) { - if (clearFailTimer) { - const clear = - isTimestampPlusTenMinutesBeforeNow(clearFailTimer); - if (clear) { - return newData - } else { - return []; - } - } else { - return newData; - } - } - if (type.title === NODEDIALOGTYPE.ClearWargingNode.title) { - if (clearWarningTimer) { - const clear = - isTimestampPlusTenMinutesBeforeNow(clearWarningTimer); - console.log(clear,'clear') - if (clear) { - return newData - } else { - return []; - } - } else { - return newData; - } - } + const proxyList = useMemo(() => { + const newData = getRandomNodes(nodeList); - return newData; - } - // 随机 2-9条 nodelist里面的数据 - return []; - }, [nodeList, open, isClear, clearFailTimer, clearWarningTimer, type]); + return newData; + }, [nodeList, open, isClear, type]); - useEffect(() => { - if (!open) { - setIsClear(false); - } - }, [open]); + useEffect(() => { + if (!open) { + setIsClear(false); + } + }, [open]); - return ( - -
- {proxyList.length > 0 ? ( - proxyList.map((item) => { - return ; - }) - ) : ( -
- {type.title === NODEDIALOGTYPE.ClearFailNode.title ? ( - - ) : ( - - )} + return ( + +
+ {proxyList.length > 0 ? ( + proxyList.map((item) => { + return ; + }) + ) : ( +
+ {type.title === NODEDIALOGTYPE.ClearFailNode.title ? ( + + ) : ( + + )} -
- {type.title === NODEDIALOGTYPE.ClearFailNode.title - ? "暂无掉线节点" - : "暂无恶意节点"} -
-
- )} +
+ {type.title === NODEDIALOGTYPE.ClearFailNode.title + ? "暂无掉线节点" + : "暂无恶意节点"}
- - ); +
+ )} +
+ + ); }; diff --git a/src/pages/anti-forensics-forwarding/components/world-geo.tsx b/src/pages/anti-forensics-forwarding/components/world-geo.tsx index 7877a68..3eb0745 100644 --- a/src/pages/anti-forensics-forwarding/components/world-geo.tsx +++ b/src/pages/anti-forensics-forwarding/components/world-geo.tsx @@ -702,7 +702,8 @@ export const WorldGeo = memo( show: true, // 是否显示 period: 4, // 特效动画时间 trailLength: 0.7, // 特效尾迹长度。取从 0 到 1 的值,数值越大尾迹越长 - symbol: planePathImg, // 特效图形标记 + color: pathColor, // 特效颜色 + // symbol: planePathImg, // 特效图形标记 symbolSize: [10, 20], }, // 线条样式 diff --git a/src/pages/decentralized-lastic-network/components/ClearNodeDialog/index.tsx b/src/pages/decentralized-lastic-network/components/ClearNodeDialog/index.tsx index a7c627a..262f5cc 100644 --- a/src/pages/decentralized-lastic-network/components/ClearNodeDialog/index.tsx +++ b/src/pages/decentralized-lastic-network/components/ClearNodeDialog/index.tsx @@ -3,7 +3,7 @@ import { FormInstance } from "antd"; import { FormDialog } from "@/components/FormDialog"; import { useDispatch, useSelector } from "react-redux"; -import { nodeList,getRandomNodes } from "@/store/datas"; +import { nodeList, getRandomNodes } from "@/store/datas"; import "./index.scss"; import { EllipsisTooltip } from "@/components/Encapsulation"; import NotFailNodeIcon from "@/assets/svg/common/not-fail-node.svg?react"; @@ -11,170 +11,127 @@ import NotWarningNodeIcon from "@/assets/svg/common/not-warning-node.svg?react"; import { NODEDIALOGTYPE } from "../../index"; import { cn, getUrl } from "@/lib/utils"; -import { - setClearFailTimer, - setClearWarningTimer, -} from "@/store/web3Slice"; import { AppDispatch, RootState } from "@/store"; import { isTimestampPlusTenMinutesBeforeNow } from "@/utils/tools"; export interface DialogConfig { - title: string; - desc: string; - successText: string; + title: string; + desc: string; + successText: string; } export const ProxyItem: React.FC<{ proxyInfo: any; clasName?: string }> = ( - props + props ) => { - const { name, code, exit = false } = props.proxyInfo; + const { name, code, exit = false } = props.proxyInfo; - return ( -
-
-
-
- -
- -
-
+ return ( +
+
+
+
+ +
+
- ); +
+
+ ); }; export const ClearNodeDialog = ({ - open, - setOpen, - successHandle, - dialogLoading, - form, - type, - canSubmit, + open, + setOpen, + successHandle, + dialogLoading, + form, + type, + canSubmit, }: { - open: boolean; - setOpen: (open: boolean) => void; - successHandle: () => void; - dialogLoading: boolean; - canSubmit: boolean; - form: FormInstance; - type: DialogConfig; + open: boolean; + setOpen: (open: boolean) => void; + successHandle: () => void; + dialogLoading: boolean; + canSubmit: boolean; + form: FormInstance; + type: DialogConfig; }) => { - const dispatch = useDispatch(); - const { clearWarningTimer, clearFailTimer } = useSelector( - (state: RootState) => state.web3Reducer - ); - const [isClear, setIsClear] = useState(false); - const showDialog = (open: boolean) => { - setOpen(open); - }; - const onSuccessHandle = () => { - successHandle(); - setIsClear(true); - if (type.title === NODEDIALOGTYPE.ClearFailNode.title) { - dispatch(setClearFailTimer(Date.now())); - } else if (type.title === NODEDIALOGTYPE.ClearWargingNode.title) { - dispatch(setClearWarningTimer(Date.now())); - } - // showDialog(false); - }; + const dispatch = useDispatch(); + const {} = useSelector((state: RootState) => state.web3Reducer); + const [isClear, setIsClear] = useState(false); + const showDialog = (open: boolean) => { + setOpen(open); + }; + const onSuccessHandle = () => { + successHandle(); + setIsClear(true); + if (type.title === NODEDIALOGTYPE.ClearFailNode.title) { + } else if (type.title === NODEDIALOGTYPE.ClearWargingNode.title) { + } + // showDialog(false); + }; - const proxyList = useMemo(() => { - const newData = getRandomNodes(nodeList); - if (open) { - if (isClear) return []; - if (type.title === NODEDIALOGTYPE.ClearFailNode.title) { - if (clearFailTimer) { - const clear = - isTimestampPlusTenMinutesBeforeNow(clearFailTimer); - if (clear) { - return newData - } else { - return []; - } - } else { - return newData; - } - } - if (type.title === NODEDIALOGTYPE.ClearWargingNode.title) { - if (clearWarningTimer) { - const clear = - isTimestampPlusTenMinutesBeforeNow(clearWarningTimer); - console.log(clear,'clear') - if (clear) { - return newData - } else { - return []; - } - } else { - return newData; - } - } + const proxyList = useMemo(() => { + // 随机 2-9条 nodelist里面的数据 + return []; + }, [nodeList, open, isClear, type]); - return newData; - } - // 随机 2-9条 nodelist里面的数据 - return []; - }, [nodeList, open, isClear, clearFailTimer, clearWarningTimer, type]); + useEffect(() => { + if (!open) { + setIsClear(false); + } + }, [open]); - useEffect(() => { - if (!open) { - setIsClear(false); - } - }, [open]); + return ( + +
+ {proxyList.length > 0 ? ( + proxyList.map((item) => { + return ; + }) + ) : ( +
+ {type.title === NODEDIALOGTYPE.ClearFailNode.title ? ( + + ) : ( + + )} - return ( - -
- {proxyList.length > 0 ? ( - proxyList.map((item) => { - return ; - }) - ) : ( -
- {type.title === NODEDIALOGTYPE.ClearFailNode.title ? ( - - ) : ( - - )} - -
- {type.title === NODEDIALOGTYPE.ClearFailNode.title - ? "暂无掉线节点" - : "暂无恶意节点"} -
-
- )} +
+ {type.title === NODEDIALOGTYPE.ClearFailNode.title + ? "暂无掉线节点" + : "暂无恶意节点"}
- - ); +
+ )} +
+ + ); }; diff --git a/src/pages/decentralized-lastic-network/components/FormAlertDialog/index.tsx b/src/pages/decentralized-lastic-network/components/FormAlertDialog/index.tsx index cc433ec..faa75ae 100644 --- a/src/pages/decentralized-lastic-network/components/FormAlertDialog/index.tsx +++ b/src/pages/decentralized-lastic-network/components/FormAlertDialog/index.tsx @@ -8,217 +8,237 @@ import { DIALOGTYPE } from "../../index"; import "./index.scss"; import { DefaultLink } from "./pathChoose"; import { Button } from "@/components/ui/button"; +import { Switch } from "@/components/ui/switch"; export interface DialogConfig { - title: string; - desc: string; - successText: string; + title: string; + desc: string; + successText: string; } const PledgeAmount = ({ - value, - onChange, + value, + onChange, }: { - value?: string; - onChange?: (data: string) => void; + value?: string; + onChange?: (data: string) => void; }) => { - return ( -
- { - onChange?.(e.target.value); - }} - /> - SOL -
- ); + return ( +
+ { + onChange?.(e.target.value); + }} + /> + SOL +
+ ); }; const IpPortInput = ({ - value, - onChange, + value, + onChange, }: { - value?: { port: string; ip: string }; - onChange?: (data: { port: string; ip: string }) => void; + value?: { port: string; ip: string }; + onChange?: (data: { port: string; ip: string }) => void; }) => { - const [ipAndPort, setIpAndPort] = useState<{ - port: string; - ip: string; - }>(value ? value : { port: "", ip: "" }); - const handleChagne = ({ - key, - val, - }: { - key: "port" | "ip"; - val: string; - }) => { - const newValue = value ? { ...value } : { port: "", ip: "" }; - newValue[key] = val; - onChange?.(newValue); - }; - useEffect(() => { - if (value) { - setIpAndPort(value); - } - }, [value]); - return ( -
- { - handleChagne?.({ key: "ip", val: e.target.value }); - }} - /> - { - handleChagne?.({ key: "port", val: e.target.value }); - }} - /> -
- ); + const [ipAndPort, setIpAndPort] = useState<{ + port: string; + ip: string; + }>(value ? value : { port: "", ip: "" }); + const handleChagne = ({ key, val }: { key: "port" | "ip"; val: string }) => { + const newValue = value ? { ...value } : { port: "", ip: "" }; + newValue[key] = val; + onChange?.(newValue); + }; + useEffect(() => { + if (value) { + setIpAndPort(value); + } + }, [value]); + return ( +
+ { + handleChagne?.({ key: "ip", val: e.target.value }); + }} + /> + { + handleChagne?.({ key: "port", val: e.target.value }); + }} + /> +
+ ); +}; + +const SwitchComponent = ({ + value, + onChange, +}: { + value?: boolean; + onChange?: (data: boolean) => void; +}) => { + const [checked, setChecked] = useState(value); + + return ( +
+ { + setChecked(e); + onChange?.(e); + }} + /> +
+ 是否为出口节点 +
+
+ ); }; const NodeForm = ({ form }: { form: FormInstance }) => { - return ( -
- {/* + return ( + + {/*
uid
*/} - - - - - - - - - - - - - - - - - ); + + + + + + + + + + + + + + + + + ); }; const NetworkForm = ({ form }: { form: FormInstance }) => { - return ( -
- - key)} - /> - - - key)} - /> - -
- ); + return ( +
+ + key)} + /> + + + key)} + /> + +
+ ); }; export const FormAlertDialog = ({ - open, - setOpen, - successHandle, - dialogLoading, - form, - type, - canSubmit, - handleSelectFile, + open, + setOpen, + successHandle, + dialogLoading, + form, + type, + canSubmit, + handleSelectFile, }: { - open: boolean; - setOpen: (open: boolean) => void; - successHandle: () => void; - dialogLoading: boolean; - canSubmit: boolean; - form: FormInstance; - type: DialogConfig; - handleSelectFile: () => void; + open: boolean; + setOpen: (open: boolean) => void; + successHandle: () => void; + dialogLoading: boolean; + canSubmit: boolean; + form: FormInstance; + type: DialogConfig; + handleSelectFile: () => void; }) => { - const showDialog = (open: boolean) => { - setOpen(open); - }; + const showDialog = (open: boolean) => { + setOpen(open); + }; - - return ( - - - {open && type.title === DIALOGTYPE.ADDNode.title ? ( - - ) : ( - - )} - - ); + return ( + + + {open && type.title === DIALOGTYPE.ADDNode.title ? ( + + ) : ( + + )} + + ); }; diff --git a/src/pages/decentralized-lastic-network/components/world-geo.tsx b/src/pages/decentralized-lastic-network/components/world-geo.tsx index 96f556f..fc08d4d 100644 --- a/src/pages/decentralized-lastic-network/components/world-geo.tsx +++ b/src/pages/decentralized-lastic-network/components/world-geo.tsx @@ -91,7 +91,6 @@ export const WorldGeo = memo(({ screenData }: { screenData: any }) => { const mainToData = useMemo(() => { // 使用新的数据结构 const proxiesList = screenData?.proxy_info?.proxies ?? [{data:[{country_code: 'AI', ingress_country_code: 'AE'}], isLine: true}]; - console.log(proxiesList,'proxiesList') // 初始化数据数组 - 不再包含 startCountry const data: any = []; @@ -418,7 +417,8 @@ export const WorldGeo = memo(({ screenData }: { screenData: any }) => { show: true, // 是否显示 period: 4, // 特效动画时间 trailLength: 0.7, // 特效尾迹长度。取从 0 到 1 的值,数值越大尾迹越长 - symbol: planePathImg, // 特效图形标记 + // symbol: planePathImg, // 特效图形标记 + color:"#0ea5e9", symbolSize: [10, 20], }, // 线条样式 diff --git a/src/pages/new-home/components/ClearNodeDialog/index.tsx b/src/pages/new-home/components/ClearNodeDialog/index.tsx index a7c627a..641814e 100644 --- a/src/pages/new-home/components/ClearNodeDialog/index.tsx +++ b/src/pages/new-home/components/ClearNodeDialog/index.tsx @@ -3,7 +3,7 @@ import { FormInstance } from "antd"; import { FormDialog } from "@/components/FormDialog"; import { useDispatch, useSelector } from "react-redux"; -import { nodeList,getRandomNodes } from "@/store/datas"; +import { nodeList, getRandomNodes } from "@/store/datas"; import "./index.scss"; import { EllipsisTooltip } from "@/components/Encapsulation"; import NotFailNodeIcon from "@/assets/svg/common/not-fail-node.svg?react"; @@ -11,170 +11,128 @@ import NotWarningNodeIcon from "@/assets/svg/common/not-warning-node.svg?react"; import { NODEDIALOGTYPE } from "../../index"; import { cn, getUrl } from "@/lib/utils"; -import { - setClearFailTimer, - setClearWarningTimer, -} from "@/store/web3Slice"; import { AppDispatch, RootState } from "@/store"; import { isTimestampPlusTenMinutesBeforeNow } from "@/utils/tools"; export interface DialogConfig { - title: string; - desc: string; - successText: string; + title: string; + desc: string; + successText: string; } export const ProxyItem: React.FC<{ proxyInfo: any; clasName?: string }> = ( - props + props ) => { - const { name, code, exit = false } = props.proxyInfo; + const { name, code, exit = false } = props.proxyInfo; - return ( -
-
-
-
- -
- -
-
+ return ( +
+
+
+
+ +
+
- ); +
+
+ ); }; export const ClearNodeDialog = ({ - open, - setOpen, - successHandle, - dialogLoading, - form, - type, - canSubmit, + open, + setOpen, + successHandle, + dialogLoading, + form, + type, + canSubmit, }: { - open: boolean; - setOpen: (open: boolean) => void; - successHandle: () => void; - dialogLoading: boolean; - canSubmit: boolean; - form: FormInstance; - type: DialogConfig; + open: boolean; + setOpen: (open: boolean) => void; + successHandle: () => void; + dialogLoading: boolean; + canSubmit: boolean; + form: FormInstance; + type: DialogConfig; }) => { - const dispatch = useDispatch(); - const { clearWarningTimer, clearFailTimer } = useSelector( - (state: RootState) => state.web3Reducer - ); - const [isClear, setIsClear] = useState(false); - const showDialog = (open: boolean) => { - setOpen(open); - }; - const onSuccessHandle = () => { - successHandle(); - setIsClear(true); - if (type.title === NODEDIALOGTYPE.ClearFailNode.title) { - dispatch(setClearFailTimer(Date.now())); - } else if (type.title === NODEDIALOGTYPE.ClearWargingNode.title) { - dispatch(setClearWarningTimer(Date.now())); - } - // showDialog(false); - }; + const dispatch = useDispatch(); + const {} = useSelector((state: RootState) => state.web3Reducer); + const [isClear, setIsClear] = useState(false); + const showDialog = (open: boolean) => { + setOpen(open); + }; + const onSuccessHandle = () => { + successHandle(); + setIsClear(true); + if (type.title === NODEDIALOGTYPE.ClearFailNode.title) { + } else if (type.title === NODEDIALOGTYPE.ClearWargingNode.title) { + } + // showDialog(false); + }; - const proxyList = useMemo(() => { - const newData = getRandomNodes(nodeList); - if (open) { - if (isClear) return []; - if (type.title === NODEDIALOGTYPE.ClearFailNode.title) { - if (clearFailTimer) { - const clear = - isTimestampPlusTenMinutesBeforeNow(clearFailTimer); - if (clear) { - return newData - } else { - return []; - } - } else { - return newData; - } - } - if (type.title === NODEDIALOGTYPE.ClearWargingNode.title) { - if (clearWarningTimer) { - const clear = - isTimestampPlusTenMinutesBeforeNow(clearWarningTimer); - console.log(clear,'clear') - if (clear) { - return newData - } else { - return []; - } - } else { - return newData; - } - } + const proxyList = useMemo(() => { + const newData = getRandomNodes(nodeList); - return newData; - } - // 随机 2-9条 nodelist里面的数据 - return []; - }, [nodeList, open, isClear, clearFailTimer, clearWarningTimer, type]); + return []; + }, [nodeList, open, isClear, type]); - useEffect(() => { - if (!open) { - setIsClear(false); - } - }, [open]); + useEffect(() => { + if (!open) { + setIsClear(false); + } + }, [open]); - return ( - -
- {proxyList.length > 0 ? ( - proxyList.map((item) => { - return ; - }) - ) : ( -
- {type.title === NODEDIALOGTYPE.ClearFailNode.title ? ( - - ) : ( - - )} + return ( + +
+ {proxyList.length > 0 ? ( + proxyList.map((item) => { + return ; + }) + ) : ( +
+ {type.title === NODEDIALOGTYPE.ClearFailNode.title ? ( + + ) : ( + + )} -
- {type.title === NODEDIALOGTYPE.ClearFailNode.title - ? "暂无掉线节点" - : "暂无恶意节点"} -
-
- )} +
+ {type.title === NODEDIALOGTYPE.ClearFailNode.title + ? "暂无掉线节点" + : "暂无恶意节点"}
- - ); +
+ )} +
+ + ); }; diff --git a/src/pages/new-home/components/world-geo.tsx b/src/pages/new-home/components/world-geo.tsx index 13c8275..39721cb 100644 --- a/src/pages/new-home/components/world-geo.tsx +++ b/src/pages/new-home/components/world-geo.tsx @@ -59,7 +59,7 @@ export const WorldGeo = memo( const labelsRef = useRef([]); const mainToData = useMemo(() => { const newList = [ - ...dataInfo.passAuthentication.data, + dataInfo.passAuthentication, ...dataInfo.trafficObfuscation, ...dataInfo.nestedEncryption, ...dataInfo.dynamicRouteGeneration, @@ -239,7 +239,8 @@ export const WorldGeo = memo( const positionCustomTooltip2 = () => { if (!customTooltip2Ref.current || !proxyGeoRef.current) return; // 找到US点 - const coords = geoCoordMap[dataInfo.trafficObfuscation?.[0]?.code ?? "ZA"]; + const coords = + geoCoordMap[dataInfo.trafficObfuscation?.[0]?.code ?? "ZA"]; if (!coords) return; try { // 将地理坐标转换为屏幕坐标 @@ -261,27 +262,7 @@ export const WorldGeo = memo( console.error("Error positioning tooltip:", error); } }; - // 主线每个节点tip竖线的经纬度,修改tip 竖线的高度也可以用这个 - const mianLineData = (data: typeof mainToData) => { - return ( - data - .map((item: any) => { - const countryCode = item.country_code.toUpperCase(); - if (!(["RU", "FR"].includes(countryCode) && item.type === "start")) - return null; - const coords = geoCoordMap[countryCode] as - | [number, number] - | undefined; - if (!coords) return null; - return { - name: countryCodeMap[countryCode], - coords: [coords, [coords[0], coords[1] + 4]], - value: countryCode, - }; - }) - .filter((v: any) => !!v) ?? [] - ); - }; + const getLineItem = ( preCode: string, nextCode: string @@ -746,7 +727,8 @@ export const WorldGeo = memo( show: true, // 是否显示 period: 4, // 特效动画时间 trailLength: 0.7, // 特效尾迹长度。取从 0 到 1 的值,数值越大尾迹越长 - symbol: planePathImg, // 特效图形标记 + color: lastExitColor, // 特效颜色 + // symbol: planePathImg, // 特效图形标记 symbolSize: [10, 20], }, // 线条样式 @@ -772,7 +754,6 @@ export const WorldGeo = memo( const lastExit = item[1]?.[item[1].length - 1]?.[1] ?? null; const lastExitColor = (item[1]?.[item[1].length - 1] as any)?.color || "#0ea5e9"; - // 添加虚线 series.push({ name: item[0], @@ -807,7 +788,7 @@ export const WorldGeo = memo( }); return true; }; - + // 创建A点和B点,并添加飞线和标签 const createSpecialPoints = (series: echarts.SeriesOption[]) => { // 定义点A和点B的坐标 diff --git a/src/routes/index.tsx b/src/routes/index.tsx index 07871a5..3838f52 100644 --- a/src/routes/index.tsx +++ b/src/routes/index.tsx @@ -1,5 +1,5 @@ import { createBrowserRouter, Navigate } from 'react-router-dom' -// import HomePage from '@/pages/home' +import HomePage from '@/pages/home' import NewHomePage from '@/pages/new-home' import DecentralizedElasticNetworkPage from '@/pages/decentralized-lastic-network' import AntiForensicsForwardingPage from '@/pages/anti-forensics-forwarding' @@ -35,7 +35,7 @@ export const router = createBrowserRouter([ // }, { path: '/proxies', - element: , + element: , }, ], }, diff --git a/src/store/web3Slice.ts b/src/store/web3Slice.ts index 0506638..8c4dcc8 100644 --- a/src/store/web3Slice.ts +++ b/src/store/web3Slice.ts @@ -23,8 +23,6 @@ interface Iweb3Slice { newHomeProxies: any[]; path_list: any; proxy_info: any; - clearWarningTimer: number | null; - clearFailTimer: number | null; isLine: boolean; } @@ -104,8 +102,6 @@ const initialState: Iweb3Slice = { change_at: 0, proxies: [], }, - clearWarningTimer: null, - clearFailTimer: null, newHomeProxies: [ { authenticationPoint: [ @@ -187,7 +183,6 @@ export const appSlice = createSlice({ // 进一步优化的代码 if (state.proxy_info.proxies.length === 0) return; - // 标记所有代理为在线 - 这个操作仍然需要 state.proxy_info.proxies = state.proxy_info.proxies.map((item: any) => { item.isLine = true; @@ -244,12 +239,6 @@ export const appSlice = createSlice({ setIsLine: (state, action) => { state.isLine = action.payload; }, - setClearWarningTimer: (state, action) => { - state.clearWarningTimer = action.payload; - }, - setClearFailTimer: (state, action) => { - state.clearFailTimer = action.payload; - }, setWeb3List: (state, action) => { state.web3List = action.payload; }, @@ -281,8 +270,6 @@ export const { setProxyInfoProxies, randomUpdateWeb3List, randomUpdateWeb3List2, - setClearWarningTimer, - setClearFailTimer, reset, setIsLine, setProxiesList1, diff --git a/src/utils/eventBus.ts b/src/utils/eventBus.ts new file mode 100644 index 0000000..b13c51f --- /dev/null +++ b/src/utils/eventBus.ts @@ -0,0 +1,23 @@ +import mitt from "mitt"; + +const eventBus = mitt(); + +// 事件类型 +export const eventTypes = { + // 节点上线 + NODE_UP: "node_up", + // 节点下线 + NODE_DOWN: "node_down", + // 检测到恶意节点 + MALICIOUS_NODE: "malicious_node", + // 节点预配置完成 + NODE_INIT_COMPLATE: "node_init_complate", + // 节点清除 + NODE_REMOVE: "node_remove", + // 添加节点 + NODE_ADD: "node_add", + // 节点预配置 + NODE_INIT: "node_init", +}; + +export default eventBus; diff --git a/src/utils/webSocketClient.ts b/src/utils/webSocketClient.ts index 43dcff9..6f9e01f 100644 --- a/src/utils/webSocketClient.ts +++ b/src/utils/webSocketClient.ts @@ -27,7 +27,7 @@ export class WebSocketClient { } // 发送消息 - async sendMessage(message: string): Promise { + async sendMessage(message: any): Promise { if (!this.ws) { console.error('WebSocket is not connected') return