feat: 新增131nodes 接口数据转 proxies 格式
This commit is contained in:
parent
ffabc1ccbe
commit
d220b7b0f5
4
.env
4
.env
@ -1,5 +1,5 @@
|
||||
GRPC_ENDPOINT="156.229.167.121:9090"
|
||||
COSMOS_ENDPOINT="http://156.229.167.121:26657"
|
||||
GRPC_ENDPOINT="10.66.66.234:9090"
|
||||
COSMOS_ENDPOINT="http://10.66.66.234:26657"
|
||||
NODE_SECRET="aHVnZSBjb21wYW55IHBob25lIHdlc3QgcGxhY2Ugc2VtaW5hciBtaXJhY2xlIGxlbmQgbWFuZGF0ZSB0aGVuIGFkanVzdCBxdWl0IG1lYXQgY2hlYXAgbm9vZGxlIGNvdXBsZSBkZWZpbmUgbXVzY2xlIHB1bHNlIHNpc3RlciBwaWVjZSBkZXZpY2UgcHJpdmF0ZSBob29k"
|
||||
IS_DEBUG="true"
|
||||
ACCOUNT_NAME="de1"
|
||||
|
||||
@ -1,64 +0,0 @@
|
||||
|
||||
let __unconfig_data;
|
||||
let __unconfig_stub = function (data = {}) { __unconfig_data = data };
|
||||
__unconfig_stub.default = (data = {}) => { __unconfig_data = data };
|
||||
import { defineConfig } from 'vite'
|
||||
import react from '@vitejs/plugin-react'
|
||||
import AutoImport from 'unplugin-auto-import/vite'
|
||||
import svgr from 'vite-plugin-svgr'
|
||||
import { CodeInspectorPlugin } from 'code-inspector-plugin'
|
||||
|
||||
import path from 'path'
|
||||
|
||||
// const host = process.env.TAURI_DEV_HOST;
|
||||
const host = '127.0.0.1'
|
||||
|
||||
// https://vitejs.dev/config/
|
||||
const __unconfig_default = defineConfig(async () => ({
|
||||
plugins: [
|
||||
react(),
|
||||
AutoImport({
|
||||
dts: './auto-imports.d.ts', //此文件配置保存后系统自动生成
|
||||
imports: [
|
||||
'react', // 自动导入 React
|
||||
],
|
||||
}),
|
||||
svgr({ include: '**/*.svg?react' }),
|
||||
CodeInspectorPlugin({
|
||||
bundler: 'vite',
|
||||
}),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
'@': path.resolve(__dirname, './src'),
|
||||
'package.json': path.resolve(__dirname, './package.json'),
|
||||
},
|
||||
},
|
||||
|
||||
build: {
|
||||
sourcemap: true,
|
||||
},
|
||||
// Vite options tailored for Tauri development and only applied in `tauri dev` or `tauri build`
|
||||
//
|
||||
// 1. prevent vite from obscuring rust errors
|
||||
clearScreen: false,
|
||||
// 2. tauri expects a fixed port, fail if that port is not available
|
||||
server: {
|
||||
port: 1420,
|
||||
strictPort: true,
|
||||
host: host,
|
||||
hmr: host
|
||||
? {
|
||||
protocol: 'ws',
|
||||
host,
|
||||
port: 1421,
|
||||
}
|
||||
: undefined,
|
||||
watch: {
|
||||
// 3. tell vite to ignore watching `src-tauri`
|
||||
ignored: ['**/src-tauri/**'],
|
||||
},
|
||||
},
|
||||
}))
|
||||
|
||||
if (typeof __unconfig_default === "function") __unconfig_default(...[{"command":"serve","mode":"development"}]);export default __unconfig_data;
|
||||
14
src/App.tsx
14
src/App.tsx
@ -9,6 +9,8 @@ import {
|
||||
setProxiesList1,
|
||||
setProxiesList2,
|
||||
setProxiesLine,
|
||||
setMaliciousNodeList,
|
||||
setNodeDownList,
|
||||
} from "@/store/web3Slice";
|
||||
import type { AppDispatch, RootState } from "@/store";
|
||||
|
||||
@ -32,9 +34,9 @@ function App() {
|
||||
const { loadCoreConfig } = useCoreConfig();
|
||||
loadCoreConfig();
|
||||
const dispatch = useDispatch<AppDispatch>();
|
||||
const { web3List, web3List2, proxy_info, path_list } = useSelector(
|
||||
(state: RootState) => state.web3Reducer
|
||||
);
|
||||
// const { } = useSelector(
|
||||
// (state: RootState) => state.web3Reducer
|
||||
// );
|
||||
const webSocketClient = useRef<WebSocketClient | null>();
|
||||
|
||||
const openWsTraffic = async () => {
|
||||
@ -60,10 +62,12 @@ function App() {
|
||||
break;
|
||||
case eventTypes.NODE_DOWN:
|
||||
// 添加下线节点到store 里面
|
||||
dispatch(setNodeDownList(msg.data.name));
|
||||
console.log("节点下线");
|
||||
break;
|
||||
case eventTypes.MALICIOUS_NODE:
|
||||
// 添加恶意节点到store 里面
|
||||
dispatch(setMaliciousNodeList(msg.data.name));
|
||||
console.log("检测到恶意节点");
|
||||
break;
|
||||
case eventTypes.NODE_INIT_COMPLATE:
|
||||
@ -90,13 +94,13 @@ function App() {
|
||||
console.log("节点预配置完成", data);
|
||||
webSocketClient.current?.sendMessage(data);
|
||||
});
|
||||
eventBus.on(eventTypes.NODE_REMOVE, () => {
|
||||
eventBus.on(eventTypes.NODE_REMOVE, (data: any) => {
|
||||
console.log("节点清除");
|
||||
webSocketClient.current?.sendMessage({
|
||||
code: 0,
|
||||
event: eventTypes.NODE_REMOVE,
|
||||
data: {
|
||||
name: "proxy-xxx",
|
||||
name: data,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
BIN
src/assets/image/home/close-proxy.png
Normal file
BIN
src/assets/image/home/close-proxy.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 273 KiB |
@ -1,21 +1,21 @@
|
||||
import { useEffect } from 'react'
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
import { v4 as uuidv4 } from 'uuid'
|
||||
import { useEffect } from "react";
|
||||
import { useDispatch, useSelector } from "react-redux";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
|
||||
import { commands, ProxyNodeInfo } from '@/bindings'
|
||||
import { app } from '@tauri-apps/api'
|
||||
import { createCircuit } from '@/store/circuitSlice'
|
||||
import { setServiceStatus, getProxy, getVersion } from '@/store/serviceSlice'
|
||||
import { setNodes, setNodesError, clearNodes } from '@/store/nodesSlice'
|
||||
// import {} from '@/store/web3Slice'
|
||||
import { commands, ProxyNodeInfo } from "@/bindings";
|
||||
import { app } from "@tauri-apps/api";
|
||||
import { createCircuit } from "@/store/circuitSlice";
|
||||
import { setServiceStatus, getProxy, getVersion } from "@/store/serviceSlice";
|
||||
import { setNodes, setNodesError, clearNodes } from "@/store/nodesSlice";
|
||||
import { setProxiesList1 } from "@/store/web3Slice";
|
||||
|
||||
// import { clearCircuitState } from '@/store/circuitSlice';
|
||||
import { AppDispatch, RootState } from '@/store'
|
||||
import { AppDispatch, RootState } from "@/store";
|
||||
|
||||
interface StartupCheckResult {
|
||||
success: boolean
|
||||
error?: string
|
||||
data?: ProxyNodeInfo[]
|
||||
success: boolean;
|
||||
error?: string;
|
||||
data?: ProxyNodeInfo[];
|
||||
}
|
||||
|
||||
// 重试函数:最多重试指定次数,每次等待指定时间
|
||||
@ -23,27 +23,27 @@ async function retry<T>(
|
||||
operation: () => Promise<T>,
|
||||
maxAttempts: number,
|
||||
delayMs: number,
|
||||
validate: (result: T) => boolean,
|
||||
validate: (result: T) => boolean
|
||||
): Promise<T> {
|
||||
let lastError: Error | undefined
|
||||
let lastError: Error | undefined;
|
||||
|
||||
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
||||
try {
|
||||
const result = await operation()
|
||||
const result = await operation();
|
||||
if (validate(result)) {
|
||||
return result
|
||||
return result;
|
||||
}
|
||||
lastError = new Error(`Validation failed on attempt ${attempt}`)
|
||||
lastError = new Error(`Validation failed on attempt ${attempt}`);
|
||||
} catch (error) {
|
||||
lastError = error instanceof Error ? error : new Error(String(error))
|
||||
lastError = error instanceof Error ? error : new Error(String(error));
|
||||
}
|
||||
|
||||
if (attempt < maxAttempts) {
|
||||
await new Promise((resolve) => setTimeout(resolve, delayMs))
|
||||
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
||||
}
|
||||
}
|
||||
|
||||
throw lastError || new Error('Operation failed after all attempts')
|
||||
throw lastError || new Error("Operation failed after all attempts");
|
||||
}
|
||||
|
||||
// 正常来说,windows下和linux下,使用包管理器更新时安装/卸载服务是足够的,只有macOS下依赖启动检查来安装/卸载服务
|
||||
@ -51,44 +51,44 @@ async function retry<T>(
|
||||
async function checkAndInstallService(): Promise<StartupCheckResult> {
|
||||
try {
|
||||
// 获取当前服务版本和期望版本
|
||||
const versionResult = await commands.getServiceVersion()
|
||||
const expectedVersion = await app.getVersion()
|
||||
const versionResult = await commands.getServiceVersion();
|
||||
const expectedVersion = await app.getVersion();
|
||||
|
||||
// 需要安装/重装的两种情况,分别是
|
||||
// 1. 服务不存在
|
||||
// 2. 服务存在但版本不匹配
|
||||
const serviceNotExists = versionResult.status === 'error'
|
||||
const serviceNotExists = versionResult.status === "error";
|
||||
const versionMismatch =
|
||||
!serviceNotExists && versionResult.data !== expectedVersion
|
||||
!serviceNotExists && versionResult.data !== expectedVersion;
|
||||
|
||||
if (serviceNotExists) {
|
||||
console.log('Service not found, installing...')
|
||||
const installResult = await commands.installService()
|
||||
if (installResult.status === 'error') {
|
||||
console.log("Service not found, installing...");
|
||||
const installResult = await commands.installService();
|
||||
if (installResult.status === "error") {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Failed to install service',
|
||||
}
|
||||
error: "Failed to install service",
|
||||
};
|
||||
}
|
||||
} else if (versionMismatch) {
|
||||
console.log('Service version mismatch, uninstalling old service...')
|
||||
const uninstallResult = await commands.uninstallService()
|
||||
if (uninstallResult.status === 'error') {
|
||||
console.log("Service version mismatch, uninstalling old service...");
|
||||
const uninstallResult = await commands.uninstallService();
|
||||
if (uninstallResult.status === "error") {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Failed to uninstall old service',
|
||||
}
|
||||
error: "Failed to uninstall old service",
|
||||
};
|
||||
}
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000))
|
||||
await new Promise((resolve) => setTimeout(resolve, 5000));
|
||||
|
||||
console.log('Installing new service...')
|
||||
const installResult = await commands.installService()
|
||||
if (installResult.status === 'error') {
|
||||
console.log("Installing new service...");
|
||||
const installResult = await commands.installService();
|
||||
if (installResult.status === "error") {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Failed to install service',
|
||||
}
|
||||
error: "Failed to install service",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,41 +101,41 @@ async function checkAndInstallService(): Promise<StartupCheckResult> {
|
||||
() => commands.getServiceVersion(),
|
||||
10,
|
||||
1000,
|
||||
(result) => result.status === 'ok' && result.data === expectedVersion,
|
||||
)
|
||||
(result) => result.status === "ok" && result.data === expectedVersion
|
||||
);
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Service installation verification failed after retries',
|
||||
}
|
||||
error: "Service installation verification failed after retries",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return { success: true }
|
||||
return { success: true };
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error:
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: 'Unknown error during service check',
|
||||
}
|
||||
: "Unknown error during service check",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async function checkAndStartCore(): Promise<StartupCheckResult> {
|
||||
try {
|
||||
// 检查核心状态
|
||||
let coreStatus = await commands.getNodes()
|
||||
let coreStatus = await commands.getNodes();
|
||||
// 如果核心未运行,尝试启动
|
||||
if (coreStatus.status === 'error') {
|
||||
console.log('Starting core...')
|
||||
const startResult = await commands.restartCore()
|
||||
if (startResult.status === 'error') {
|
||||
if (coreStatus.status === "error") {
|
||||
console.log("Starting core...");
|
||||
const startResult = await commands.restartCore();
|
||||
if (startResult.status === "error") {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Failed to start core',
|
||||
}
|
||||
error: "Failed to start core",
|
||||
};
|
||||
}
|
||||
|
||||
// 等待并验证核心是否成功启动
|
||||
@ -145,166 +145,177 @@ async function checkAndStartCore(): Promise<StartupCheckResult> {
|
||||
() => commands.getNodes(),
|
||||
10,
|
||||
500,
|
||||
(result) => result.status === 'ok',
|
||||
)
|
||||
(result) => result.status === "ok"
|
||||
);
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error: 'Core start verification failed after retries',
|
||||
}
|
||||
error: "Core start verification failed after retries",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
data: coreStatus.status === 'ok' ? coreStatus.data : undefined,
|
||||
}
|
||||
data: coreStatus.status === "ok" ? coreStatus.data : undefined,
|
||||
};
|
||||
} catch (error) {
|
||||
return {
|
||||
success: false,
|
||||
error:
|
||||
error instanceof Error
|
||||
? error.message
|
||||
: 'Unknown error during core check',
|
||||
}
|
||||
: "Unknown error during core check",
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export function useStartupCheck() {
|
||||
const dispatch: AppDispatch = useDispatch()
|
||||
const dispatch: AppDispatch = useDispatch();
|
||||
const { fallbackCircuit } = useSelector(
|
||||
(state: RootState) => state.circuitReducer,
|
||||
)
|
||||
(state: RootState) => state.circuitReducer
|
||||
);
|
||||
// 检查服务和核心状态,同时更新节点信息
|
||||
const checkStatus = async () => {
|
||||
try {
|
||||
const [versionResult, nodesResult] = await Promise.all([
|
||||
commands.getServiceVersion(),
|
||||
commands.getNodes(),
|
||||
])
|
||||
]);
|
||||
|
||||
const suitableServiceVersion = await app.getVersion()
|
||||
const suitableServiceVersion = await app.getVersion();
|
||||
const isServiceInstalled =
|
||||
versionResult.status === 'ok' &&
|
||||
versionResult.data === suitableServiceVersion
|
||||
const isCoreRunning = nodesResult.status === 'ok'
|
||||
versionResult.status === "ok" &&
|
||||
versionResult.data === suitableServiceVersion;
|
||||
const isCoreRunning = nodesResult.status === "ok";
|
||||
|
||||
// 更新服务状态
|
||||
dispatch(
|
||||
setServiceStatus({
|
||||
isServiceInstalled,
|
||||
isCoreRunning,
|
||||
}),
|
||||
)
|
||||
})
|
||||
);
|
||||
|
||||
// 更新节点信息
|
||||
// 只有当核心正在运行时才更新节点
|
||||
if (isCoreRunning) {
|
||||
if (nodesResult.status === 'ok') {
|
||||
dispatch(setNodes(nodesResult.data))
|
||||
if (nodesResult.status === "ok") {
|
||||
console.log("触发了???");
|
||||
const proxies:any[] = [];
|
||||
nodesResult.data.forEach((node,index) => {
|
||||
const { country_code } = node
|
||||
if(nodesResult.data.length-1 === index){
|
||||
return
|
||||
}
|
||||
proxies.push({ country_code: country_code,ingress_country_code: nodesResult.data[index + 1].country_code })
|
||||
})
|
||||
console.log(proxies,'proxiesproxiesproxies')
|
||||
// dispatch(setProxiesList1())
|
||||
dispatch(setNodes(nodesResult.data));
|
||||
} else {
|
||||
dispatch(setNodesError('Failed to fetch nodes'))
|
||||
dispatch(setNodesError("Failed to fetch nodes"));
|
||||
}
|
||||
} else {
|
||||
dispatch(clearNodes())
|
||||
dispatch(clearNodes());
|
||||
// dispatch(clearCircuitState()); // 当核心未运行时清空链路状态
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Status check failed:', error)
|
||||
console.error("Status check failed:", error);
|
||||
dispatch(
|
||||
setServiceStatus({
|
||||
isServiceInstalled: false,
|
||||
isCoreRunning: false,
|
||||
}),
|
||||
)
|
||||
dispatch(clearNodes())
|
||||
})
|
||||
);
|
||||
dispatch(clearNodes());
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
async function performStartupCheck() {
|
||||
try {
|
||||
// 步骤1:检查并安装服务
|
||||
const serviceResult = await checkAndInstallService()
|
||||
const serviceResult = await checkAndInstallService();
|
||||
if (!serviceResult.success) {
|
||||
console.error('Service check failed:', serviceResult.error)
|
||||
console.error("Service check failed:", serviceResult.error);
|
||||
await dispatch(
|
||||
setServiceStatus({
|
||||
isServiceInstalled: false,
|
||||
isCoreRunning: false,
|
||||
}),
|
||||
)
|
||||
await dispatch(clearNodes())
|
||||
return
|
||||
})
|
||||
);
|
||||
await dispatch(clearNodes());
|
||||
return;
|
||||
}
|
||||
|
||||
// 步骤2:检查并启动核心
|
||||
const coreResult = await checkAndStartCore()
|
||||
const coreResult = await checkAndStartCore();
|
||||
if (!coreResult.success) {
|
||||
console.error('Core check failed:', coreResult.error)
|
||||
console.error("Core check failed:", coreResult.error);
|
||||
await dispatch(
|
||||
setServiceStatus({
|
||||
isServiceInstalled: true,
|
||||
isCoreRunning: false,
|
||||
}),
|
||||
)
|
||||
await dispatch(clearNodes())
|
||||
return
|
||||
})
|
||||
);
|
||||
await dispatch(clearNodes());
|
||||
return;
|
||||
}
|
||||
// 步骤3:检查当前核心版本
|
||||
await dispatch(getVersion())
|
||||
await dispatch(getVersion());
|
||||
|
||||
// 步骤4:检查当前是否开启了代理
|
||||
await dispatch(getProxy())
|
||||
await dispatch(getProxy());
|
||||
|
||||
// 步骤5:检查当前是否有默认链路并且保证状态是正常,否则重新创建一个默认链路
|
||||
if (!fallbackCircuit || fallbackCircuit?.state === 'failed') {
|
||||
let inbound = ''
|
||||
let outbound = ''
|
||||
if (!fallbackCircuit || fallbackCircuit?.state === "failed") {
|
||||
let inbound = "";
|
||||
let outbound = "";
|
||||
if (coreResult && coreResult.data && coreResult.data.length > 0) {
|
||||
inbound = coreResult.data[0].country_code || ''
|
||||
inbound = coreResult.data[0].country_code || "";
|
||||
outbound =
|
||||
coreResult.data
|
||||
.filter((item) => item.exit && item.country_code !== inbound)
|
||||
?.slice(-1)?.[0].country_code || ''
|
||||
?.slice(-1)?.[0].country_code || "";
|
||||
// 如果没有这两个那么就跳过,证明核心运行了但是节点是空的,如果只有其中一个,那么证明总共节点就一个无法创建链路
|
||||
if (inbound && outbound) {
|
||||
await dispatch(
|
||||
createCircuit({
|
||||
uid: uuidv4(),
|
||||
name: '系统默认链路',
|
||||
name: "系统默认链路",
|
||||
inbound: inbound,
|
||||
outbound: outbound,
|
||||
multi_hop: 3,
|
||||
fallback: true,
|
||||
rule_path: null,
|
||||
is_prefix: false,
|
||||
}),
|
||||
).unwrap()
|
||||
})
|
||||
).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// 执行一次完整的状态检查
|
||||
await checkStatus()
|
||||
await checkStatus();
|
||||
} catch (error) {
|
||||
console.error('Startup check failed:', error)
|
||||
console.error("Startup check failed:", error);
|
||||
dispatch(
|
||||
setServiceStatus({
|
||||
isServiceInstalled: false,
|
||||
isCoreRunning: false,
|
||||
}),
|
||||
)
|
||||
dispatch(clearNodes())
|
||||
})
|
||||
);
|
||||
dispatch(clearNodes());
|
||||
}
|
||||
}
|
||||
|
||||
// 执行启动自检
|
||||
performStartupCheck()
|
||||
performStartupCheck();
|
||||
|
||||
// 每5秒检查一次状态
|
||||
const intervalId = setInterval(checkStatus, 5000)
|
||||
return () => clearInterval(intervalId)
|
||||
}, [])
|
||||
const intervalId = setInterval(checkStatus, 5000);
|
||||
return () => clearInterval(intervalId);
|
||||
}, []);
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@
|
||||
outline-offset: -0.46px;
|
||||
backdrop-filter: blur(5.50px);
|
||||
|
||||
.close-icon {
|
||||
.close-icon , .close-icon2 {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
position: absolute;
|
||||
|
||||
@ -10,8 +10,10 @@ import NotFailNodeIcon from "@/assets/svg/common/not-fail-node.svg?react";
|
||||
import NotWarningNodeIcon from "@/assets/svg/common/not-warning-node.svg?react";
|
||||
import { NODEDIALOGTYPE } from "../../index";
|
||||
import { cn, getUrl } from "@/lib/utils";
|
||||
import eventBus, { eventTypes } from "@/utils/eventBus";
|
||||
|
||||
import { AppDispatch, RootState } from "@/store";
|
||||
import {removeMaliciousNodeList,removeNodeDownList} from '@/store/web3Slice'
|
||||
import { isTimestampPlusTenMinutesBeforeNow } from "@/utils/tools";
|
||||
|
||||
export interface DialogConfig {
|
||||
@ -69,7 +71,9 @@ export const ClearNodeDialog = ({
|
||||
type: DialogConfig;
|
||||
}) => {
|
||||
const dispatch = useDispatch<AppDispatch>();
|
||||
const {} = useSelector((state: RootState) => state.web3Reducer);
|
||||
const { maliciousNodeList, nodeDownList } = useSelector(
|
||||
(state: RootState) => state.web3Reducer
|
||||
);
|
||||
const [isClear, setIsClear] = useState(false);
|
||||
const showDialog = (open: boolean) => {
|
||||
setOpen(open);
|
||||
@ -78,15 +82,26 @@ export const ClearNodeDialog = ({
|
||||
successHandle();
|
||||
setIsClear(true);
|
||||
if (type.title === NODEDIALOGTYPE.ClearFailNode.title) {
|
||||
nodeDownList.forEach((item)=>{
|
||||
dispatch(removeNodeDownList(item.name));
|
||||
eventBus.emit(eventTypes.NODE_REMOVE, item.name);
|
||||
})
|
||||
} else if (type.title === NODEDIALOGTYPE.ClearWargingNode.title) {
|
||||
maliciousNodeList.forEach((item)=>{
|
||||
dispatch(removeMaliciousNodeList(item.name));
|
||||
eventBus.emit(eventTypes.NODE_REMOVE, item.name);
|
||||
})
|
||||
}
|
||||
// showDialog(false);
|
||||
};
|
||||
|
||||
const proxyList = useMemo(() => {
|
||||
// 随机 2-9条 nodelist里面的数据
|
||||
return [];
|
||||
}, [nodeList, open, isClear, type]);
|
||||
if (type.title === NODEDIALOGTYPE.ClearFailNode.title) {
|
||||
return nodeDownList;
|
||||
} else {
|
||||
return maliciousNodeList;
|
||||
}
|
||||
}, [nodeDownList, maliciousNodeList, type.title]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) {
|
||||
@ -112,7 +127,7 @@ export const ClearNodeDialog = ({
|
||||
}
|
||||
>
|
||||
<div className="flex flex-wrap gap-3">
|
||||
{proxyList.length > 0 ? (
|
||||
{proxyList?.length > 0 ? (
|
||||
proxyList.map((item) => {
|
||||
return <ProxyItem proxyInfo={item} key={item.name} />;
|
||||
})
|
||||
|
||||
@ -51,7 +51,7 @@ export const NODEDIALOGTYPE = {
|
||||
};
|
||||
const DecentralizedElasticNetwork = () => {
|
||||
const dispatch = useDispatch<AppDispatch>();
|
||||
const { web3List, web3List2, proxy_info, path_list } = useSelector(
|
||||
const { web3List, web3List2, proxy_info, path_list, } = useSelector(
|
||||
(state: RootState) => state.web3Reducer
|
||||
);
|
||||
|
||||
|
||||
@ -181,20 +181,20 @@ function Home() {
|
||||
}
|
||||
}
|
||||
// 如果代理未启用且链路未就绪,创建默认链路
|
||||
if (!isProxyEnabled && !isCircuitReady) {
|
||||
await dispatch(
|
||||
createCircuit({
|
||||
uid: uuidv4(),
|
||||
name: '系统默认链路',
|
||||
inbound: countries[0],
|
||||
outbound: exitCountries[exitCountries.length - 1],
|
||||
multi_hop: 3,
|
||||
fallback: true,
|
||||
rule_path: null,
|
||||
is_prefix: false,
|
||||
}),
|
||||
).unwrap()
|
||||
}
|
||||
// if (!isProxyEnabled && !isCircuitReady) {
|
||||
// await dispatch(
|
||||
// createCircuit({
|
||||
// uid: uuidv4(),
|
||||
// name: '系统默认链路',
|
||||
// inbound: countries[0],
|
||||
// outbound: exitCountries[exitCountries.length - 1],
|
||||
// multi_hop: 3,
|
||||
// fallback: true,
|
||||
// rule_path: null,
|
||||
// is_prefix: false,
|
||||
// }),
|
||||
// ).unwrap()
|
||||
// }
|
||||
|
||||
setIsProxyLoading(true)
|
||||
|
||||
|
||||
@ -106,6 +106,7 @@ export const WorldGeo = memo(
|
||||
}, [dataInfo, selectedApp]);
|
||||
// 创建自定义提示框DOM元素
|
||||
const createCustomTooltip = () => {
|
||||
console.log("createCustomTooltip")
|
||||
// 如果已经存在自定义提示框,则移除它
|
||||
if (document.getElementById("custom-fixed-tooltip")) {
|
||||
document.getElementById("custom-fixed-tooltip")?.remove();
|
||||
@ -206,7 +207,7 @@ export const WorldGeo = memo(
|
||||
<div class="tip-box">
|
||||
<div>
|
||||
<div class="label" style="color: white; font-weight: bold;">流量混淆</div>
|
||||
<img class="close-icon" src="${getUrl(
|
||||
<img class="close-icon2" src="${getUrl(
|
||||
"svg/Xwhite.svg"
|
||||
)}" alt=""
|
||||
style="cursor: pointer; " />
|
||||
@ -224,11 +225,11 @@ export const WorldGeo = memo(
|
||||
document.body.appendChild(tooltip);
|
||||
customTooltip2Ref.current = tooltip;
|
||||
// 添加关闭按钮事件
|
||||
const closeButton = tooltip.querySelector(".close-icon");
|
||||
const closeButton = tooltip.querySelector(".close-icon2");
|
||||
if (closeButton) {
|
||||
closeButton.addEventListener("click", () => {
|
||||
setTooltipClosed(false);
|
||||
tooltip.remove();
|
||||
customTooltip2Ref.current?.remove();
|
||||
customTooltip2Ref.current = null;
|
||||
});
|
||||
}
|
||||
@ -1142,11 +1143,6 @@ export const WorldGeo = memo(
|
||||
if (tooltipClosed) {
|
||||
createCustomTooltip();
|
||||
createCustomTooltip2();
|
||||
} else {
|
||||
customTooltipRef.current?.remove();
|
||||
customTooltip2Ref.current?.remove();
|
||||
customTooltipRef.current = null;
|
||||
customTooltip2Ref.current = null;
|
||||
}
|
||||
return () => {
|
||||
customTooltipRef.current?.remove();
|
||||
|
||||
@ -7,11 +7,13 @@ 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 OpenProxyPng from "@/assets/image/home/open-proxy.png";
|
||||
import CloseProxyPng from "@/assets/image/home/close-proxy.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 {
|
||||
setProxyInfoProxies,
|
||||
@ -30,6 +32,9 @@ import {
|
||||
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";
|
||||
|
||||
export const DIALOGTYPE = {
|
||||
ADDNode: {
|
||||
@ -61,7 +66,10 @@ const NewHome = () => {
|
||||
const { web3List, web3List2 } = useSelector(
|
||||
(state: RootState) => state.web3Reducer
|
||||
);
|
||||
|
||||
const { isProxyEnabled, isCoreRunning } = useSelector(
|
||||
(state: RootState) => state.serviceReducer
|
||||
);
|
||||
const [isProxyLoading, setIsProxyLoading] = useState(false);
|
||||
const [form] = Form.useForm();
|
||||
const [open, setOpen] = useState(false);
|
||||
const [openNode, setOpenNode] = useState(false);
|
||||
@ -226,6 +234,45 @@ const NewHome = () => {
|
||||
});
|
||||
}, [dataInfo.applicationDiversion]);
|
||||
|
||||
// 处理代理开关
|
||||
const handleProxyToggle = async (
|
||||
isProxyEnabled: boolean,
|
||||
isCoreRunning: boolean
|
||||
) => {
|
||||
if (isProxyLoading) return;
|
||||
try {
|
||||
// 如果核心未运行,先启动核心
|
||||
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);
|
||||
|
||||
// 切换代理状态
|
||||
await dispatch(isProxyEnabled ? disableProxy() : enableProxy()).unwrap();
|
||||
} catch (error) {
|
||||
console.log(error, "error");
|
||||
const errorMessage = isProxyEnabled
|
||||
? "关闭代理失败!"
|
||||
: "开启代理失败,请检查节点配置、或重新尝试开启";
|
||||
errorToast(errorMessage, toast);
|
||||
console.error("Proxy toggle failed:", error);
|
||||
} finally {
|
||||
setIsProxyLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
const initData = async () => {
|
||||
const passAuthentication = await getPassAuthentication();
|
||||
const trafficObfuscation = await getTrafficObfuscation();
|
||||
@ -365,9 +412,12 @@ const NewHome = () => {
|
||||
</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">
|
||||
<img
|
||||
src={OpenProxyPng}
|
||||
src={isProxyEnabled ? CloseProxyPng : OpenProxyPng}
|
||||
className="w-[193px] h-[90px] cursor-pointer"
|
||||
alt=""
|
||||
onClick={() => {
|
||||
handleProxyToggle(isProxyEnabled, isCoreRunning);
|
||||
}}
|
||||
/>
|
||||
{/* <div
|
||||
className="bt1 cursor-pointer"
|
||||
|
||||
@ -24,6 +24,8 @@ interface Iweb3Slice {
|
||||
path_list: any;
|
||||
proxy_info: any;
|
||||
isLine: boolean;
|
||||
maliciousNodeList: any[]; // 恶意节点
|
||||
nodeDownList: any[]; // 节点下线
|
||||
}
|
||||
|
||||
// 随机生成 0-100 之间的数字,保留一位小数或整数
|
||||
@ -147,21 +149,56 @@ const initialState: Iweb3Slice = {
|
||||
name: "newHomeProxies",
|
||||
},
|
||||
],
|
||||
maliciousNodeList: [], // 恶意节点
|
||||
nodeDownList: [], // 节点下线
|
||||
};
|
||||
|
||||
export const appSlice = createSlice({
|
||||
name: "web3",
|
||||
initialState,
|
||||
reducers: {
|
||||
setProxiesList1: (state) => {
|
||||
removeMaliciousNodeList: (state, action) => {
|
||||
state.maliciousNodeList = state.maliciousNodeList.filter(
|
||||
(item) => item !== action.payload
|
||||
);
|
||||
},
|
||||
removeNodeDownList: (state, action) => {
|
||||
state.nodeDownList = state.nodeDownList.filter(
|
||||
(item) => item !== action.payload
|
||||
);
|
||||
},
|
||||
setMaliciousNodeList: (state, action) => {
|
||||
// 判断当前节点是否已经存在
|
||||
const maliciousNode = state.maliciousNodeList.find(
|
||||
(item) => action.payload === item
|
||||
);
|
||||
if (!maliciousNode) {
|
||||
state.maliciousNodeList.push(action.payload);
|
||||
}
|
||||
},
|
||||
setNodeDownList: (state, action) => {
|
||||
// 判断当前节点是否已经存在
|
||||
const nodeDown = state.nodeDownList.find(
|
||||
(item) => action.payload === item
|
||||
);
|
||||
if (!nodeDown) {
|
||||
state.nodeDownList.push(action.payload);
|
||||
}
|
||||
},
|
||||
setProxiesList1: (state, action) => {
|
||||
// state.proxy_info.prox
|
||||
// 判断是否已经存在
|
||||
const proxies = state.proxy_info.proxies.find(
|
||||
(item: any) => item.name === "data1"
|
||||
);
|
||||
if (!proxies) {
|
||||
state.proxy_info.proxies.push(data1);
|
||||
const proxy_info = state.proxy_info;
|
||||
if (proxy_info.proxies.length === 0) {
|
||||
proxy_info.proxies.push({
|
||||
name: "data1",
|
||||
isLine: false,
|
||||
data: action.payload,
|
||||
});
|
||||
} else {
|
||||
proxy_info.proxies[0] = action.payload;
|
||||
}
|
||||
state.proxy_info = proxy_info;
|
||||
},
|
||||
setProxiesList2: (state) => {
|
||||
// state.proxy_info.prox
|
||||
@ -233,7 +270,6 @@ export const appSlice = createSlice({
|
||||
|
||||
// 更新状态
|
||||
state.web3List = [...state.web3List, ...newWallets];
|
||||
console.log(state.web3List, "state.web3List");
|
||||
}
|
||||
},
|
||||
setIsLine: (state, action) => {
|
||||
@ -265,6 +301,10 @@ export const appSlice = createSlice({
|
||||
});
|
||||
|
||||
export const {
|
||||
removeMaliciousNodeList,
|
||||
removeNodeDownList,
|
||||
setMaliciousNodeList,
|
||||
setNodeDownList,
|
||||
setWeb3List,
|
||||
setWeb3List2,
|
||||
setProxyInfoProxies,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user