paw-gui/src/App.tsx
2025-05-07 17:15:41 +08:00

332 lines
9.4 KiB
TypeScript

import { useEffect, useRef } from "react";
import dayjs from "dayjs";
import { useStartupCheck } from "@/hooks/useStartupCheck";
import { usePreventDefault } from "@/hooks/usePreventDefaultEventListener";
import { useGlobalShortcut } from "@/hooks/useGlobalShortcut";
import { useRecreateTheCircuit } from "@/hooks/useRecreateTheCircuit";
import { useCoreConfig } from "@/hooks/useCoreConfig";
import { useDispatch } from "react-redux";
import {
setMaliciousNodeList,
setNodeDownList,
setWeb3List,
setWeb3List2,
} from "@/store/web3Slice";
import type { AppDispatch } from "@/store";
import eventBus, { eventTypes } from "@/utils/eventBus";
import { WebSocketClient } from "@/utils/webSocketClientV2";
import { blockChainApi } from "@/api/block";
import { getRandomCountryKey } from "@/data";
import Titlebar from "@/components/Titlebar";
import Layout from "@/layout";
import Tray from "@/components/Tray";
function App() {
// 执行启动自检
useStartupCheck();
// 阻止默认事件
usePreventDefault();
// 注册全局快捷方式
useGlobalShortcut();
// 当核心启动时重新创建电路
useRecreateTheCircuit();
// 读取配置,若文件不存在则持久化到本地 `%APPDATA%/com.paw.paw-gui`
const { loadCoreConfig } = useCoreConfig();
loadCoreConfig();
const dispatch = useDispatch<AppDispatch>();
const eventsWsRef = useRef<WebSocketClient | null>(null);
const blockchainTimerRef = useRef<NodeJS.Timeout | null>(null);
const wsInitializedRef = useRef<boolean>(false);
// 处理 WebSocket 消息
const handleWebSocketMessage = (msg: any) => {
try {
const msgData = msg ? JSON.parse(msg.data) : {};
console.log("Received WebSocket message:", msgData);
if (msgData?.code === 0) {
switch (msgData.event) {
case eventTypes.NODE_UP:
console.log("节点上线");
break;
case eventTypes.NODE_DOWN:
// 添加下线节点到store 里面
if (msgData.data.name) {
// 获取一个随机的国家code
const countryCode = getRandomCountryKey();
dispatch(
setNodeDownList({
name: msgData.data.name,
code: countryCode,
})
);
}
console.log("节点下线");
break;
case eventTypes.MALICIOUS_NODE:
// 添加恶意节点到store 里面
if (msgData.data.name) {
// 获取一个随机的国家code
const countryCode = getRandomCountryKey();
dispatch(
setMaliciousNodeList({
name: msgData.data.name,
code: countryCode,
})
);
}
console.log("检测到恶意节点");
break;
case eventTypes.NODE_INIT_COMPLATE:
if (eventsWsRef.current?.isWebSocketConnected()) {
eventsWsRef.current.sendMessage(
JSON.stringify({
...msgData,
event: eventTypes.NODE_ADD,
})
);
console.log("节点预配置完成:", {
...msgData,
event: eventTypes.NODE_ADD,
});
}
break;
case eventTypes.NODE_REMOVE:
console.log("节点清除");
break;
case eventTypes.NODE_ADD:
console.log("添加节点");
break;
default:
break;
}
}
} catch (error) {
console.error("Error processing WebSocket message:", error);
}
};
// 初始化 WebSocket 连接
const initWebSocket = async () => {
if (eventsWsRef.current) return;
console.log("Initializing WebSocket connection...");
eventsWsRef.current = new WebSocketClient(
"ws://47.82.97.10:8080/events",
{},
{
autoReconnect: true,
maxReconnectAttempts: 10,
reconnectDelay: 2000,
}
);
const connected = await eventsWsRef.current.connect();
if (connected) {
console.log("WebSocket connected successfully");
eventsWsRef.current.addListener(handleWebSocketMessage);
wsInitializedRef.current = true;
} else {
console.error("Failed to establish WebSocket connection");
}
};
// 设置事件总线监听器
const setupEventBusListeners = () => {
console.log("执行了没")
// 添加节点
eventBus.on(eventTypes.NODE_ADD, (data: any) => {
console.log("添加节点", data);
if (eventsWsRef.current?.isWebSocketConnected()) {
const timestamp = dayjs().unix();
const params = {
code: 0,
event: eventTypes.NODE_ADD,
data: data,
timestamp,
};
eventsWsRef.current.sendMessage(JSON.stringify(params));
} else {
console.warn("WebSocket not connected, can't send NODE_ADD message");
}
});
// 节点预配置事件
eventBus.on(eventTypes.NODE_INIT, (data: any) => {
console.log("节点预配置", data);
if (eventsWsRef.current?.isWebSocketConnected()) {
const timestamp = dayjs().unix();
const params = {
code: 0,
event: "node_init",
data: {},
timestamp: timestamp,
};
eventsWsRef.current.sendMessage(JSON.stringify(params));
} else {
console.warn("WebSocket not connected, can't send NODE_INIT message");
}
});
// 节点清除事件
eventBus.on(eventTypes.NODE_REMOVE, (data: any) => {
console.log("节点清除", data);
if (eventsWsRef.current?.isWebSocketConnected()) {
const timestamp = dayjs().unix();
const params = {
code: 0,
event: eventTypes.NODE_REMOVE,
data: {
name: data,
},
timestamp,
};
eventsWsRef.current.sendMessage(JSON.stringify(params));
} else {
console.warn("WebSocket not connected, can't send NODE_REMOVE message");
}
});
};
// 清理事件总线监听器
const cleanupEventBusListeners = () => {
eventBus.off(eventTypes.NODE_INIT);
eventBus.off(eventTypes.NODE_REMOVE);
};
// 启动区块链数据轮询
const startBlockchainPolling = () => {
// 立即执行一次
fetchBlockchainData();
// 设置定时器定期获取数据
blockchainTimerRef.current = setInterval(fetchBlockchainData, 5000);
};
// 获取区块链数据
const fetchBlockchainData = async () => {
try {
const blockRes = await blockChainApi.getLatestBlock();
const height = blockRes.data.block.last_commit.height;
const txsRes = await blockChainApi.getTxsByBlock(height);
const timer = txsRes.data.block.header.time;
const txs = txsRes.data.txs;
const balance = txs.reduce((acc: number, 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),
};
dispatch(setWeb3List(item));
} catch (error) {
console.error("Error fetching blockchain data:", error);
}
};
// 初始化所有服务
const initializeServices = async () => {
// 初始化示例数据
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: 1204,
timerstamp: dayjs().format("HH:mm:ss"),
balanceToFixed: 0,
},
])
);
// 初始化 WebSocket
await initWebSocket();
// 设置事件总线
setupEventBusListeners();
// 启动区块链数据轮询
startBlockchainPolling();
};
// 清理所有资源
const cleanupServices = () => {
// 清理区块链数据轮询
if (blockchainTimerRef.current) {
clearInterval(blockchainTimerRef.current);
blockchainTimerRef.current = null;
}
// 清理事件总线
cleanupEventBusListeners();
// 关闭 WebSocket 连接
if (eventsWsRef.current) {
eventsWsRef.current.disconnect();
eventsWsRef.current = null;
}
wsInitializedRef.current = false;
};
useEffect(() => {
// 延迟初始化以确保组件完全挂载
const initTimer = setTimeout(() => {
initializeServices();
}, 1000);
// 组件卸载时清理资源
return () => {
clearTimeout(initTimer);
cleanupServices();
console.log("App component unmounted, all services cleaned up");
};
}, []);
return (
<main>
<Titlebar />
<Layout />
<Tray />
</main>
);
}
export default App;