feat: 新增websoket事件对应的events

This commit is contained in:
liyuanhu 2025-04-21 14:40:24 +08:00
parent d220b7b0f5
commit 1693316766
12 changed files with 180 additions and 116 deletions

3
.env
View File

@ -3,5 +3,6 @@ COSMOS_ENDPOINT="http://10.66.66.234:26657"
NODE_SECRET="aHVnZSBjb21wYW55IHBob25lIHdlc3QgcGxhY2Ugc2VtaW5hciBtaXJhY2xlIGxlbmQgbWFuZGF0ZSB0aGVuIGFkanVzdCBxdWl0IG1lYXQgY2hlYXAgbm9vZGxlIGNvdXBsZSBkZWZpbmUgbXVzY2xlIHB1bHNlIHNpc3RlciBwaWVjZSBkZXZpY2UgcHJpdmF0ZSBob29k" NODE_SECRET="aHVnZSBjb21wYW55IHBob25lIHdlc3QgcGxhY2Ugc2VtaW5hciBtaXJhY2xlIGxlbmQgbWFuZGF0ZSB0aGVuIGFkanVzdCBxdWl0IG1lYXQgY2hlYXAgbm9vZGxlIGNvdXBsZSBkZWZpbmUgbXVzY2xlIHB1bHNlIHNpc3RlciBwaWVjZSBkZXZpY2UgcHJpdmF0ZSBob29k"
IS_DEBUG="true" IS_DEBUG="true"
ACCOUNT_NAME="de1" ACCOUNT_NAME="de1"
VIET_EVENTS_WS_URL="ws://10.66.66.234:8080/events"
VITE_BASE_URL="http://10.66.66.234:6060" VITE_BASE_URL="http://10.66.66.234:6060"
VITE_BLOCK_URL="http://localhost:3001" VITE_BLOCK_URL="http://10.66.66.234:1317"

View File

@ -12,6 +12,7 @@ use paw_common::preclude::{CoreConfig, CoreResponse};
#[derive(Debug, Clone, Deserialize, Serialize, specta::Type)] #[derive(Debug, Clone, Deserialize, Serialize, specta::Type)]
pub struct ProxyNodeInfo { pub struct ProxyNodeInfo {
pub name: String, pub name: String,
pub ip: String,
pub country_code: String, pub country_code: String,
pub country_name: String, pub country_name: String,
pub country_name_zh: String, pub country_name_zh: String,
@ -76,7 +77,7 @@ pub async fn get_nodes(config: CoreConfig) -> Result<Vec<ProxyNodeInfo>> {
debug!("Successfully got nodes: {:?}", result.data); debug!("Successfully got nodes: {:?}", result.data);
Ok(result.data) Ok(result.data)
} else { } else {
error!("Failed to get nodes: {}", response.text().await?); debug!("Failed to get nodes: {}", response.text().await?);
bail!("Failed to get nodes") bail!("Failed to get nodes")
} }
} }

View File

