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" 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" VIET_EVENTS_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://10.66.66.234:1317" 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 { useStartupCheck } from "@/hooks/useStartupCheck";
import { usePreventDefault } from "@/hooks/usePreventDefaultEventListener"; import { usePreventDefault } from "@/hooks/usePreventDefaultEventListener";
import { useGlobalShortcut } from "@/hooks/useGlobalShortcut"; import { useGlobalShortcut } from "@/hooks/useGlobalShortcut";
@ -5,23 +6,22 @@ import { useRecreateTheCircuit } from "@/hooks/useRecreateTheCircuit";
import { useCoreConfig } from "@/hooks/useCoreConfig"; import { useCoreConfig } from "@/hooks/useCoreConfig";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { import {
setProxyInfoProxies,
setProxiesList1,
setProxiesList2,
setProxiesLine,
setMaliciousNodeList, setMaliciousNodeList,
setNodeDownList, setNodeDownList,
setWeb3List,
setWeb3List2,
} from "@/store/web3Slice"; } from "@/store/web3Slice";
import type { AppDispatch } 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";
import { blockChainApi } from "@/api/block";
import { getRandomCountryKey } from "@/data";
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 { api } from "./utils/api";
import dayjs from "dayjs";
function App() { function App() {
// 执行启动自检 // 执行启动自检
@ -40,18 +40,17 @@ function App() {
// (state: RootState) => state.web3Reducer // (state: RootState) => state.web3Reducer
// ); // );
let eventsWs: WebSocketClient | null = null; let eventsWs: WebSocketClient | null = null;
const openWsTraffic = async () => { const openWsTraffic = async () => {
if (eventsWs) return; if (eventsWs) return;
eventsWs = new WebSocketClient("ws://10.66.66.234:8080/events", {}); eventsWs = new WebSocketClient("ws://10.66.66.234:8080/events", {});
console.log(eventsWs, "openWsTraffic Start"); console.log(eventsWs, "openWsTraffic Start");
// 执行 WebSocket 操作 // 执行 WebSocket 操作
await eventsWs?.connect(); await eventsWs?.connect();
await eventsWs?.addListener((msg: any) => { eventsWs?.addListener((msg: any) => {
try { try {
const msgData = msg ? JSON.parse(msg.data) : {}; const msgData = msg ? JSON.parse(msg.data) : {};
if (msgData.code === 0) { if (msgData.code === 0) {
console.log(msgData, "msgDatamsgData"); // console.log(msgData, "msgDatamsgData");
switch (msgData.event) { switch (msgData.event) {
case eventTypes.NODE_UP: case eventTypes.NODE_UP:
console.log("节点上线"); console.log("节点上线");
@ -140,16 +139,72 @@ function App() {
eventBus.off(eventTypes.NODE_REMOVE); eventBus.off(eventTypes.NODE_REMOVE);
}; };
const timer = useRef<NodeJS.Timeout | null>(null);
const initWebsocketsAndEventBus = async () => { const initWebsocketsAndEventBus = async () => {
await openWsTraffic(); await openWsTraffic();
await createdSoketEventBus(); 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(() => { 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(() => { setTimeout(() => {
initWebsocketsAndEventBus(); initWebsocketsAndEventBus();
}, 1000); }, 1000);
return () => { return () => {
if (timer.current) {
clearInterval(timer.current);
}
closeWsTraffic(); closeWsTraffic();
removeSoketEventBus(); removeSoketEventBus();
}; };

View File

@ -1,13 +1,26 @@
import { CoreConfig } from "@/bindings"; import { CoreConfig } from "@/bindings";
import { api } from "@/utils/api"; import { api } from "@/utils/api";
type BlockConfig = {
halt_height: string;
minimum_gas_price: string;
pruning_interval: string;
pruning_keep_recent: string;
}
// 区块链api 类 // 区块链api 类
export class BlockChainApi { export class BlockChainApi {
public coreConfig: CoreConfig; public coreConfig: CoreConfig;
public blockConfig: BlockConfig
public baseUrl = import.meta.env.VITE_BLOCK_URL; public baseUrl = import.meta.env.VITE_BLOCK_URL;
// public baseUrl = "http://10.66.66.234:26657";
constructor() { constructor() {
this.coreConfig = {} as CoreConfig; this.coreConfig = {} as CoreConfig;
this.blockConfig = {} as BlockConfig;
this.getBlockConfig();
} }
// async initCoreConfig() { // async initCoreConfig() {
@ -15,13 +28,41 @@ export class BlockChainApi {
// this.coreConfig = await loadCoreConfig(); // 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() { async getLatestBlock() {
const res = await api.get( 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 // 导出一个异步函数 initBlockChinApi用于初始化区块链API

View File

@ -56,22 +56,29 @@ export function ServiceControlPanel() {
} }
// 处理代理开关 // 处理代理开关
// 定义一个异步函数 handleProxyToggle用于处理代理开关的切换
const handleProxyToggle = async (checked: boolean) => { const handleProxyToggle = async (checked: boolean) => {
// 如果开关被选中且电路未准备好,则输出错误信息并返回
if (checked && !isCircuitReady) { if (checked && !isCircuitReady) {
console.error('请先创建电路') console.error('请先创建电路')
return return
} }
// 设置代理加载状态为 true表示正在处理代理开关的切换
setIsProxyLoading(true) setIsProxyLoading(true)
try { try {
// 如果开关被选中,则调用 enableProxy 函数启用代理
if (checked) { if (checked) {
await dispatch(enableProxy()).unwrap() // await dispatch(enableProxy()).unwrap()
} else { } else {
// 如果开关未被选中,则调用 disableProxy 函数禁用代理
await dispatch(disableProxy()).unwrap() await dispatch(disableProxy()).unwrap()
} }
} catch (error) { } catch (error) {
// 如果在启用或禁用代理时发生错误,则输出错误信息
console.error('Proxy toggle failed:', error) console.error('Proxy toggle failed:', error)
} finally { } finally {
// 无论启用或禁用代理是否成功,最后都将代理加载状态设置为 false
setIsProxyLoading(false) setIsProxyLoading(false)
} }
} }

View File

@ -1,10 +1,10 @@
import { useEffect } from "react"; import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { v4 as uuidv4 } from "uuid"; // import { v4 as uuidv4 } from "uuid";
import { commands, ProxyNodeInfo } from "@/bindings"; import { commands, ProxyNodeInfo } from "@/bindings";
import { app } from "@tauri-apps/api"; import { app } from "@tauri-apps/api";
import { createCircuit } from "@/store/circuitSlice"; // import { createCircuit } from "@/store/circuitSlice";
import { setServiceStatus, getProxy, getVersion } from "@/store/serviceSlice"; import { setServiceStatus, getProxy, getVersion } from "@/store/serviceSlice";
import { setNodes, setNodesError, clearNodes } from "@/store/nodesSlice"; import { setNodes, setNodesError, clearNodes } from "@/store/nodesSlice";
import { setProxiesList1 } from "@/store/web3Slice"; import { setProxiesList1 } from "@/store/web3Slice";
@ -267,33 +267,33 @@ export function useStartupCheck() {
// 步骤4检查当前是否开启了代理 // 步骤4检查当前是否开启了代理
await dispatch(getProxy()); await dispatch(getProxy());
// 步骤5检查当前是否有默认链路并且保证状态是正常否则重新创建一个默认链路 // // 步骤5检查当前是否有默认链路并且保证状态是正常否则重新创建一个默认链路
if (!fallbackCircuit || fallbackCircuit?.state === "failed") { // if (!fallbackCircuit || fallbackCircuit?.state === "failed") {
let inbound = ""; // let inbound = "";
let outbound = ""; // let outbound = "";
if (coreResult && coreResult.data && coreResult.data.length > 0) { // if (coreResult && coreResult.data && coreResult.data.length > 0) {
inbound = coreResult.data[0].country_code || ""; // inbound = coreResult.data[0].country_code || "";
outbound = // outbound =
coreResult.data // coreResult.data
.filter((item) => item.exit && item.country_code !== inbound) // .filter((item) => item.exit && item.country_code !== inbound)
?.slice(-1)?.[0].country_code || ""; // ?.slice(-1)?.[0].country_code || "";
// 如果没有这两个那么就跳过,证明核心运行了但是节点是空的,如果只有其中一个,那么证明总共节点就一个无法创建链路 // // 如果没有这两个那么就跳过,证明核心运行了但是节点是空的,如果只有其中一个,那么证明总共节点就一个无法创建链路
if (inbound && outbound) { // if (inbound && outbound) {
await dispatch( // await dispatch(
createCircuit({ // createCircuit({
uid: uuidv4(), // uid: uuidv4(),
name: "系统默认链路", // name: "系统默认链路",
inbound: inbound, // inbound: inbound,
outbound: outbound, // outbound: outbound,
multi_hop: 3, // multi_hop: 3,
fallback: true, // fallback: true,
rule_path: null, // rule_path: null,
is_prefix: false, // is_prefix: false,
}) // })
).unwrap(); // ).unwrap();
} // }
} // }
} // }
// //
// 执行一次完整的状态检查 // 执行一次完整的状态检查

View File

@ -37,11 +37,11 @@ export default function Layout() {
title: "面向溯源对抗的数据转发", title: "面向溯源对抗的数据转发",
icon: <PoolSvg className="w-5 h-5" />, icon: <PoolSvg className="w-5 h-5" />,
}, },
{ // {
id: 'proxies', // id: 'proxies',
title: '节点池', // title: '节点池',
icon: <PoolSvg className="w-5 h-5" />, // icon: <PoolSvg className="w-5 h-5" />,
}, // },
]; ];
const handleClickMenu = (index: number) => { 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 { cn } from "@/lib/utils";
import { import {
setProxyInfoProxies, setProxyInfoProxies,
setProxiesList1, setProxiesList2,
setProxiesList2, setProxiesLine,
setProxiesLine,
} from "@/store/web3Slice"; } from "@/store/web3Slice";
import type { AppDispatch, RootState } from "@/store"; import type { AppDispatch, RootState } from "@/store";
import "./index.scss"; import "./index.scss";
@ -25,274 +24,258 @@ import { DialogConfig, FormAlertDialog } from "./components/FormAlertDialog";
import { ClearNodeDialog } from "./components/ClearNodeDialog"; import { ClearNodeDialog } from "./components/ClearNodeDialog";
export const DIALOGTYPE = { export const DIALOGTYPE = {
ADDNode: { ADDNode: {
title: "添加节点", title: "添加节点",
desc: "", desc: "",
successText: "添加", successText: "添加",
}, },
AddNetwork: { AddNetwork: {
title: "构建网络", title: "构建网络",
desc: "", desc: "",
successText: "构建", successText: "构建",
}, },
}; };
export const NODEDIALOGTYPE = { export const NODEDIALOGTYPE = {
ClearFailNode: { ClearFailNode: {
title: "清除掉线节点", title: "清除掉线节点",
desc: "", desc: "",
successText: "清除", successText: "清除",
}, },
ClearWargingNode: { ClearWargingNode: {
title: "恶意节点", title: "恶意节点",
desc: "", desc: "",
successText: "清除", successText: "清除",
}, },
}; };
const DecentralizedElasticNetwork = () => { const DecentralizedElasticNetwork = () => {
const dispatch = useDispatch<AppDispatch>(); const dispatch = useDispatch<AppDispatch>();
const { web3List, web3List2, proxy_info, path_list, } = useSelector( const { web3List, web3List2, proxy_info, path_list } = useSelector(
(state: RootState) => state.web3Reducer (state: RootState) => state.web3Reducer
); );
const [form] = Form.useForm(); const [form] = Form.useForm();
const [open, setOpen] = useState(false); const [open, setOpen] = useState(false);
const [openNode, setOpenNode] = useState(false); const [openNode, setOpenNode] = useState(false);
const [dialogLoading] = useState(false); const [dialogLoading] = useState(false);
const [type, setType] = useState<DialogConfig>(DIALOGTYPE.ADDNode); const [type, setType] = useState<DialogConfig>(DIALOGTYPE.ADDNode);
const [nodeType, setNodeType] = useState<DialogConfig>( const [nodeType, setNodeType] = useState<DialogConfig>(
NODEDIALOGTYPE.ClearFailNode NODEDIALOGTYPE.ClearFailNode
); );
const newWeb3List = useMemo(() => { const newWeb3List = useMemo(() => {
// 展示最新的6个节点 // 展示最新的6个节点
return web3List.slice(-6); return web3List.slice(-6);
}, [web3List]); }, [web3List]);
const successHandle = async () => { const successHandle = async () => {
await form.validateFields(); await form.validateFields();
const formValue: any = form.getFieldsValue(); const formValue: any = form.getFieldsValue();
if (type.title === DIALOGTYPE.ADDNode.title) { if (type.title === DIALOGTYPE.ADDNode.title) {
console.log(formValue,"formValue") setOpen(false);
setOpen(false); } else {
} else { const { inbound, outbound } = formValue || {};
const { inbound, outbound } = formValue || {}; if (inbound && outbound) {
if (inbound && outbound) { dispatch(
dispatch( setProxyInfoProxies({
setProxyInfoProxies({ country_code: inbound,
country_code: inbound, ingress_country_code: outbound,
ingress_country_code: outbound, })
}) );
); setOpen(false);
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 ICircuitRequest = useMemo(() => { async function handleSelectFile() {
return { try {
open, const selected = await openFile({
setOpen, multiple: false,
successHandle, directory: false,
dialogLoading, filters: [
form, {
type, name: "Excel Files",
canSubmit: true, extensions: ["xlsx", "xls"], // 移除了扩展名前的点号
handleSelectFile, },
}; ],
}, [open, dialogLoading, type, handleSelectFile]); });
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(() => { const nodeSuccessHandle = () => {};
return {
open: openNode,
setOpen: setOpenNode,
successHandle: nodeSuccessHandle,
dialogLoading,
form,
type: nodeType,
canSubmit: true,
};
}, [openNode, dialogLoading, nodeType]);
const screenData = useMemo(() => { const ClearNodeDialogProps = useMemo(() => {
return { return {
path_list, open: openNode,
proxy_info, setOpen: setOpenNode,
}; successHandle: nodeSuccessHandle,
}, [path_list, proxy_info]); dialogLoading,
form,
type: nodeType,
canSubmit: true,
};
}, [openNode, dialogLoading, nodeType]);
// useEffect(() => { const screenData = useMemo(() => {
// dispatch(randomUpdateWeb3List()); return {
// dispatch(randomUpdateWeb3List2()); path_list,
// // 每1.5秒更新一次 proxy_info,
// const interval = setInterval(() => { };
// dispatch(randomUpdateWeb3List()); }, [path_list, proxy_info]);
// dispatch(randomUpdateWeb3List2());
// }, 1500);
// return () => clearInterval(interval); // useEffect(() => {
// }, [dispatch]); // dispatch(randomUpdateWeb3List());
// dispatch(randomUpdateWeb3List2());
// // 每1.5秒更新一次
// const interval = setInterval(() => {
// dispatch(randomUpdateWeb3List());
// dispatch(randomUpdateWeb3List2());
// }, 1500);
return ( // return () => clearInterval(interval);
<div className="decentralized w-full h-full flex flex-col relative"> // }, [dispatch]);
<div className="box"></div>
<div className="w-full flex items-center justify-center relative"> return (
{/* <img <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" className="w-[1693px] h-[271px] absolute top-[160px] left-[50%] translate-x-[-50%] z-10"
src={linePng} src={linePng}
alt="" alt=""
/> */} /> */}
{/* <div className="w-[90%] absolute top-0 left-0"></div> */} {/* <div className="w-[90%] absolute top-0 left-0"></div> */}
<div className="w-[1693px] h-full flex items-center justify-center"> <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="w-[795px] h-full flex items-center justify-end gap-10 z-10">
<div className="carousel-container !justify-end"> <div className="carousel-container !justify-end">
{newWeb3List.map((item, index) => { {newWeb3List.map((item, index) => {
// 随机0-10的整数 // 随机0-10的整数
const randomDelay = const randomDelay = Math.floor(Math.random() * 35) * 1;
Math.floor(Math.random() * 35) * 1; return (
return ( <div
<div className="w-[105px] relative carousel-item"
className="w-[105px] relative carousel-item" key={`${item.height}-${index}`}
key={`${item.id}-${index}`} style={{
style={{ viewTransitionName: `web3-item-1-${index}`,
viewTransitionName: `web3-item-1-${index}`, }}
}} >
> <div className="w-[calc(100%-10px)] h-[calc(100%-10px)] absolute top-[6px] left-[8px] overflow-hidden">
<div className="w-[calc(100%-10px)] h-[calc(100%-10px)] absolute top-[6px] left-[8px] overflow-hidden"> <img
<img className={cn(
className={cn( "!max-w-[186px] h-[160px] relative opacity-50 mix-blend-soft-light z-10"
"!max-w-[186px] h-[160px] relative opacity-50 mix-blend-soft-light z-10" )}
)} style={{
style={{ left: `${-30 - randomDelay}px`,
left: `${ top: `${-30 - randomDelay}px`,
-30 - randomDelay }}
}px`, src={web3BoxGif}
top: `${ />
-30 - randomDelay </div>
}px`, <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>
src={web3BoxGif} <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>
<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} {item.transactions}
</div> */} </div> */}
<div className="text-lg"> <div className="!text-xs">{item?.balanceToFixed} SOL</div>
{item.balance} SOL <div className="!text-xs my-[10px]">
</div> {item.txs.length}
<div className="!text-xs my-[10px]"> </div>
{item.numberTransactions} <div className="!text-sm opacity-60">
</div> {item.timerstamp}
<div className="!text-sm opacity-60"> </div>
{item.upDatedAt}
</div>
</div>
</div>
);
})}
</div>
</div> </div>
<div className="w-fit mt-6 mx-[20px] flex-shrink-0"> </div>
<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"> </div>
<WorldGeo screenData={screenData} /> <div className="w-fit mt-6 mx-[20px] flex-shrink-0">
</div> <VectorSlideSvg />
<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>
<div <div className="w-[795px] h-full flex items-center justify-start gap-10 ">
className="bt1 cursor-pointer" <div className="carousel-container justify-start">
onClick={() => { {web3List2.map((item, index) => {
setType(DIALOGTYPE.ADDNode); const randomDelay = Math.floor(Math.random() * 35) * 1;
setOpen(true); return (
<div
key={`${item.id}-${index}`}
className="w-[105px] relative carousel-item"
style={{
viewTransitionName: `web3-item-2-${index}`,
}} }}
> >
<AddSvg /> <div className="w-[calc(100%-10px)] h-[calc(100%-10px)] absolute top-[6px] left-[8px] overflow-hidden">
<img
</div> className="!max-w-[186px] h-[160px] relative left-[-30px] top-[-30px] opacity-50 mix-blend-soft-light z-10"
{/* <div 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" className="bt1 cursor-pointer"
onClick={() => { onClick={() => {
setType(DIALOGTYPE.AddNetwork); setType(DIALOGTYPE.AddNetwork);
@ -302,40 +285,40 @@ const DecentralizedElasticNetwork = () => {
<InterSvg /> <InterSvg />
</div> */} </div> */}
<div <div
className="bt1 cursor-pointer" className="bt1 cursor-pointer"
onClick={() => { onClick={() => {
dispatch(setProxiesLine()); dispatch(setProxiesLine());
}} }}
> >
<InterSvg /> <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> </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; export default DecentralizedElasticNetwork;

View File

@ -15,7 +15,6 @@ import {
enableProxy, enableProxy,
disableProxy, disableProxy,
} from '@/store/serviceSlice' } from '@/store/serviceSlice'
import { createCircuit } from '@/store/circuitSlice'
import { WebSocketClient } from '@/utils/webSocketClient' import { WebSocketClient } from '@/utils/webSocketClient'
import { ServiceControlPanel } from '@/components/ServiceControlPanel' import { ServiceControlPanel } from '@/components/ServiceControlPanel'
import { useCoreConfig } from '@/hooks/useCoreConfig' import { useCoreConfig } from '@/hooks/useCoreConfig'

View File

@ -31,7 +31,6 @@ import {
getDynamicRouteGeneration, getDynamicRouteGeneration,
getApplicationDiversion, getApplicationDiversion,
} from "@/api/flying-line"; } from "@/api/flying-line";
import { blockChainApi } from "@/api/block";
import { errorToast } from "@/components/GlobalToast"; import { errorToast } from "@/components/GlobalToast";
import { toast } from "@/components/ui/use-toast"; import { toast } from "@/components/ui/use-toast";
import { disableProxy, enableProxy } from "@/store/serviceSlice"; import { disableProxy, enableProxy } from "@/store/serviceSlice";
@ -245,17 +244,6 @@ const NewHome = () => {
if (!isCoreRunning) { if (!isCoreRunning) {
await commands.startCore(); 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); setIsProxyLoading(true);
@ -289,9 +277,6 @@ const NewHome = () => {
}); });
}; };
useEffect(() => { useEffect(() => {
blockChainApi.getLatestBlock().then((res) => {
console.log("getLatestBlock res:", res);
});
initData(); 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%]"> {/* <div className="justify-start text-pink-600 text-2xl font-normal font-['Oswald'] absolute top-[-34px] left-[50%] translate-x-[-50%]">
{item.transactions} {item.transactions}
</div> */} </div> */}
<div className="text-lg">{item.balance} SOL</div> <div className="!text-xs">{item?.balanceToFixed} SOL</div>
<div className="!text-xs my-[10px]"> <div className="!text-xs my-[10px]">
{item.numberTransactions} {item.txs.length}
</div> </div>
<div className="!text-sm opacity-60"> <div className="!text-sm opacity-60">
{item.upDatedAt} {item.timerstamp}
</div> </div>
</div> </div>
</div> </div>
@ -360,7 +344,7 @@ const NewHome = () => {
</div> </div>
<div className="w-[795px] h-full flex items-center justify-start gap-10 "> <div className="w-[795px] h-full flex items-center justify-start gap-10 ">
<div className="carousel-container justify-start"> <div className="carousel-container justify-start">
{web3List2.map((item, index) => { {web3List2.map((item, index) => {
const randomDelay = Math.floor(Math.random() * 35) * 1; const randomDelay = Math.floor(Math.random() * 35) * 1;
return ( return (
<div <div
@ -385,13 +369,12 @@ const NewHome = () => {
className="w-full h-full" 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="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]"> <div className="!text-xs my-[10px]">
{item.numberTransactions} {item.numberTransactions}
</div> </div>
<div className="!text-sm opacity-60"> <div className="!text-sm opacity-60">
{item.upDatedAt} {item.timerstamp}
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,5 +1,5 @@
import { createBrowserRouter, Navigate } from 'react-router-dom' import { createBrowserRouter, Navigate } from 'react-router-dom'
import HomePage from '@/pages/home' // import HomePage from '@/pages/home'
import NewHomePage from '@/pages/new-home' import NewHomePage from '@/pages/new-home'
import DecentralizedElasticNetworkPage from '@/pages/decentralized-lastic-network' import DecentralizedElasticNetworkPage from '@/pages/decentralized-lastic-network'
import AntiForensicsForwardingPage from '@/pages/anti-forensics-forwarding' import AntiForensicsForwardingPage from '@/pages/anti-forensics-forwarding'
@ -35,7 +35,7 @@ export const router = createBrowserRouter([
// }, // },
{ {
path: '/proxies', 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 () => { export const enableProxy = createAsyncThunk('service/enableProxy', async () => {
console.log("开启代理了?")
const result = await commands.enableProxy() const result = await commands.enableProxy()
return result return result
}) })

View File

@ -15,6 +15,10 @@ export interface Iweb3 {
numberTransactions?: string; numberTransactions?: string;
// 交易次数 // 交易次数
transactions?: number | string; transactions?: number | string;
height?: number | string;
txs: any[];
timerstamp?: string;
balanceToFixed?: string | number;
} }
interface Iweb3Slice { interface Iweb3Slice {
@ -65,23 +69,7 @@ const initialState: Iweb3Slice = {
isLine: false, isLine: false,
web3List: [], web3List: [],
web3List2: [ 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: [ path_list: [
{ {
@ -228,58 +216,26 @@ export const appSlice = createSlice({
item.isLine = true; item.isLine = true;
return item; 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) => { setIsLine: (state, action) => {
state.isLine = action.payload; state.isLine = action.payload;
}, },
setWeb3List: (state, action) => { 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) => { setWeb3List2: (state, action) => {
state.web3List2 = action.payload; state.web3List2 = action.payload;