This commit is contained in:
liyuanhu 2025-04-21 19:32:32 +08:00
parent 1693316766
commit 5000c88f0f
12 changed files with 442 additions and 417 deletions

2
.env
View File

@ -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"

View File

@ -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();
};

View File

@ -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

View File

@ -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)
}
}

View File

@ -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();
// }
// }
// }
//
// 执行一次完整的状态检查

View File

@ -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) => {

View File

@ -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;

View File

@ -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'

View File

@ -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>

View File

@ -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} />,
},
],
},

View File

@ -51,6 +51,7 @@ export const stopCore = createAsyncThunk(
)
export const enableProxy = createAsyncThunk('service/enableProxy', async () => {
console.log("开启代理了?")
const result = await commands.enableProxy()
return result
})

View File

@ -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;