2025-05-07 14:43:04 +08:00

368 lines
13 KiB
TypeScript

import { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { WorldGeo } from "./components/world-geo";
import Web3BoxPng from "@/assets/image/home/web3-box.png";
import Web3Box2Png from "@/assets/image/home/web3-box2.png";
import web3BoxGif from "@/assets/gif/web3-box-bg.gif";
import VectorSlideSvg from "@/assets/svg/home/vector-solide.svg?react";
import { Apps, CONST_TOOLTIP_TYPE } from "@/pages/anti-forensics-forwarding";
import { cn } from "@/lib/utils";
import { commands } from "@/bindings";
import type { AppDispatch, RootState } from "@/store";
import "./index.scss";
import {
getPassAuthentication,
getTrafficObfuscation,
getNestedEncryption,
getDynamicRouteGeneration,
getApplicationDiversion,
} from "@/api/flying-line";
import { errorToast } from "@/components/GlobalToast";
import { toast } from "@/components/ui/use-toast";
import { disableProxy, enableProxy } from "@/store/serviceSlice";
export const DIALOGTYPE = {
ADDNode: {
title: "添加节点",
desc: "",
successText: "添加",
},
AddNetwork: {
title: "构建网络",
desc: "",
successText: "构建",
},
};
export const NODEDIALOGTYPE = {
ClearFailNode: {
title: "清除掉线节点",
desc: "",
successText: "清除",
},
ClearWargingNode: {
title: "恶意节点",
desc: "",
successText: "清除",
},
};
const NewHome = () => {
const dispatch = useDispatch<AppDispatch>();
const { web3List, web3List2 } = useSelector(
(state: RootState) => state.web3Reducer
);
const { isProxyEnabled, isCoreRunning } = useSelector(
(state: RootState) => state.serviceReducer
);
const [isProxyLoading, setIsProxyLoading] = useState(false);
const [selectedApp, setSelectedApp] = useState<any>(null);
const [tooltipClosed, setTooltipClosed] = useState(true);
const [tooltipType, setTooltipType] = useState(
CONST_TOOLTIP_TYPE.NESTED_ENCRYPTION.type
);
// 模拟日志数据
const [nestedEncryptionLogs, setNestedEncryptionLogs] = useState<string[]>(
[]
);
const [trafficObfuscationLogs, setTrafficObfuscationLogs] = useState<
string[]
>([]);
const newWeb3List = useMemo(() => {
// 展示最新的6个节点
return web3List.slice(-6);
}, [web3List]);
const handleClickApp = (item: any) => {
setSelectedApp(item);
};
const [dataInfo, setDataInfo] = useState<any>({
passAuthentication: {
type: "PASS_AUTHENTICATION",
name: "通信认证",
startPoint: "GL",
endPoint: "CA",
authenticationPoint: [
[-103.346771, 54.130366],
[-120.346771, 52.130366],
[-108.346771, 48.130366],
[-98.346771, 46.130366],
[-106.346771, 48.450366],
[-101.346771, 53.130366],
[-123.346771, 58.130366],
[-111.346771, 65.443366],
[-108.346771, 54.130366],
[-116.346771, 59.130366],
[-97.346771, 61.130366],
[-95.346771, 63.130366],
[-113.346771, 58.840366],
[-99.346771, 59.130366],
[-102.346771, 68.130366],
],
data: [
{
country_code: "gl",
ingress_country_code: "dz",
},
{
country_code: "br",
ingress_country_code: "dz",
},
{
country_code: "dz",
ingress_country_code: "ru",
},
{
country_code: "dz",
ingress_country_code: "cn",
},
{
country_code: "ru",
ingress_country_code: "za",
},
],
isLine: true,
},
trafficObfuscation: [],
nestedEncryption: [],
dynamicRouteGeneration: [],
applicationDiversion: [],
});
const appDiversion = useMemo(() => {
return Apps.map((item) => {
const findApp = dataInfo.applicationDiversion.find(
(appItem: any) => item.name === appItem.name
);
return {
...item,
...findApp,
};
});
}, [dataInfo.applicationDiversion]);
// 处理代理开关
const handleProxyToggle = useCallback(
async (isProxyEnabled: boolean, isCoreRunning: boolean) => {
// console.log(isProxyLoading, "isProxyLoadingisProxyLoading");
if (isProxyLoading) return;
try {
// 如果核心未运行,先启动核心
if (!isCoreRunning) {
await commands.startCore();
}
setIsProxyLoading(true);
// 切换代理状态
await dispatch(isProxyEnabled ? disableProxy() : enableProxy()).unwrap();
setIsProxyLoading(false);
console.log(`Proxy ${isProxyEnabled ? "关闭成功" : "开启成功"}`);
} catch (error) {
const errorMessage = isProxyEnabled
? "关闭代理失败!"
: "开启代理失败,请检查节点配置、或重新尝试开启";
errorToast(errorMessage, toast);
console.error("Proxy toggle failed:", error);
} finally {
setIsProxyLoading(false);
}
},
[dispatch, isProxyLoading, isCoreRunning, isProxyEnabled]
);
const initData = async () => {
const passAuthentication = await getPassAuthentication();
const trafficObfuscation = await getTrafficObfuscation();
const nestedEncryption = await getNestedEncryption();
const applicationDiversion = await getApplicationDiversion();
const dynamicRouteGeneration = await getDynamicRouteGeneration();
setNestedEncryptionLogs(nestedEncryption.logs);
setTrafficObfuscationLogs(trafficObfuscation.logs);
setDataInfo({
passAuthentication: passAuthentication.data,
trafficObfuscation: [trafficObfuscation.data],
nestedEncryption: [nestedEncryption.data],
applicationDiversion: applicationDiversion.data,
dynamicRouteGeneration: dynamicRouteGeneration.data,
});
};
useEffect(() => {
initData();
}, []);
// useEffect(() => {
// console.log(dataInfo, "awaidataInfodataInfotawait");
// }, [dataInfo]);
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] flex items-center justify-end gap-10 z-[99]">
<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%]">
{item.transactions}
</div> */}
{/* <div className="!text-xs">{item?.balanceToFixed} SOL</div> */}
<div className="!text-xs my-[6px]">#{item.height}</div>
<div className="!text-xs opacity-60 mb-[6px]">
{item.timerstamp}
</div>
<div className="!text-xs opacity-60">
{item.txs.length}
</div>
</div>
</div>
);
})}
</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-xs my-[6px]">#{item.height}</div>
<div className="!text-xs opacity-60 mb-[6px]">
{item.timerstamp}
</div>
<div className="!text-xs opacity-60">
{item.numberTransactions}
</div>
</div>
</div>
);
})}
</div>
</div>
</div>
</div>
<div className="mt-2 w-full h-full flex-1">
<WorldGeo
dataInfo={dataInfo}
nestedEncryptionLogs={nestedEncryptionLogs}
trafficObfuscationLogs={trafficObfuscationLogs}
selectedApp={selectedApp}
tooltipType={tooltipType}
tooltipClosed={tooltipClosed}
setTooltipClosed={setTooltipClosed}
/>
</div>
<div className="absolute bottom-[10px] left-[50%] translate-x-[-50%] w-[calc(100%-51px)] p-6 inline-flex justify-start items-center gap-10">
<div
className="flex items-center justify-center w-[193px] h-[80px] cursor-pointer bg-[#1448F5] rounded-[40px] text-white text-lg font-medium"
onClick={() => {
handleProxyToggle(isProxyEnabled, isCoreRunning);
}}
>
{isProxyEnabled ? "关闭匿名服务" : "开启匿名服务"}
</div>
{/* <div
className="bt1 cursor-pointer"
onClick={() => {
setTooltipType(
CONST_TOOLTIP_TYPE.NESTED_ENCRYPTION.type
);
setTooltipClosed(true);
}}
>
嵌套加密
</div>
<div
className="bt1 cursor-pointer"
onClick={() => {
setTooltipType(
CONST_TOOLTIP_TYPE.TRAFFIC_OBFUSCATION.type
);
setTooltipClosed(true);
}}
>
流量混淆
</div> */}
{appDiversion.map((item) => {
return (
<div
key={item.name}
className="flex items-center justify-center w-16 h-16 relative rounded-[4.95px] shadow-[0px_0px_3.299999952316284px_0px_rgba(84,87,255,1.00)] outline outline-[0.50px] outline-offset-[-0.50px] outline-indigo-50/60 overflow-hidden"
onClick={() => handleClickApp(item)}
>
{selectedApp?.name === item?.name ? (
<item.activeIcon />
) : (
<item.icon />
)}
</div>
);
})}
</div>
</div>
);
};
export default NewHome;