fix:bug
This commit is contained in:
parent
1693316766
commit
5000c88f0f
2
.env
2
.env
@ -3,6 +3,6 @@ COSMOS_ENDPOINT="http://10.66.66.234:26657"
|
||||
NODE_SECRET="aHVnZSBjb21wYW55IHBob25lIHdlc3QgcGxhY2Ugc2VtaW5hciBtaXJhY2xlIGxlbmQgbWFuZGF0ZSB0aGVuIGFkanVzdCBxdWl0IG1lYXQgY2hlYXAgbm9vZGxlIGNvdXBsZSBkZWZpbmUgbXVzY2xlIHB1bHNlIHNpc3RlciBwaWVjZSBkZXZpY2UgcHJpdmF0ZSBob29k"
|
||||
IS_DEBUG="true"
|
||||
ACCOUNT_NAME="de1"
|
||||
VIET_EVENTS_WS_URL="ws://10.66.66.234:8080/events"
|
||||
VIET_EVENTS_URL="ws://10.66.66.234:8080/events"
|
||||
VITE_BASE_URL="http://10.66.66.234:6060"
|
||||
VITE_BLOCK_URL="http://10.66.66.234:1317"
|
||||
73
src/App.tsx
73
src/App.tsx
@ -1,3 +1,4 @@
|
||||
import dayjs from "dayjs";
|
||||
import { useStartupCheck } from "@/hooks/useStartupCheck";
|
||||
import { usePreventDefault } from "@/hooks/usePreventDefaultEventListener";
|
||||
import { useGlobalShortcut } from "@/hooks/useGlobalShortcut";
|
||||
@ -5,23 +6,22 @@ import { useRecreateTheCircuit } from "@/hooks/useRecreateTheCircuit";
|
||||
import { useCoreConfig } from "@/hooks/useCoreConfig";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import {
|
||||
setProxyInfoProxies,
|
||||
setProxiesList1,
|
||||
setProxiesList2,
|
||||
setProxiesLine,
|
||||
setMaliciousNodeList,
|
||||
setNodeDownList,
|
||||
setWeb3List,
|
||||
setWeb3List2,
|
||||
} from "@/store/web3Slice";
|
||||
import type { AppDispatch } from "@/store";
|
||||
|
||||
import eventBus, { eventTypes } from "@/utils/eventBus";
|
||||
import { WebSocketClient } from "@/utils/webSocketClient";
|
||||
import { blockChainApi } from "@/api/block";
|
||||
import { getRandomCountryKey } from "@/data";
|
||||
|
||||
import Titlebar from "@/components/Titlebar";
|
||||
import Layout from "@/layout";
|
||||
import Tray from "@/components/Tray";
|
||||
import { getRandomCountryKey } from "./data";
|
||||
import dayjs from "dayjs";
|
||||
import { api } from "./utils/api";
|
||||
|
||||
function App() {
|
||||
// 执行启动自检
|
||||
@ -40,18 +40,17 @@ function App() {
|
||||
// (state: RootState) => state.web3Reducer
|
||||
// );
|
||||
let eventsWs: WebSocketClient | null = null;
|
||||
|
||||
const openWsTraffic = async () => {
|
||||
if (eventsWs) return;
|
||||
eventsWs = new WebSocketClient("ws://10.66.66.234:8080/events", {});
|
||||
console.log(eventsWs, "openWsTraffic Start");
|
||||
// 执行 WebSocket 操作
|
||||
await eventsWs?.connect();
|
||||
await eventsWs?.addListener((msg: any) => {
|
||||
eventsWs?.addListener((msg: any) => {
|
||||
try {
|
||||
const msgData = msg ? JSON.parse(msg.data) : {};
|
||||
if (msgData.code === 0) {
|
||||
console.log(msgData, "msgDatamsgData");
|
||||
// console.log(msgData, "msgDatamsgData");
|
||||
switch (msgData.event) {
|
||||
case eventTypes.NODE_UP:
|
||||
console.log("节点上线");
|
||||
@ -140,16 +139,72 @@ function App() {
|
||||
eventBus.off(eventTypes.NODE_REMOVE);
|
||||
};
|
||||
|
||||
const timer = useRef<NodeJS.Timeout | null>(null);
|
||||
|
||||
const initWebsocketsAndEventBus = async () => {
|
||||
await openWsTraffic();
|
||||
await createdSoketEventBus();
|
||||
timer.current = setInterval(() => {
|
||||
blockChainApi.getLatestBlock().then((res) => {
|
||||
blockChainApi
|
||||
.getTxsByBlock(res.data.block.last_commit.height)
|
||||
.then((res) => {
|
||||
const height = res.data.block.last_commit.height;
|
||||
const timer = res.data.block.header.time;
|
||||
const txs = res.data.txs;
|
||||
const balance = res.data.txs.reduce((acc: any, item: any) => {
|
||||
const blance =
|
||||
item.auth_info.fee.gas_limit *
|
||||
Number(blockChainApi.blockConfig.minimum_gas_price);
|
||||
return acc + blance;
|
||||
}, 0)
|
||||
const item = {
|
||||
height: height,
|
||||
txs: txs,
|
||||
timerstamp: dayjs(timer).format("HH:mm:ss"),
|
||||
balance,
|
||||
// 保留三位小数
|
||||
balanceToFixed: Number(balance).toFixed(3),
|
||||
};
|
||||
// const timerstamp = dayjs().unix();
|
||||
dispatch(setWeb3List(item));
|
||||
console.log(item, "getTxsByBlock");
|
||||
});
|
||||
});
|
||||
}, 5000);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(setWeb3List2([
|
||||
{
|
||||
id: "6",
|
||||
name: "Cardano Wallet",
|
||||
payType: "ADA",
|
||||
status: "active",
|
||||
createdAt: 1737436420,
|
||||
upDatedAt: 5,
|
||||
balance: "65",
|
||||
address:
|
||||
"addr1qxck6ztj8lrxd0j2jz8f7tznzfu9wqv9qrplrh3r9eq8g9n0n3anjy2a4x54kd2sort3qvnc7mct82krlnpnxvl7v3sxmrv3f",
|
||||
privateKey:
|
||||
"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
|
||||
publicKey:
|
||||
"addr1qxck6ztj8lrxd0j2jz8f7tznzfu9wqv9qrplrh3r9eq8g9n0n3anjy2a4x54kd2sort3qvnc7mct82krlnpnxvl7v3sxmrv3f",
|
||||
numberTransactions: "35",
|
||||
transactions: 1,
|
||||
txs: [],
|
||||
height: 0,
|
||||
timerstamp: dayjs().format("HH:mm:ss"),
|
||||
balanceToFixed: 0,
|
||||
},
|
||||
]))
|
||||
setTimeout(() => {
|
||||
initWebsocketsAndEventBus();
|
||||
}, 1000);
|
||||
return () => {
|
||||
if (timer.current) {
|
||||
clearInterval(timer.current);
|
||||
}
|
||||
closeWsTraffic();
|
||||
removeSoketEventBus();
|
||||
};
|
||||
|
||||
@ -1,13 +1,26 @@
|
||||
import { CoreConfig } from "@/bindings";
|
||||
import { api } from "@/utils/api";
|
||||
|
||||
type BlockConfig = {
|
||||
halt_height: string;
|
||||
minimum_gas_price: string;
|
||||
pruning_interval: string;
|
||||
pruning_keep_recent: string;
|
||||
}
|
||||
|
||||
// 区块链api 类
|
||||
export class BlockChainApi {
|
||||
public coreConfig: CoreConfig;
|
||||
public blockConfig: BlockConfig
|
||||
public baseUrl = import.meta.env.VITE_BLOCK_URL;
|
||||
// public baseUrl = "http://10.66.66.234:26657";
|
||||
|
||||
constructor() {
|
||||
this.coreConfig = {} as CoreConfig;
|
||||
this.blockConfig = {} as BlockConfig;
|
||||
this.getBlockConfig();
|
||||
|
||||
|
||||
}
|
||||
|
||||
// async initCoreConfig() {
|
||||
@ -15,13 +28,41 @@ export class BlockChainApi {
|
||||
// this.coreConfig = await loadCoreConfig();
|
||||
// }
|
||||
|
||||
async getBlockConfig(){
|
||||
const res = await api.get(this.baseUrl + "/cosmos/base/node/v1beta1/config");
|
||||
this.blockConfig = {
|
||||
halt_height: res.data.halt_height,
|
||||
minimum_gas_price: res.data.minimum_gas_price || 0.0001,
|
||||
pruning_interval: res.data.pruning_interval,
|
||||
pruning_keep_recent: res.data.pruning_keep_recent,
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// 获取最新的区块信息
|
||||
async getLatestBlock() {
|
||||
const res = await api.get(
|
||||
this.baseUrl + "/cosmos/base/tendermint/v1beta1/blocks/latest",
|
||||
this.baseUrl + "/cosmos/base/tendermint/v1beta1/blocks/latest"
|
||||
);
|
||||
return res
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// cosmos/tx/v1beta1/txs/block
|
||||
async getTxsByBlock(blockHeight: number) {
|
||||
const res = await api.get(
|
||||
this.baseUrl + `/cosmos/tx/v1beta1/txs/block/${blockHeight}`
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
async getNodeInfo() {
|
||||
const res = await api.get(
|
||||
this.baseUrl + "/cosmos/base/tendermint/v1beta1/node_info"
|
||||
);
|
||||
return res;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 导出一个异步函数 initBlockChinApi,用于初始化区块链API
|
||||
|
||||
@ -56,22 +56,29 @@ export function ServiceControlPanel() {
|
||||
}
|
||||
|
||||
// 处理代理开关
|
||||
// 定义一个异步函数 handleProxyToggle,用于处理代理开关的切换
|
||||
const handleProxyToggle = async (checked: boolean) => {
|
||||
// 如果开关被选中且电路未准备好,则输出错误信息并返回
|
||||
if (checked && !isCircuitReady) {
|
||||
console.error('请先创建电路')
|
||||
return
|
||||
}
|
||||
|
||||
// 设置代理加载状态为 true,表示正在处理代理开关的切换
|
||||
setIsProxyLoading(true)
|
||||
try {
|
||||
// 如果开关被选中,则调用 enableProxy 函数启用代理
|
||||
if (checked) {
|
||||
await dispatch(enableProxy()).unwrap()
|
||||
// await dispatch(enableProxy()).unwrap()
|
||||
} else {
|
||||
// 如果开关未被选中,则调用 disableProxy 函数禁用代理
|
||||
await dispatch(disableProxy()).unwrap()
|
||||
}
|
||||
} catch (error) {
|
||||
// 如果在启用或禁用代理时发生错误,则输出错误信息
|
||||
console.error('Proxy toggle failed:', error)
|
||||
} finally {
|
||||
// 无论启用或禁用代理是否成功,最后都将代理加载状态设置为 false
|
||||
setIsProxyLoading(false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,10 @@
|
||||
import { useEffect } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
// import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import { commands, ProxyNodeInfo } from "@/bindings";
|
||||
import { app } from "@tauri-apps/api";
|
||||
import { createCircuit } from "@/store/circuitSlice";
|
||||
// import { createCircuit } from "@/store/circuitSlice";
|
||||
import { setServiceStatus, getProxy, getVersion } from "@/store/serviceSlice";
|
||||
import { setNodes, setNodesError, clearNodes } from "@/store/nodesSlice";
|
||||
import { setProxiesList1 } from "@/store/web3Slice";
|
||||
@ -267,33 +267,33 @@ export function useStartupCheck() {
|
||||
// 步骤4:检查当前是否开启了代理
|
||||
await dispatch(getProxy());
|
||||
|
||||
// 步骤5:检查当前是否有默认链路并且保证状态是正常,否则重新创建一个默认链路
|
||||
if (!fallbackCircuit || fallbackCircuit?.state === "failed") {
|
||||
let inbound = "";
|
||||
let outbound = "";
|
||||
if (coreResult && coreResult.data && coreResult.data.length > 0) {
|
||||
inbound = coreResult.data[0].country_code || "";
|
||||
outbound =
|
||||
coreResult.data
|
||||
.filter((item) => item.exit && item.country_code !== inbound)
|
||||
?.slice(-1)?.[0].country_code || "";
|
||||
// 如果没有这两个那么就跳过,证明核心运行了但是节点是空的,如果只有其中一个,那么证明总共节点就一个无法创建链路
|
||||
if (inbound && outbound) {
|
||||
await dispatch(
|
||||
createCircuit({
|
||||
uid: uuidv4(),
|
||||
name: "系统默认链路",
|
||||
inbound: inbound,
|
||||
outbound: outbound,
|
||||
multi_hop: 3,
|
||||
fallback: true,
|
||||
rule_path: null,
|
||||
is_prefix: false,
|
||||
})
|
||||
).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
// // 步骤5:检查当前是否有默认链路并且保证状态是正常,否则重新创建一个默认链路
|
||||
// if (!fallbackCircuit || fallbackCircuit?.state === "failed") {
|
||||
// let inbound = "";
|
||||
// let outbound = "";
|
||||
// if (coreResult && coreResult.data && coreResult.data.length > 0) {
|
||||
// inbound = coreResult.data[0].country_code || "";
|
||||
// outbound =
|
||||
// coreResult.data
|
||||
// .filter((item) => item.exit && item.country_code !== inbound)
|
||||
// ?.slice(-1)?.[0].country_code || "";
|
||||
// // 如果没有这两个那么就跳过,证明核心运行了但是节点是空的,如果只有其中一个,那么证明总共节点就一个无法创建链路
|
||||
// if (inbound && outbound) {
|
||||
// await dispatch(
|
||||
// createCircuit({
|
||||
// uid: uuidv4(),
|
||||
// name: "系统默认链路",
|
||||
// inbound: inbound,
|
||||
// outbound: outbound,
|
||||
// multi_hop: 3,
|
||||
// fallback: true,
|
||||
// rule_path: null,
|
||||
// is_prefix: false,
|
||||
// })
|
||||
// ).unwrap();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
//
|
||||
// 执行一次完整的状态检查
|
||||
|
||||
@ -37,11 +37,11 @@ export default function Layout() {
|
||||
title: "面向溯源对抗的数据转发",
|
||||
icon: <PoolSvg className="w-5 h-5" />,
|
||||
},
|
||||
{
|
||||
id: 'proxies',
|
||||
title: '节点池',
|
||||
icon: <PoolSvg className="w-5 h-5" />,
|
||||
},
|
||||
// {
|
||||
// id: 'proxies',
|
||||
// title: '节点池',
|
||||
// icon: <PoolSvg className="w-5 h-5" />,
|
||||
// },
|
||||
];
|
||||
|
||||
const handleClickMenu = (index: number) => {
|
||||
|
||||
@ -14,10 +14,9 @@ import TrashSvg from "@/assets/svg/home/trash.svg?react";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
import {
|
||||
setProxyInfoProxies,
|
||||
setProxiesList1,
|
||||
setProxiesList2,
|
||||
setProxiesLine,
|
||||
setProxyInfoProxies,
|
||||
setProxiesList2,
|
||||
setProxiesLine,
|
||||
} from "@/store/web3Slice";
|
||||
import type { AppDispatch, RootState } from "@/store";
|
||||
import "./index.scss";
|
||||
@ -25,274 +24,258 @@ import { DialogConfig, FormAlertDialog } from "./components/FormAlertDialog";
|
||||
import { ClearNodeDialog } from "./components/ClearNodeDialog";
|
||||
|
||||
export const DIALOGTYPE = {
|
||||
ADDNode: {
|
||||
title: "添加节点",
|
||||
desc: "",
|
||||
successText: "添加",
|
||||
},
|
||||
AddNetwork: {
|
||||
title: "构建网络",
|
||||
desc: "",
|
||||
successText: "构建",
|
||||
},
|
||||
ADDNode: {
|
||||
title: "添加节点",
|
||||
desc: "",
|
||||
successText: "添加",
|
||||
},
|
||||
AddNetwork: {
|
||||
title: "构建网络",
|
||||
desc: "",
|
||||
successText: "构建",
|
||||
},
|
||||
};
|
||||
|
||||
export const NODEDIALOGTYPE = {
|
||||
ClearFailNode: {
|
||||
title: "清除掉线节点",
|
||||
desc: "",
|
||||
successText: "清除",
|
||||
},
|
||||
ClearWargingNode: {
|
||||
title: "恶意节点",
|
||||
desc: "",
|
||||
successText: "清除",
|
||||
},
|
||||
ClearFailNode: {
|
||||
title: "清除掉线节点",
|
||||
desc: "",
|
||||
successText: "清除",
|
||||
},
|
||||
ClearWargingNode: {
|
||||
title: "恶意节点",
|
||||
desc: "",
|
||||
successText: "清除",
|
||||
},
|
||||
};
|
||||
const DecentralizedElasticNetwork = () => {
|
||||
const dispatch = useDispatch<AppDispatch>();
|
||||
const { web3List, web3List2, proxy_info, path_list, } = useSelector(
|
||||
(state: RootState) => state.web3Reducer
|
||||
);
|
||||
const dispatch = useDispatch<AppDispatch>();
|
||||
const { web3List, web3List2, proxy_info, path_list } = useSelector(
|
||||
(state: RootState) => state.web3Reducer
|
||||
);
|
||||
|
||||
const [form] = Form.useForm();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [openNode, setOpenNode] = useState(false);
|
||||
const [dialogLoading] = useState(false);
|
||||
const [type, setType] = useState<DialogConfig>(DIALOGTYPE.ADDNode);
|
||||
const [nodeType, setNodeType] = useState<DialogConfig>(
|
||||
NODEDIALOGTYPE.ClearFailNode
|
||||
);
|
||||
const [form] = Form.useForm();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [openNode, setOpenNode] = useState(false);
|
||||
const [dialogLoading] = useState(false);
|
||||
const [type, setType] = useState<DialogConfig>(DIALOGTYPE.ADDNode);
|
||||
const [nodeType, setNodeType] = useState<DialogConfig>(
|
||||
NODEDIALOGTYPE.ClearFailNode
|
||||
);
|
||||
|
||||
const newWeb3List = useMemo(() => {
|
||||
// 展示最新的6个节点
|
||||
return web3List.slice(-6);
|
||||
}, [web3List]);
|
||||
const newWeb3List = useMemo(() => {
|
||||
// 展示最新的6个节点
|
||||
return web3List.slice(-6);
|
||||
}, [web3List]);
|
||||
|
||||
const successHandle = async () => {
|
||||
await form.validateFields();
|
||||
const formValue: any = form.getFieldsValue();
|
||||
if (type.title === DIALOGTYPE.ADDNode.title) {
|
||||
console.log(formValue,"formValue")
|
||||
setOpen(false);
|
||||
} else {
|
||||
const { inbound, outbound } = formValue || {};
|
||||
if (inbound && outbound) {
|
||||
dispatch(
|
||||
setProxyInfoProxies({
|
||||
country_code: inbound,
|
||||
ingress_country_code: outbound,
|
||||
})
|
||||
);
|
||||
setOpen(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
async function handleSelectFile() {
|
||||
try {
|
||||
const selected = await openFile({
|
||||
multiple: false,
|
||||
directory: false,
|
||||
filters: [
|
||||
{
|
||||
name: "Excel Files",
|
||||
extensions: ["xlsx", "xls"], // 移除了扩展名前的点号
|
||||
},
|
||||
],
|
||||
});
|
||||
if (selected && typeof selected === "string") {
|
||||
if (selected.includes("验证节点包1")) {
|
||||
console.log("验证节点包1");
|
||||
dispatch(setProxiesList1());
|
||||
}
|
||||
if (selected.includes("验证节点包2")) {
|
||||
console.log("验证节点包2");
|
||||
dispatch(setProxiesList2());
|
||||
}
|
||||
setOpen(false);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Error selecting file:", err);
|
||||
}
|
||||
const successHandle = async () => {
|
||||
await form.validateFields();
|
||||
const formValue: any = form.getFieldsValue();
|
||||
if (type.title === DIALOGTYPE.ADDNode.title) {
|
||||
setOpen(false);
|
||||
} else {
|
||||
const { inbound, outbound } = formValue || {};
|
||||
if (inbound && outbound) {
|
||||
dispatch(
|
||||
setProxyInfoProxies({
|
||||
country_code: inbound,
|
||||
ingress_country_code: outbound,
|
||||
})
|
||||
);
|
||||
setOpen(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const ICircuitRequest = useMemo(() => {
|
||||
return {
|
||||
open,
|
||||
setOpen,
|
||||
successHandle,
|
||||
dialogLoading,
|
||||
form,
|
||||
type,
|
||||
canSubmit: true,
|
||||
handleSelectFile,
|
||||
};
|
||||
}, [open, dialogLoading, type, handleSelectFile]);
|
||||
async function handleSelectFile() {
|
||||
try {
|
||||
const selected = await openFile({
|
||||
multiple: false,
|
||||
directory: false,
|
||||
filters: [
|
||||
{
|
||||
name: "Excel Files",
|
||||
extensions: ["xlsx", "xls"], // 移除了扩展名前的点号
|
||||
},
|
||||
],
|
||||
});
|
||||
if (selected && typeof selected === "string") {
|
||||
if (selected.includes("验证节点包1")) {
|
||||
console.log("验证节点包1");
|
||||
// dispatch(setProxiesList1());
|
||||
}
|
||||
if (selected.includes("验证节点包2")) {
|
||||
console.log("验证节点包2");
|
||||
dispatch(setProxiesList2());
|
||||
}
|
||||
setOpen(false);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error("Error selecting file:", err);
|
||||
}
|
||||
}
|
||||
|
||||
const nodeSuccessHandle = () => {};
|
||||
const ICircuitRequest = useMemo(() => {
|
||||
return {
|
||||
open,
|
||||
setOpen,
|
||||
successHandle,
|
||||
dialogLoading,
|
||||
form,
|
||||
type,
|
||||
canSubmit: true,
|
||||
handleSelectFile,
|
||||
};
|
||||
}, [open, dialogLoading, type, handleSelectFile]);
|
||||
|
||||
const ClearNodeDialogProps = useMemo(() => {
|
||||
return {
|
||||
open: openNode,
|
||||
setOpen: setOpenNode,
|
||||
successHandle: nodeSuccessHandle,
|
||||
dialogLoading,
|
||||
form,
|
||||
type: nodeType,
|
||||
canSubmit: true,
|
||||
};
|
||||
}, [openNode, dialogLoading, nodeType]);
|
||||
const nodeSuccessHandle = () => {};
|
||||
|
||||
const screenData = useMemo(() => {
|
||||
return {
|
||||
path_list,
|
||||
proxy_info,
|
||||
};
|
||||
}, [path_list, proxy_info]);
|
||||
const ClearNodeDialogProps = useMemo(() => {
|
||||
return {
|
||||
open: openNode,
|
||||
setOpen: setOpenNode,
|
||||
successHandle: nodeSuccessHandle,
|
||||
dialogLoading,
|
||||
form,
|
||||
type: nodeType,
|
||||
canSubmit: true,
|
||||
};
|
||||
}, [openNode, dialogLoading, nodeType]);
|
||||
|
||||
// useEffect(() => {
|
||||
// dispatch(randomUpdateWeb3List());
|
||||
// dispatch(randomUpdateWeb3List2());
|
||||
// // 每1.5秒更新一次
|
||||
// const interval = setInterval(() => {
|
||||
// dispatch(randomUpdateWeb3List());
|
||||
// dispatch(randomUpdateWeb3List2());
|
||||
// }, 1500);
|
||||
const screenData = useMemo(() => {
|
||||
return {
|
||||
path_list,
|
||||
proxy_info,
|
||||
};
|
||||
}, [path_list, proxy_info]);
|
||||
|
||||
// return () => clearInterval(interval);
|
||||
// }, [dispatch]);
|
||||
// useEffect(() => {
|
||||
// dispatch(randomUpdateWeb3List());
|
||||
// dispatch(randomUpdateWeb3List2());
|
||||
// // 每1.5秒更新一次
|
||||
// const interval = setInterval(() => {
|
||||
// dispatch(randomUpdateWeb3List());
|
||||
// dispatch(randomUpdateWeb3List2());
|
||||
// }, 1500);
|
||||
|
||||
return (
|
||||
<div className="decentralized w-full h-full flex flex-col relative">
|
||||
<div className="box"></div>
|
||||
<div className="w-full flex items-center justify-center relative">
|
||||
{/* <img
|
||||
// return () => clearInterval(interval);
|
||||
// }, [dispatch]);
|
||||
|
||||
return (
|
||||
<div className="decentralized w-full h-full flex flex-col relative">
|
||||
<div className="box"></div>
|
||||
<div className="w-full flex items-center justify-center relative">
|
||||
{/* <img
|
||||
className="w-[1693px] h-[271px] absolute top-[160px] left-[50%] translate-x-[-50%] z-10"
|
||||
src={linePng}
|
||||
alt=""
|
||||
/> */}
|
||||
{/* <div className="w-[90%] absolute top-0 left-0"></div> */}
|
||||
<div className="w-[1693px] h-full flex items-center justify-center">
|
||||
<div className="w-[795px] h-full flex items-center justify-end gap-10 z-10">
|
||||
<div className="carousel-container !justify-end">
|
||||
{newWeb3List.map((item, index) => {
|
||||
// 随机0-10的整数
|
||||
const randomDelay =
|
||||
Math.floor(Math.random() * 35) * 1;
|
||||
return (
|
||||
<div
|
||||
className="w-[105px] relative carousel-item"
|
||||
key={`${item.id}-${index}`}
|
||||
style={{
|
||||
viewTransitionName: `web3-item-1-${index}`,
|
||||
}}
|
||||
>
|
||||
<div className="w-[calc(100%-10px)] h-[calc(100%-10px)] absolute top-[6px] left-[8px] overflow-hidden">
|
||||
<img
|
||||
className={cn(
|
||||
"!max-w-[186px] h-[160px] relative opacity-50 mix-blend-soft-light z-10"
|
||||
)}
|
||||
style={{
|
||||
left: `${
|
||||
-30 - randomDelay
|
||||
}px`,
|
||||
top: `${
|
||||
-30 - randomDelay
|
||||
}px`,
|
||||
}}
|
||||
src={web3BoxGif}
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
src={Web3Box2Png}
|
||||
className="w-full h-full"
|
||||
/>
|
||||
<div className="absolute bottom-[-170px] left-[55px] h-[160px] w-[2px] bg-gradient-to-bl to-[#4820C9]/0 from-[#7D82FF] web3-line"></div>
|
||||
<div className="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center text-white pl-1.5 z-20">
|
||||
{/* <div className="justify-start text-pink-600 text-2xl font-normal font-['Oswald'] absolute top-[-34px] left-[50%] translate-x-[-50%]">
|
||||
{/* <div className="w-[90%] absolute top-0 left-0"></div> */}
|
||||
<div className="w-[1693px] h-full flex items-center justify-center">
|
||||
<div className="w-[795px] h-full flex items-center justify-end gap-10 z-10">
|
||||
<div className="carousel-container !justify-end">
|
||||
{newWeb3List.map((item, index) => {
|
||||
// 随机0-10的整数
|
||||
const randomDelay = Math.floor(Math.random() * 35) * 1;
|
||||
return (
|
||||
<div
|
||||
className="w-[105px] relative carousel-item"
|
||||
key={`${item.height}-${index}`}
|
||||
style={{
|
||||
viewTransitionName: `web3-item-1-${index}`,
|
||||
}}
|
||||
>
|
||||
<div className="w-[calc(100%-10px)] h-[calc(100%-10px)] absolute top-[6px] left-[8px] overflow-hidden">
|
||||
<img
|
||||
className={cn(
|
||||
"!max-w-[186px] h-[160px] relative opacity-50 mix-blend-soft-light z-10"
|
||||
)}
|
||||
style={{
|
||||
left: `${-30 - randomDelay}px`,
|
||||
top: `${-30 - randomDelay}px`,
|
||||
}}
|
||||
src={web3BoxGif}
|
||||
/>
|
||||
</div>
|
||||
<img src={Web3Box2Png} className="w-full h-full" />
|
||||
<div className="absolute bottom-[-170px] left-[55px] h-[160px] w-[2px] bg-gradient-to-bl to-[#4820C9]/0 from-[#7D82FF] web3-line"></div>
|
||||
<div className="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center text-white pl-1.5 z-20">
|
||||
{/* <div className="justify-start text-pink-600 text-2xl font-normal font-['Oswald'] absolute top-[-34px] left-[50%] translate-x-[-50%]">
|
||||
{item.transactions}
|
||||
</div> */}
|
||||
<div className="text-lg">
|
||||
{item.balance} SOL
|
||||
</div>
|
||||
<div className="!text-xs my-[10px]">
|
||||
{item.numberTransactions}笔交易
|
||||
</div>
|
||||
<div className="!text-sm opacity-60">
|
||||
{item.upDatedAt}
|
||||
分钟内
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="!text-xs">{item?.balanceToFixed} SOL</div>
|
||||
<div className="!text-xs my-[10px]">
|
||||
{item.txs.length}笔交易
|
||||
</div>
|
||||
<div className="!text-sm opacity-60">
|
||||
{item.timerstamp}
|
||||
</div>
|
||||
</div>
|
||||
<div className="w-fit mt-6 mx-[20px] flex-shrink-0">
|
||||
<VectorSlideSvg />
|
||||
</div>
|
||||
<div className="w-[795px] h-full flex items-center justify-start gap-10 ">
|
||||
<div className="carousel-container justify-start">
|
||||
{web3List2.map((item, index) => {
|
||||
const randomDelay =
|
||||
Math.floor(Math.random() * 35) * 1;
|
||||
return (
|
||||
<div
|
||||
key={`${item.id}-${index}`}
|
||||
className="w-[105px] relative carousel-item"
|
||||
style={{
|
||||
viewTransitionName: `web3-item-2-${index}`,
|
||||
}}
|
||||
>
|
||||
<div className="w-[calc(100%-10px)] h-[calc(100%-10px)] absolute top-[6px] left-[8px] overflow-hidden">
|
||||
<img
|
||||
className="!max-w-[186px] h-[160px] relative left-[-30px] top-[-30px] opacity-50 mix-blend-soft-light z-10"
|
||||
src={web3BoxGif}
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
src={Web3BoxPng}
|
||||
style={{
|
||||
left: `${-30 - randomDelay}px`,
|
||||
top: `${-30 - randomDelay}px`,
|
||||
}}
|
||||
className="w-full h-full"
|
||||
/>
|
||||
<div className="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center text-white pl-1.5">
|
||||
<div className="text-lg">
|
||||
{item.balance} SOL
|
||||
</div>
|
||||
<div className="!text-xs my-[10px]">
|
||||
{item.numberTransactions}笔交易
|
||||
</div>
|
||||
<div className="!text-sm opacity-60">
|
||||
{item.upDatedAt}
|
||||
分钟内
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
<div className="mt-2 w-full h-full flex-1">
|
||||
<WorldGeo screenData={screenData} />
|
||||
</div>
|
||||
<div className="absolute bottom-6 left-[50%] translate-x-[-50%] w-[calc(100%-51px)] p-6 bg-indigo-950 bg-opacity-10 rounded-md outline outline-1 outline-zinc-200 outline-opacity-40 backdrop-blur-lg inline-flex justify-start items-center gap-4">
|
||||
<div
|
||||
className="bt1 cursor-pointer"
|
||||
onClick={() => {
|
||||
setType(DIALOGTYPE.ADDNode);
|
||||
setOpen(true);
|
||||
</div>
|
||||
<div className="w-fit mt-6 mx-[20px] flex-shrink-0">
|
||||
<VectorSlideSvg />
|
||||
</div>
|
||||
<div className="w-[795px] h-full flex items-center justify-start gap-10 ">
|
||||
<div className="carousel-container justify-start">
|
||||
{web3List2.map((item, index) => {
|
||||
const randomDelay = Math.floor(Math.random() * 35) * 1;
|
||||
return (
|
||||
<div
|
||||
key={`${item.id}-${index}`}
|
||||
className="w-[105px] relative carousel-item"
|
||||
style={{
|
||||
viewTransitionName: `web3-item-2-${index}`,
|
||||
}}
|
||||
>
|
||||
<AddSvg />
|
||||
添加节点
|
||||
</div>
|
||||
{/* <div
|
||||
>
|
||||
<div className="w-[calc(100%-10px)] h-[calc(100%-10px)] absolute top-[6px] left-[8px] overflow-hidden">
|
||||
<img
|
||||
className="!max-w-[186px] h-[160px] relative left-[-30px] top-[-30px] opacity-50 mix-blend-soft-light z-10"
|
||||
src={web3BoxGif}
|
||||
/>
|
||||
</div>
|
||||
<img
|
||||
src={Web3BoxPng}
|
||||
style={{
|
||||
left: `${-30 - randomDelay}px`,
|
||||
top: `${-30 - randomDelay}px`,
|
||||
}}
|
||||
className="w-full h-full"
|
||||
/>
|
||||
<div className="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center text-white pl-1.5">
|
||||
<div className="text-lg">{item.balance} SOL</div>
|
||||
<div className="!text-xs my-[10px]">
|
||||
{item.numberTransactions}笔交易
|
||||
</div>
|
||||
<div className="!text-sm opacity-60">
|
||||
{item.timerstamp}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="mt-2 w-full h-full flex-1">
|
||||
<WorldGeo screenData={screenData} />
|
||||
</div>
|
||||
<div className="absolute bottom-6 left-[50%] translate-x-[-50%] w-[calc(100%-51px)] p-6 bg-indigo-950 bg-opacity-10 rounded-md outline outline-1 outline-zinc-200 outline-opacity-40 backdrop-blur-lg inline-flex justify-start items-center gap-4">
|
||||
<div
|
||||
className="bt1 cursor-pointer"
|
||||
onClick={() => {
|
||||
setType(DIALOGTYPE.ADDNode);
|
||||
setOpen(true);
|
||||
}}
|
||||
>
|
||||
<AddSvg />
|
||||
添加节点
|
||||
</div>
|
||||
{/* <div
|
||||
className="bt1 cursor-pointer"
|
||||
onClick={() => {
|
||||
setType(DIALOGTYPE.AddNetwork);
|
||||
@ -302,40 +285,40 @@ const DecentralizedElasticNetwork = () => {
|
||||
<InterSvg />
|
||||
网络构建
|
||||
</div> */}
|
||||
<div
|
||||
className="bt1 cursor-pointer"
|
||||
onClick={() => {
|
||||
dispatch(setProxiesLine());
|
||||
}}
|
||||
>
|
||||
<InterSvg />
|
||||
网络构建
|
||||
</div>
|
||||
<div
|
||||
className="bt2 cursor-pointer"
|
||||
onClick={() => {
|
||||
setNodeType(NODEDIALOGTYPE.ClearWargingNode);
|
||||
setOpenNode(true);
|
||||
}}
|
||||
>
|
||||
检测恶意节点
|
||||
</div>
|
||||
<div
|
||||
className="bt2 cursor-pointer"
|
||||
onClick={() => {
|
||||
setNodeType(NODEDIALOGTYPE.ClearFailNode);
|
||||
setOpenNode(true);
|
||||
}}
|
||||
>
|
||||
<TrashSvg />
|
||||
清除掉线节点
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<FormAlertDialog {...ICircuitRequest} />
|
||||
<ClearNodeDialog {...ClearNodeDialogProps} />
|
||||
<div
|
||||
className="bt1 cursor-pointer"
|
||||
onClick={() => {
|
||||
dispatch(setProxiesLine());
|
||||
}}
|
||||
>
|
||||
<InterSvg />
|
||||
网络构建
|
||||
</div>
|
||||
);
|
||||
<div
|
||||
className="bt2 cursor-pointer"
|
||||
onClick={() => {
|
||||
setNodeType(NODEDIALOGTYPE.ClearWargingNode);
|
||||
setOpenNode(true);
|
||||
}}
|
||||
>
|
||||
检测恶意节点
|
||||
</div>
|
||||
<div
|
||||
className="bt2 cursor-pointer"
|
||||
onClick={() => {
|
||||
setNodeType(NODEDIALOGTYPE.ClearFailNode);
|
||||
setOpenNode(true);
|
||||
}}
|
||||
>
|
||||
<TrashSvg />
|
||||
清除掉线节点
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
<FormAlertDialog {...ICircuitRequest} />
|
||||
<ClearNodeDialog {...ClearNodeDialogProps} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default DecentralizedElasticNetwork;
|
||||
|
||||
@ -15,7 +15,6 @@ import {
|
||||
enableProxy,
|
||||
disableProxy,
|
||||
} from '@/store/serviceSlice'
|
||||
import { createCircuit } from '@/store/circuitSlice'
|
||||
import { WebSocketClient } from '@/utils/webSocketClient'
|
||||
import { ServiceControlPanel } from '@/components/ServiceControlPanel'
|
||||
import { useCoreConfig } from '@/hooks/useCoreConfig'
|
||||
|
||||
@ -31,7 +31,6 @@ import {
|
||||
getDynamicRouteGeneration,
|
||||
getApplicationDiversion,
|
||||
} from "@/api/flying-line";
|
||||
import { blockChainApi } from "@/api/block";
|
||||
import { errorToast } from "@/components/GlobalToast";
|
||||
import { toast } from "@/components/ui/use-toast";
|
||||
import { disableProxy, enableProxy } from "@/store/serviceSlice";
|
||||
@ -245,17 +244,6 @@ const NewHome = () => {
|
||||
if (!isCoreRunning) {
|
||||
await commands.startCore();
|
||||
}
|
||||
// 这里要先轮询去判断是否启动成功,如果启动失败,则抛出异常
|
||||
let isGetNodesResult = await commands.getNodes();
|
||||
let count = 0;
|
||||
while (isGetNodesResult.status !== "ok") {
|
||||
isGetNodesResult = await commands.getNodes();
|
||||
count++;
|
||||
// 如果50次都没有开启成功核心那么启动失败
|
||||
if (count > 50) {
|
||||
throw new Error("启动核心失败");
|
||||
}
|
||||
}
|
||||
|
||||
setIsProxyLoading(true);
|
||||
|
||||
@ -289,9 +277,6 @@ const NewHome = () => {
|
||||
});
|
||||
};
|
||||
useEffect(() => {
|
||||
blockChainApi.getLatestBlock().then((res) => {
|
||||
console.log("getLatestBlock res:", res);
|
||||
});
|
||||
initData();
|
||||
}, []);
|
||||
|
||||
@ -341,13 +326,12 @@ const NewHome = () => {
|
||||
{/* <div className="justify-start text-pink-600 text-2xl font-normal font-['Oswald'] absolute top-[-34px] left-[50%] translate-x-[-50%]">
|
||||
{item.transactions}
|
||||
</div> */}
|
||||
<div className="text-lg">{item.balance} SOL</div>
|
||||
<div className="!text-xs">{item?.balanceToFixed} SOL</div>
|
||||
<div className="!text-xs my-[10px]">
|
||||
{item.numberTransactions}笔交易
|
||||
{item.txs.length}笔交易
|
||||
</div>
|
||||
<div className="!text-sm opacity-60">
|
||||
{item.upDatedAt}
|
||||
分钟内
|
||||
{item.timerstamp}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -360,7 +344,7 @@ const NewHome = () => {
|
||||
</div>
|
||||
<div className="w-[795px] h-full flex items-center justify-start gap-10 ">
|
||||
<div className="carousel-container justify-start">
|
||||
{web3List2.map((item, index) => {
|
||||
{web3List2.map((item, index) => {
|
||||
const randomDelay = Math.floor(Math.random() * 35) * 1;
|
||||
return (
|
||||
<div
|
||||
@ -385,13 +369,12 @@ const NewHome = () => {
|
||||
className="w-full h-full"
|
||||
/>
|
||||
<div className="absolute top-0 left-0 w-full h-full flex flex-col items-center justify-center text-white pl-1.5">
|
||||
<div className="text-lg">{item.balance} SOL</div>
|
||||
<div className="!text-xs">{item.balance} SOL</div>
|
||||
<div className="!text-xs my-[10px]">
|
||||
{item.numberTransactions}笔交易
|
||||
</div>
|
||||
<div className="!text-sm opacity-60">
|
||||
{item.upDatedAt}
|
||||
分钟内
|
||||
{item.timerstamp}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -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: <LazyLoader component={HomePage} />,
|
||||
element: <LazyLoader component={ProxiesPage} />,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
||||
@ -51,6 +51,7 @@ export const stopCore = createAsyncThunk(
|
||||
)
|
||||
|
||||
export const enableProxy = createAsyncThunk('service/enableProxy', async () => {
|
||||
console.log("开启代理了?")
|
||||
const result = await commands.enableProxy()
|
||||
return result
|
||||
})
|
||||
|
||||
@ -15,6 +15,10 @@ export interface Iweb3 {
|
||||
numberTransactions?: string;
|
||||
// 交易次数
|
||||
transactions?: number | string;
|
||||
height?: number | string;
|
||||
txs: any[];
|
||||
timerstamp?: string;
|
||||
balanceToFixed?: string | number;
|
||||
}
|
||||
|
||||
interface Iweb3Slice {
|
||||
@ -65,23 +69,7 @@ const initialState: Iweb3Slice = {
|
||||
isLine: false,
|
||||
web3List: [],
|
||||
web3List2: [
|
||||
{
|
||||
id: "6",
|
||||
name: "Cardano Wallet",
|
||||
payType: "ADA",
|
||||
status: "active",
|
||||
createdAt: 1737436420,
|
||||
upDatedAt: 5,
|
||||
balance: "65",
|
||||
address:
|
||||
"addr1qxck6ztj8lrxd0j2jz8f7tznzfu9wqv9qrplrh3r9eq8g9n0n3anjy2a4x54kd2sort3qvnc7mct82krlnpnxvl7v3sxmrv3f",
|
||||
privateKey:
|
||||
"xprv9s21ZrQH143K3QTDL4LXw2F7HEK3wJUD2nW2nRk4stbPy6cq3jPPqjiChkVvvNKmPGJxWUtg6LnF5kejMRNNU3TGtRBeJgk33yuGBxrMPHi",
|
||||
publicKey:
|
||||
"addr1qxck6ztj8lrxd0j2jz8f7tznzfu9wqv9qrplrh3r9eq8g9n0n3anjy2a4x54kd2sort3qvnc7mct82krlnpnxvl7v3sxmrv3f",
|
||||
numberTransactions: "35",
|
||||
transactions: 1,
|
||||
},
|
||||
|
||||
],
|
||||
path_list: [
|
||||
{
|
||||
@ -228,58 +216,26 @@ export const appSlice = createSlice({
|
||||
item.isLine = true;
|
||||
return item;
|
||||
});
|
||||
|
||||
// 计算需要添加的钱包数量
|
||||
const proxiesCount = state.proxy_info.proxies.length;
|
||||
const currentWeb3Count = state.web3List.length;
|
||||
|
||||
// 检查是否需要添加钱包
|
||||
if (
|
||||
(proxiesCount === 2 && currentWeb3Count >= 2) ||
|
||||
(proxiesCount === 1 && currentWeb3Count >= 1)
|
||||
) {
|
||||
// 已满足条件,不需要任何操作
|
||||
return;
|
||||
}
|
||||
|
||||
// 计算需要添加的钱包数量
|
||||
let walletsToAdd = 0;
|
||||
if (proxiesCount === 2) {
|
||||
walletsToAdd = 2 - currentWeb3Count; // 最多添加到2个
|
||||
} else if (proxiesCount === 1) {
|
||||
walletsToAdd = 1 - currentWeb3Count; // 最多添加到1个
|
||||
}
|
||||
|
||||
// 确保不会添加负数的钱包
|
||||
walletsToAdd = Math.max(0, walletsToAdd);
|
||||
|
||||
// 只有在需要添加钱包时才创建新钱包
|
||||
if (walletsToAdd > 0) {
|
||||
const newWallets: Iweb3[] = [];
|
||||
for (let i = 0; i < walletsToAdd; i++) {
|
||||
const id = uuid();
|
||||
newWallets.push({
|
||||
id,
|
||||
name: "Cardano Wallet",
|
||||
payType: "ADA",
|
||||
status: "active",
|
||||
createdAt: 1737436420,
|
||||
balance: randomBalance(),
|
||||
upDatedAt: randomUpdatedAt(),
|
||||
transactions: randomTransactionCount2(),
|
||||
numberTransactions: randomTransactionCount(),
|
||||
});
|
||||
}
|
||||
|
||||
// 更新状态
|
||||
state.web3List = [...state.web3List, ...newWallets];
|
||||
}
|
||||
},
|
||||
setIsLine: (state, action) => {
|
||||
state.isLine = action.payload;
|
||||
},
|
||||
setWeb3List: (state, action) => {
|
||||
state.web3List = action.payload;
|
||||
// 最多只存六条数据 action.payload 为item
|
||||
const web3List = state.web3List;
|
||||
// 判断如果源数据有六条或六条以上,那么截取最后五条数据
|
||||
if (web3List.length >= 6) {
|
||||
web3List.splice(0, 1);
|
||||
}
|
||||
// 判断一下当前的高度是否存在,如果存在那么就不添加
|
||||
const isExist = web3List.find(
|
||||
(item) => item.height === action.payload.height
|
||||
);
|
||||
if (!isExist) {
|
||||
web3List.push(action.payload);
|
||||
}
|
||||
|
||||
state.web3List = web3List;
|
||||
},
|
||||
setWeb3List2: (state, action) => {
|
||||
state.web3List2 = action.payload;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user