@ -12,7 +12,7 @@ import {
setMaliciousNodeList, setMaliciousNodeList,
setNodeDownList, setNodeDownList,
} from "@/store/web3Slice"; } from "@/store/web3Slice";
import type { AppDispatch, RootState } from "@/store"; import type { AppDispatch } from "@/store";
import eventBus, { eventTypes } from "@/utils/eventBus"; import eventBus, { eventTypes } from "@/utils/eventBus";
import { WebSocketClient } from "@/utils/webSocketClient"; import { WebSocketClient } from "@/utils/webSocketClient";
@ -20,6 +20,8 @@ import { WebSocketClient } from "@/utils/webSocketClient";
import Titlebar from "@/components/Titlebar"; import Titlebar from "@/components/Titlebar";
import Layout from "@/layout"; import Layout from "@/layout";
import Tray from "@/components/Tray"; import Tray from "@/components/Tray";
import { getRandomCountryKey } from "./data";
import dayjs from "dayjs";
function App() { function App() {
// 执行启动自检 // 执行启动自检
@ -37,79 +39,99 @@ function App() {
// const { } = useSelector( // const { } = useSelector(
// (state: RootState) => state.web3Reducer // (state: RootState) => state.web3Reducer
// ); // );
const webSocketClient = useRef<WebSocketClient | null>(); let eventsWs: WebSocketClient | null = null;
const openWsTraffic = async () => { const openWsTraffic = async () => {
if (webSocketClient.current) return; if (eventsWs) return;
const { api_port } = await loadCoreConfig(); eventsWs = new WebSocketClient("ws://10.66.66.234:8080/events", {});
// todo! 后面会把二级制文件启动的参数作为配置项,这里暂时写死 console.log(eventsWs, "openWsTraffic Start");
webSocketClient.current = new WebSocketClient(
`ws://127.0.0.1:${api_port}/traffic`,
{
headers: {
Authorization: "Bearer secret",
},
}
);
// 执行 WebSocket 操作 // 执行 WebSocket 操作
await webSocketClient.current.connect(); await eventsWs?.connect();
webSocketClient.current.addListener((msg: any) => { await eventsWs?.addListener((msg: any) => {
if (msg.code === 0) { try {
switch (msg.event) { const msgData = msg ? JSON.parse(msg.data) : {};
case eventTypes.NODE_UP: if (msgData.code === 0) {
console.log("节点上线"); console.log(msgData, "msgDatamsgData");
break; switch (msgData.event) {
case eventTypes.NODE_DOWN: case eventTypes.NODE_UP:
// 添加下线节点到store 里面 console.log("节点上线");
dispatch(setNodeDownList(msg.data.name)); break;
console.log("节点下线"); case eventTypes.NODE_DOWN:
break; // 添加下线节点到store 里面
case eventTypes.MALICIOUS_NODE: if (msgData.data.name) {
// 添加恶意节点到store 里面 // 获取一个随机的国家code
dispatch(setMaliciousNodeList(msg.data.name)); const countryCode = getRandomCountryKey();
console.log("检测到恶意节点"); dispatch(
break; setNodeDownList({
case eventTypes.NODE_INIT_COMPLATE: name: msgData.data.name,
console.log("节点预配置完成"); code: countryCode,
break; })
case eventTypes.NODE_REMOVE: );
console.log("节点清除"); }
break; console.log("节点下线");
case eventTypes.NODE_ADD: break;
console.log("添加节点"); case eventTypes.MALICIOUS_NODE:
break; // 添加恶意节点到store 里面
case eventTypes.NODE_INIT: if (msgData.data.name) {
console.log("节点预配置"); // 获取一个随机的国家code
break; const countryCode = getRandomCountryKey();
default: dispatch(
break; setMaliciousNodeList({
name: msgData.data.name,
code: countryCode,
})
);
}
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;
}
} }
} catch (error) {
console.log(error, "error");
} }
}); });
console.log(eventsWs, "openWsTraffic End");
}; };
const createdSoketEventBus = async () => { const createdSoketEventBus = async () => {
eventBus.on(eventTypes.NODE_INIT_COMPLATE, (data: any) => { eventBus.on(eventTypes.NODE_INIT_COMPLATE, (data: any) => {
console.log("节点预配置完成", data); console.log("节点预配置完成", data);
webSocketClient.current?.sendMessage(data); eventsWs?.sendMessage(data);
}); });
eventBus.on(eventTypes.NODE_REMOVE, (data: any) => { eventBus.on(eventTypes.NODE_REMOVE, (data: any) => {
console.log("节点清除"); console.log("节点清除");
webSocketClient.current?.sendMessage({ const timestamp = dayjs().unix();
const params = {
code: 0, code: 0,
event: eventTypes.NODE_REMOVE, event: eventTypes.NODE_REMOVE,
data: { data: {
name: data, name: data,
}, },
}); timestamp,
};
console.log(JSON.stringify(params), "节点清除 params");
eventsWs?.sendMessage(JSON.stringify(params));
}); });
}; };
const closeWsTraffic = async () => { const closeWsTraffic = async () => {
if (webSocketClient.current) { if (eventsWs) {
await webSocketClient.current.disconnect(); await eventsWs.disconnect();
webSocketClient.current = null; eventsWs = null;
} }
}; };
@ -124,11 +146,13 @@ function App() {
}; };
useEffect(() => { useEffect(() => {
// initWebsocketsAndEventBus(); setTimeout(() => {
// return () => { initWebsocketsAndEventBus();
// closeWsTraffic(); }, 1000);
// removeSoketEventBus(); return () => {
// }; closeWsTraffic();
removeSoketEventBus();
};
}, []); }, []);
return ( return (

View File

@ -209,7 +209,7 @@ export type CoreConfig = { socks_port: number; socks_user: string; socks_pass: s
/** /**
* *
*/ */
export type ProxyNodeInfo = { name: string; country_code: string; country_name: string; country_name_zh: string; city_name: string; city_name_zh: string; delay: number; download: number; upload: number; survive_score: number; exit: boolean; use: boolean } export type ProxyNodeInfo = { name: string; ip: string; country_code: string; country_name: string; country_name_zh: string; city_name: string; city_name_zh: string; delay: number; download: number; upload: number; survive_score: number; exit: boolean; use: boolean }
/** tauri-specta globals **/ /** tauri-specta globals **/

View File

@ -500,6 +500,18 @@ export const countryNameMap = {
Curaçao: '库拉索', Curaçao: '库拉索',
} }
// 获取一个随机的国家key
export function getRandomCountryKey() {
const keys = Object.keys(countryCodeMap)
return keys[Math.floor(Math.random() * keys.length)]
}
// 获取一个随机的国家name
export function getRandomCountryName() {
const keys = Object.keys(countryCodeMap)
return countryCodeMap[keys[Math.floor(Math.random() * keys.length)]]
}
// 国家代码映射 // 国家代码映射
export const countryCodeMap: { [key: string]: string } = { export const countryCodeMap: { [key: string]: string } = {
AD: '安道尔', AD: '安道尔',

View File

@ -201,7 +201,6 @@ export function useStartupCheck() {
// 只有当核心正在运行时才更新节点 // 只有当核心正在运行时才更新节点
if (isCoreRunning) { if (isCoreRunning) {
if (nodesResult.status === "ok") { if (nodesResult.status === "ok") {
console.log("触发了???");
const proxies:any[] = []; const proxies:any[] = [];
nodesResult.data.forEach((node,index) => { nodesResult.data.forEach((node,index) => {
const { country_code } = node const { country_code } = node
@ -210,8 +209,8 @@ export function useStartupCheck() {
} }
proxies.push({ country_code: country_code,ingress_country_code: nodesResult.data[index + 1].country_code }) proxies.push({ country_code: country_code,ingress_country_code: nodesResult.data[index + 1].country_code })
}) })
console.log(proxies,'proxiesproxiesproxies') // console.log(proxies,'proxiesproxiesproxies')
// dispatch(setProxiesList1()) dispatch(setProxiesList1(proxies))
dispatch(setNodes(nodesResult.data)); dispatch(setNodes(nodesResult.data));
} else { } else {
dispatch(setNodesError("Failed to fetch nodes")); dispatch(setNodesError("Failed to fetch nodes"));

View File

@ -3,17 +3,17 @@ import { FormInstance } from "antd";
import { FormDialog } from "@/components/FormDialog"; import { FormDialog } from "@/components/FormDialog";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { nodeList, getRandomNodes } from "@/store/datas";
import "./index.scss"; import "./index.scss";
import { EllipsisTooltip } from "@/components/Encapsulation"; import { EllipsisTooltip } from "@/components/Encapsulation";
import NotFailNodeIcon from "@/assets/svg/common/not-fail-node.svg?react"; import NotFailNodeIcon from "@/assets/svg/common/not-fail-node.svg?react";
import NotWarningNodeIcon from "@/assets/svg/common/not-warning-node.svg?react"; import NotWarningNodeIcon from "@/assets/svg/common/not-warning-node.svg?react";
import { NODEDIALOGTYPE } from "../../index"; import { NODEDIALOGTYPE } from "../../index";
import { cn, getUrl } from "@/lib/utils"; import { cn, getUrl } from "@/lib/utils";
import eventBus, { eventTypes } from "@/utils/eventBus";
import { } from "@/store/web3Slice";
import { AppDispatch, RootState } from "@/store"; import { AppDispatch, RootState } from "@/store";
import { isTimestampPlusTenMinutesBeforeNow } from "@/utils/tools"; import { removeMaliciousNodeList, removeNodeDownList } from "@/store/web3Slice";
import { countryCodeMap } from "@/data";
export interface DialogConfig { export interface DialogConfig {
title: string; title: string;
@ -24,8 +24,7 @@ export interface DialogConfig {
export const ProxyItem: React.FC<{ proxyInfo: any; clasName?: string }> = ( export const ProxyItem: React.FC<{ proxyInfo: any; clasName?: string }> = (
props props
) => { ) => {
const { name, code, exit = false } = props.proxyInfo; const { code, exit = false } = props.proxyInfo;
return ( return (
<div <div
className={cn( className={cn(
@ -44,7 +43,7 @@ export const ProxyItem: React.FC<{ proxyInfo: any; clasName?: string }> = (
</div> </div>
<EllipsisTooltip <EllipsisTooltip
className="text-lg flex-1 font-semibold" className="text-lg flex-1 font-semibold"
text={name} text={countryCodeMap[code]}
/> />
</div> </div>
</div> </div>
@ -70,7 +69,7 @@ export const ClearNodeDialog = ({
type: DialogConfig; type: DialogConfig;
}) => { }) => {
const dispatch = useDispatch<AppDispatch>(); const dispatch = useDispatch<AppDispatch>();
const { } = useSelector( const { maliciousNodeList, nodeDownList } = useSelector(
(state: RootState) => state.web3Reducer (state: RootState) => state.web3Reducer
); );
const [isClear, setIsClear] = useState(false); const [isClear, setIsClear] = useState(false);
@ -81,18 +80,26 @@ export const ClearNodeDialog = ({
successHandle(); successHandle();
setIsClear(true); setIsClear(true);
if (type.title === NODEDIALOGTYPE.ClearFailNode.title) { if (type.title === NODEDIALOGTYPE.ClearFailNode.title) {
nodeDownList.forEach((item) => {
dispatch(removeNodeDownList(item.name));
eventBus.emit(eventTypes.NODE_REMOVE, item.name);
});
} else if (type.title === NODEDIALOGTYPE.ClearWargingNode.title) { } else if (type.title === NODEDIALOGTYPE.ClearWargingNode.title) {
maliciousNodeList.forEach((item) => {
dispatch(removeMaliciousNodeList(item.name));
eventBus.emit(eventTypes.NODE_REMOVE, item.name);
});
} }
// showDialog(false); // showDialog(false);
}; };
const proxyList = useMemo(() => { const proxyList = useMemo(() => {
const newData = getRandomNodes(nodeList); if (type.title === NODEDIALOGTYPE.ClearFailNode.title) {
return nodeDownList;
return newData; } else {
}, [nodeList, open, isClear, type]); return maliciousNodeList;
}
}, [nodeDownList, maliciousNodeList, type.title]);
useEffect(() => { useEffect(() => {
if (!open) { if (!open) {
@ -119,9 +126,11 @@ export const ClearNodeDialog = ({
> >
<div className="flex flex-wrap gap-3"> <div className="flex flex-wrap gap-3">
{proxyList.length > 0 ? ( {proxyList.length > 0 ? (
proxyList.map((item) => { proxyList
return <ProxyItem proxyInfo={item} key={item.name} />; .filter((item: any) => item?.name)
}) .map((item: any) => {
return <ProxyItem proxyInfo={item} key={item?.name} />;
})
) : ( ) : (
<div className="w-full h-[382px] flex flex-col items-center justify-center"> <div className="w-full h-[382px] flex flex-col items-center justify-center">
{type.title === NODEDIALOGTYPE.ClearFailNode.title ? ( {type.title === NODEDIALOGTYPE.ClearFailNode.title ? (

View File

@ -3,7 +3,6 @@ import { FormInstance } from "antd";
import { FormDialog } from "@/components/FormDialog"; import { FormDialog } from "@/components/FormDialog";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { nodeList, getRandomNodes } from "@/store/datas";
import "./index.scss"; import "./index.scss";
import { EllipsisTooltip } from "@/components/Encapsulation"; import { EllipsisTooltip } from "@/components/Encapsulation";
import NotFailNodeIcon from "@/assets/svg/common/not-fail-node.svg?react"; import NotFailNodeIcon from "@/assets/svg/common/not-fail-node.svg?react";
@ -13,8 +12,8 @@ import { cn, getUrl } from "@/lib/utils";
import eventBus, { eventTypes } from "@/utils/eventBus"; import eventBus, { eventTypes } from "@/utils/eventBus";
import { AppDispatch, RootState } from "@/store"; import { AppDispatch, RootState } from "@/store";
import {removeMaliciousNodeList,removeNodeDownList} from '@/store/web3Slice' import { removeMaliciousNodeList, removeNodeDownList } from "@/store/web3Slice";
import { isTimestampPlusTenMinutesBeforeNow } from "@/utils/tools"; import { countryCodeMap } from "@/data";
export interface DialogConfig { export interface DialogConfig {
title: string; title: string;
@ -25,8 +24,7 @@ export interface DialogConfig {
export const ProxyItem: React.FC<{ proxyInfo: any; clasName?: string }> = ( export const ProxyItem: React.FC<{ proxyInfo: any; clasName?: string }> = (
props props
) => { ) => {
const { name, code, exit = false } = props.proxyInfo; const { code, exit = false } = props.proxyInfo;
return ( return (
<div <div
className={cn( className={cn(
@ -45,7 +43,7 @@ export const ProxyItem: React.FC<{ proxyInfo: any; clasName?: string }> = (
</div> </div>
<EllipsisTooltip <EllipsisTooltip
className="text-lg flex-1 font-semibold" className="text-lg flex-1 font-semibold"
text={name} text={countryCodeMap[code]}
/> />
</div> </div>
</div> </div>
@ -82,15 +80,15 @@ export const ClearNodeDialog = ({
successHandle(); successHandle();
setIsClear(true); setIsClear(true);
if (type.title === NODEDIALOGTYPE.ClearFailNode.title) { if (type.title === NODEDIALOGTYPE.ClearFailNode.title) {
nodeDownList.forEach((item)=>{ nodeDownList.forEach((item) => {
dispatch(removeNodeDownList(item.name)); dispatch(removeNodeDownList(item));
eventBus.emit(eventTypes.NODE_REMOVE, item.name); eventBus.emit(eventTypes.NODE_REMOVE, item.name);
}) });
} else if (type.title === NODEDIALOGTYPE.ClearWargingNode.title) { } else if (type.title === NODEDIALOGTYPE.ClearWargingNode.title) {
maliciousNodeList.forEach((item)=>{ maliciousNodeList.forEach((item) => {
dispatch(removeMaliciousNodeList(item.name)); dispatch(removeMaliciousNodeList(item));
eventBus.emit(eventTypes.NODE_REMOVE, item.name); eventBus.emit(eventTypes.NODE_REMOVE, item.name);
}) });
} }
// showDialog(false); // showDialog(false);
}; };
@ -127,10 +125,12 @@ export const ClearNodeDialog = ({
} }
> >
<div className="flex flex-wrap gap-3"> <div className="flex flex-wrap gap-3">
{proxyList?.length > 0 ? ( {proxyList.length > 0 ? (
proxyList.map((item) => { proxyList
return <ProxyItem proxyInfo={item} key={item.name} />; .filter((item: any) => item?.name)
}) .map((item: any) => {
return <ProxyItem proxyInfo={item} key={item?.name} />;
})
) : ( ) : (
<div className="w-full h-[382px] flex flex-col items-center justify-center"> <div className="w-full h-[382px] flex flex-col items-center justify-center">
{type.title === NODEDIALOGTYPE.ClearFailNode.title ? ( {type.title === NODEDIALOGTYPE.ClearFailNode.title ? (

View File

@ -3,16 +3,17 @@ import { FormInstance } from "antd";
import { FormDialog } from "@/components/FormDialog"; import { FormDialog } from "@/components/FormDialog";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { nodeList, getRandomNodes } from "@/store/datas";
import "./index.scss"; import "./index.scss";
import { EllipsisTooltip } from "@/components/Encapsulation"; import { EllipsisTooltip } from "@/components/Encapsulation";
import NotFailNodeIcon from "@/assets/svg/common/not-fail-node.svg?react"; import NotFailNodeIcon from "@/assets/svg/common/not-fail-node.svg?react";
import NotWarningNodeIcon from "@/assets/svg/common/not-warning-node.svg?react"; import NotWarningNodeIcon from "@/assets/svg/common/not-warning-node.svg?react";
import { NODEDIALOGTYPE } from "../../index"; import { NODEDIALOGTYPE } from "../../index";
import { cn, getUrl } from "@/lib/utils"; import { cn, getUrl } from "@/lib/utils";
import eventBus, { eventTypes } from "@/utils/eventBus";
import { AppDispatch, RootState } from "@/store"; import { AppDispatch, RootState } from "@/store";
import { isTimestampPlusTenMinutesBeforeNow } from "@/utils/tools"; import { removeMaliciousNodeList, removeNodeDownList } from "@/store/web3Slice";
import { countryCodeMap } from "@/data";
export interface DialogConfig { export interface DialogConfig {
title: string; title: string;
@ -23,8 +24,7 @@ export interface DialogConfig {
export const ProxyItem: React.FC<{ proxyInfo: any; clasName?: string }> = ( export const ProxyItem: React.FC<{ proxyInfo: any; clasName?: string }> = (
props props
) => { ) => {
const { name, code, exit = false } = props.proxyInfo; const { code, exit = false } = props.proxyInfo;
return ( return (
<div <div
className={cn( className={cn(
@ -43,7 +43,7 @@ export const ProxyItem: React.FC<{ proxyInfo: any; clasName?: string }> = (
</div> </div>
<EllipsisTooltip <EllipsisTooltip
className="text-lg flex-1 font-semibold" className="text-lg flex-1 font-semibold"
text={name} text={countryCodeMap[code]}
/> />
</div> </div>
</div> </div>
@ -69,7 +69,9 @@ export const ClearNodeDialog = ({
type: DialogConfig; type: DialogConfig;
}) => { }) => {
const dispatch = useDispatch<AppDispatch>(); const dispatch = useDispatch<AppDispatch>();
const {} = useSelector((state: RootState) => state.web3Reducer); const { maliciousNodeList, nodeDownList } = useSelector(
(state: RootState) => state.web3Reducer
);
const [isClear, setIsClear] = useState(false); const [isClear, setIsClear] = useState(false);
const showDialog = (open: boolean) => { const showDialog = (open: boolean) => {
setOpen(open); setOpen(open);
@ -78,16 +80,26 @@ export const ClearNodeDialog = ({
successHandle(); successHandle();
setIsClear(true); setIsClear(true);
if (type.title === NODEDIALOGTYPE.ClearFailNode.title) { if (type.title === NODEDIALOGTYPE.ClearFailNode.title) {
nodeDownList.forEach((item) => {
dispatch(removeNodeDownList(item.name));
eventBus.emit(eventTypes.NODE_REMOVE, item.name);
});
} else if (type.title === NODEDIALOGTYPE.ClearWargingNode.title) { } else if (type.title === NODEDIALOGTYPE.ClearWargingNode.title) {
maliciousNodeList.forEach((item) => {
dispatch(removeMaliciousNodeList(item.name));
eventBus.emit(eventTypes.NODE_REMOVE, item.name);
});
} }
// showDialog(false); // showDialog(false);
}; };
const proxyList = useMemo(() => { const proxyList = useMemo(() => {
const newData = getRandomNodes(nodeList); if (type.title === NODEDIALOGTYPE.ClearFailNode.title) {
return nodeDownList;
return []; } else {
}, [nodeList, open, isClear, type]); return maliciousNodeList;
}
}, [nodeDownList, maliciousNodeList, type.title]);
useEffect(() => { useEffect(() => {
if (!open) { if (!open) {
@ -114,9 +126,11 @@ export const ClearNodeDialog = ({
> >
<div className="flex flex-wrap gap-3"> <div className="flex flex-wrap gap-3">
{proxyList.length > 0 ? ( {proxyList.length > 0 ? (
proxyList.map((item) => { proxyList
return <ProxyItem proxyInfo={item} key={item.name} />; .filter((item: any) => item?.name)
}) .map((item: any) => {
return <ProxyItem proxyInfo={item} key={item?.name} />;
})
) : ( ) : (
<div className="w-full h-[382px] flex flex-col items-center justify-center"> <div className="w-full h-[382px] flex flex-col items-center justify-center">
{type.title === NODEDIALOGTYPE.ClearFailNode.title ? ( {type.title === NODEDIALOGTYPE.ClearFailNode.title ? (

View File

@ -290,14 +290,14 @@ const NewHome = () => {
}; };
useEffect(() => { useEffect(() => {
blockChainApi.getLatestBlock().then((res) => { blockChainApi.getLatestBlock().then((res) => {
console.log("res", res); console.log("getLatestBlock res:", res);
}); });
initData(); initData();
}, []); }, []);
useEffect(() => { // useEffect(() => {
console.log(dataInfo, "awaidataInfodataInfotawait"); // console.log(dataInfo, "awaidataInfodataInfotawait");
}, [dataInfo]); // }, [dataInfo]);
return ( return (
<div className="decentralized w-full h-full flex flex-col relative"> <div className="decentralized w-full h-full flex flex-col relative">

View File

@ -159,18 +159,18 @@ export const appSlice = createSlice({
reducers: { reducers: {
removeMaliciousNodeList: (state, action) => { removeMaliciousNodeList: (state, action) => {
state.maliciousNodeList = state.maliciousNodeList.filter( state.maliciousNodeList = state.maliciousNodeList.filter(
(item) => item !== action.payload (item) => item.name !== action.payload.name
); );
}, },
removeNodeDownList: (state, action) => { removeNodeDownList: (state, action) => {
state.nodeDownList = state.nodeDownList.filter( state.nodeDownList = state.nodeDownList.filter(
(item) => item !== action.payload (item) => item.name !== action.payload.name
); );
}, },
setMaliciousNodeList: (state, action) => { setMaliciousNodeList: (state, action) => {
// 判断当前节点是否已经存在 // 判断当前节点是否已经存在
const maliciousNode = state.maliciousNodeList.find( const maliciousNode = state.maliciousNodeList.find(
(item) => action.payload === item (item) => action.payload.name === item.name
); );
if (!maliciousNode) { if (!maliciousNode) {
state.maliciousNodeList.push(action.payload); state.maliciousNodeList.push(action.payload);
@ -179,7 +179,7 @@ export const appSlice = createSlice({
setNodeDownList: (state, action) => { setNodeDownList: (state, action) => {
// 判断当前节点是否已经存在 // 判断当前节点是否已经存在
const nodeDown = state.nodeDownList.find( const nodeDown = state.nodeDownList.find(
(item) => action.payload === item (item) => action.payload.name === item.name
); );
if (!nodeDown) { if (!nodeDown) {
state.nodeDownList.push(action.payload); state.nodeDownList.push(action.payload);
@ -196,7 +196,10 @@ export const appSlice = createSlice({
data: action.payload, data: action.payload,
}); });
} else { } else {
proxy_info.proxies[0] = action.payload; proxy_info.proxies[0] = {
...proxy_info.proxies[0],
data: action.payload,
};
} }
state.proxy_info = proxy_info; state.proxy_info = proxy_info;
}, },

1
src/vite-env.d.ts vendored
View File

@ -4,6 +4,7 @@ interface ImportMetaEnv {
// 定义你的环境变量,例如: // 定义你的环境变量,例如:
readonly VITE_BASE_URL: string readonly VITE_BASE_URL: string
readonly VITE_BLOCK_URL: string readonly VITE_BLOCK_URL: string
readonly VIET_EVENTS_WS_URL: string
} }
interface ImportMeta { interface ImportMeta {