mirror of
https://github.com/EasyTier/EasytierGame.git
synced 2025-05-19 10:27:56 +00:00
自建服务器单独重写,成员列表新增断开连接判断,联机增加断开联机的检测
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
import useMainStore from "@/stores/index";
|
||||
export const getServerArgs = () => {
|
||||
const mainStore = useMainStore();
|
||||
const args = [];
|
||||
if (!mainStore.serverConfig.port) {
|
||||
mainStore.serverConfig.port = "11010";
|
||||
}
|
||||
args.push("-l", mainStore.serverConfig.port);
|
||||
if (mainStore.serverConfig.relayAllPeerrpc) {
|
||||
args.push("--relay-all-peer-rpc");
|
||||
}
|
||||
const whiteList = mainStore.serverConfig.serverWhiteList
|
||||
.trim()
|
||||
.split("\n")
|
||||
.map(el => el.trim())
|
||||
.filter(el => el)
|
||||
.join(" ");
|
||||
if (whiteList && mainStore.serverConfig.enableWhiteList) {
|
||||
args.push("--relay-network-whitelist", whiteList);
|
||||
}
|
||||
if (!whiteList && mainStore.serverConfig.enableWhiteList) {
|
||||
args.push("--relay-network-whitelist");
|
||||
}
|
||||
return args;
|
||||
};
|
||||
+102
-101
@@ -179,80 +179,6 @@
|
||||
</ElFormItem>
|
||||
</div>
|
||||
</ElForm>
|
||||
<!-- <ElForm
|
||||
v-else
|
||||
size="small"
|
||||
label-position="top"
|
||||
class="flex-1 overflow-hidden pb-[5px]"
|
||||
:model="config"
|
||||
>
|
||||
<ElFormItem
|
||||
label="白名单"
|
||||
prop="ServerWhiteList"
|
||||
class="full-label full-content overflow-hidden !flex flex-col h-full !mb-[0]"
|
||||
>
|
||||
<template #label>
|
||||
<div class="flex items-center flex-nowrap gap-[0_5px]">
|
||||
<div>白名单</div>
|
||||
<span>-</span>
|
||||
<ElTag
|
||||
effect="dark"
|
||||
:type="data.isStart ? 'success' : 'info'"
|
||||
>
|
||||
{{ data.isSuccessGetIp ? "运行成功" : data.isStart && !data.isSuccessGetIp ? "运行中" : "未启动" }}
|
||||
</ElTag>
|
||||
<ElButton
|
||||
v-if="!data.coreVersion"
|
||||
@click="getCoreVersion(true)"
|
||||
>
|
||||
获取内核版本
|
||||
</ElButton>
|
||||
<div
|
||||
v-else
|
||||
class="flex-1 truncate"
|
||||
>
|
||||
<ElTooltip :content="data.coreVersion">
|
||||
<ElTag type="info">
|
||||
{{ data.coreVersion }}
|
||||
</ElTag>
|
||||
</ElTooltip>
|
||||
</div>
|
||||
<ElButton
|
||||
class="ml-auto"
|
||||
:disabled="data.isStart"
|
||||
@click="handleCoreManagement"
|
||||
:loading="data.update"
|
||||
type="primary"
|
||||
size="small"
|
||||
>
|
||||
内核管理
|
||||
</ElButton>
|
||||
</div>
|
||||
</template>
|
||||
<div class="h-full w-full flex flex-col overflow-hidden">
|
||||
<div class="flex-1 overflow-auto">
|
||||
<ElInput
|
||||
:disabled="!mainStore.enableWhiteList"
|
||||
placeholder="一行一个,支持通配符列表,如(ab*)。当该参数的列表为空时,就不会为所有其他网络提供转发服务。"
|
||||
:maxlength="1000"
|
||||
v-model="mainStore.ServerWhiteList"
|
||||
type="textarea"
|
||||
:autosize="{
|
||||
minRows: 9
|
||||
}"
|
||||
resize="none"
|
||||
></ElInput>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<ElCheckbox v-model="mainStore.enableWhiteList">启用白名单</ElCheckbox>
|
||||
<ElCheckbox v-model="mainStore.config.relayAllPeerrpc">转发所有对等节点的RPC数据包</ElCheckbox>
|
||||
<ElTooltip content="帮助其他虚拟网建立P2P链接">
|
||||
<ElIcon><QuestionFilled /></ElIcon>
|
||||
</ElTooltip>
|
||||
</div>
|
||||
</div>
|
||||
</ElFormItem>
|
||||
</ElForm> -->
|
||||
<div class="flex items-start mt-auto">
|
||||
<div>
|
||||
<div>
|
||||
@@ -287,7 +213,7 @@
|
||||
:icon="SetUp"
|
||||
command="create_server"
|
||||
>
|
||||
我要开服(自建)
|
||||
自建服务({{ listenObj.server_thread_id.value ? "运行中" : "未运行" }})
|
||||
</ElDropdownItem>
|
||||
<ElDropdownItem
|
||||
:icon="Tools"
|
||||
@@ -552,7 +478,7 @@
|
||||
import { listen } from "@tauri-apps/api/event";
|
||||
import { open, Command } from "@tauri-apps/plugin-shell";
|
||||
import { QuestionFilled, Delete, List, UserFilled, Setting, Share, RefreshRight, Link, Tools, MagicStick, SetUp } from "@element-plus/icons-vue";
|
||||
import { reactive, onBeforeUnmount, onMounted } from "vue";
|
||||
import { reactive, onBeforeUnmount, onMounted, ref } from "vue";
|
||||
import { useTray, setTrayRunState, setTrayTooltip } from "~/composables/tray";
|
||||
import { initStartWinIpBroadcast } from "~/composables/netcard";
|
||||
import useMainStore from "@/stores/index";
|
||||
@@ -568,6 +494,7 @@
|
||||
import { sortedUniq, uniq } from "lodash-es";
|
||||
import { bounce, addQQGroup } from "~/utils";
|
||||
import { ElConfirmDanger, ElConfirmPrimary } from "~/utils/element";
|
||||
import { getServerArgs } from "@/composables/server";
|
||||
|
||||
let is_close = false;
|
||||
|
||||
@@ -577,6 +504,7 @@
|
||||
is_close = true;
|
||||
await invoke("stop_command", { child_id: listenObj.thread_id || 0 });
|
||||
await invoke("stop_command", { child_id: data.winipBcPid || 0 });
|
||||
await invoke("stop_command", { child_id: listenObj.server_thread_id.value || 0 });
|
||||
},
|
||||
async () => {
|
||||
await handleConnection();
|
||||
@@ -593,10 +521,12 @@
|
||||
cidrVisible: false,
|
||||
advanceVisible: false,
|
||||
toolVisible: false,
|
||||
serverVisible: false,
|
||||
winipBcPid: 0, //WinIPBroadcast进程id
|
||||
winipBcStart: false,
|
||||
memberVisible: false,
|
||||
log: "",
|
||||
serverLog: "", //服务端日志
|
||||
update: false,
|
||||
releaseList: [],
|
||||
coreVersion: "-",
|
||||
@@ -672,17 +602,29 @@
|
||||
const listenObj: { [key: string]: any } = {
|
||||
unListenOutPut: null,
|
||||
unListenThreadId: null,
|
||||
unListenServerOutPut: null,
|
||||
unListenServerThreadId: null,
|
||||
unListenConfigStart: null,
|
||||
unListenStartStopServer: null,
|
||||
thread_id: null,
|
||||
server_thread_id: ref(null),
|
||||
async listenOutput() {
|
||||
// const appWindow = getCurrentWindow();
|
||||
const unListen = await listen("command-output", async event => {
|
||||
const unListen = await listen<string>("command-output", async event => {
|
||||
data.isStart = true;
|
||||
// console.error(event.payload);
|
||||
if (event.payload) {
|
||||
data.startLoading = false;
|
||||
let ipv4 = /dhcp ip changed. old: None, new: Some\((\d+\.\d+\.\d+\.\d+).*\)/g.exec(event.payload as string)?.[1];
|
||||
let devName = /tun device ready. dev: (.*)/g.exec(event.payload as string)?.[1];
|
||||
if (event.payload.includes("peer connection removed")) {
|
||||
data.isSuccessGetIp = false;
|
||||
}
|
||||
if (event.payload.includes("new peer connection added") && !data.isSuccessGetIp) {
|
||||
await setTrayRunState(tray, true);
|
||||
data.isSuccessGetIp = true;
|
||||
await setTrayTooltip(tray, `IP: ${config.ipv4}`);
|
||||
}
|
||||
if (config.dhcp || mainStore.configStartEnable) {
|
||||
if (ipv4) {
|
||||
config.ipv4 = ipv4;
|
||||
@@ -690,12 +632,6 @@
|
||||
data.isSuccessGetIp = true;
|
||||
await setTrayTooltip(tray, `IP: ${ipv4}`);
|
||||
}
|
||||
} else {
|
||||
if ((event.payload as string).includes("new peer connection added") && !data.isSuccessGetIp) {
|
||||
await setTrayRunState(tray, true);
|
||||
data.isSuccessGetIp = true;
|
||||
await setTrayTooltip(tray, `IP: ${config.ipv4}`);
|
||||
}
|
||||
}
|
||||
if (
|
||||
devName &&
|
||||
@@ -733,6 +669,24 @@
|
||||
});
|
||||
this.unListenThreadId = unListen;
|
||||
},
|
||||
async listenServerOutPut() {
|
||||
const unListen = await listen<string>("server-command-output", async event => {
|
||||
// console.log("server-command-output", event);
|
||||
const logArr = data.serverLog.split("\n");
|
||||
const start = logArr.length > 1000 ? logArr.length - 1000 : 0;
|
||||
data.serverLog = logArr.slice(start).join("\n");
|
||||
data.serverLog += (event.payload || "") + "\n";
|
||||
});
|
||||
this.unListenServerOutPut = unListen;
|
||||
},
|
||||
async listenServerThreadId() {
|
||||
const unListen = await listen("server-thread-id", event => {
|
||||
if (event.payload) {
|
||||
this.server_thread_id.value = event.payload;
|
||||
}
|
||||
});
|
||||
this.unListenServerThreadId = unListen;
|
||||
},
|
||||
async listenConfigStart() {
|
||||
const unListen = await listen("config", event => {
|
||||
// console.error("config", event.payload);
|
||||
@@ -741,6 +695,23 @@
|
||||
config.ipv4 = ipv4;
|
||||
});
|
||||
this.unListenConfigStart = unListen;
|
||||
},
|
||||
async listenStartStopServer() {
|
||||
const unListen = await listen<{ args: Array<string> }>("startStopServer", async event => {
|
||||
await listenObj?.unListenServerOutPut?.();
|
||||
await invoke("stop_command", { child_id: listenObj.server_thread_id.value || 0 });
|
||||
if (listenObj.server_thread_id.value) {
|
||||
listenObj.server_thread_id.value = null;
|
||||
} else {
|
||||
data.serverLog = "";
|
||||
await listenObj.listenServerOutPut();
|
||||
await invoke("run_command", {
|
||||
args: event.payload.args,
|
||||
is_server: true
|
||||
});
|
||||
}
|
||||
});
|
||||
this.unListenStartStopServer = unListen;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -953,7 +924,22 @@
|
||||
});
|
||||
};
|
||||
|
||||
const initAutoStartServer = async () => {
|
||||
if (mainStore.serverConfig.autoStart && data.coreVersion) {
|
||||
const args = getServerArgs();
|
||||
await listenObj?.unListenServerOutPut?.();
|
||||
await invoke("stop_command", { child_id: listenObj.server_thread_id.value || 0 });
|
||||
data.serverLog = "";
|
||||
await listenObj.listenServerOutPut();
|
||||
await invoke("run_command", {
|
||||
args,
|
||||
is_server: true
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
let logsTimer: NodeJS.Timeout | null = null;
|
||||
let serverLogsTimer: NodeJS.Timeout | null = null;
|
||||
|
||||
onMounted(async () => {
|
||||
// await handleUpdateCore(); //默认不自动更新
|
||||
@@ -963,8 +949,11 @@
|
||||
await initStartWinIpBroadcast();
|
||||
await getCoreVersion();
|
||||
await listenObj.listenThreadId();
|
||||
await listenObj.listenServerThreadId();
|
||||
await listenObj.listenConfigStart();
|
||||
await listenObj.listenStartStopServer();
|
||||
await initConfigDir();
|
||||
await initAutoStartServer();
|
||||
await initConnectAfterStart();
|
||||
closePrevent();
|
||||
});
|
||||
@@ -973,7 +962,9 @@
|
||||
unListenAll();
|
||||
listenObj.unListenReleaseList && listenObj.unListenReleaseList();
|
||||
listenObj.unListenConfigStart && listenObj.unListenConfigStart();
|
||||
listenObj.unListenStartStopServer && listenObj.unListenStartStopServer();
|
||||
logsTimer && clearInterval(logsTimer);
|
||||
serverLogsTimer && clearInterval(serverLogsTimer);
|
||||
});
|
||||
|
||||
const getArgs = async () => {
|
||||
@@ -1006,24 +997,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// if (mainStore.enableCreateServer) {
|
||||
// if (config.relayAllPeerrpc) {
|
||||
// args.push("--relay-all-peer-rpc");
|
||||
// }
|
||||
// const whiteList = mainStore.ServerWhiteList.trim()
|
||||
// .split("\n")
|
||||
// .map(el => el.trim())
|
||||
// .filter(el => el)
|
||||
// .join(" ");
|
||||
// if (whiteList && mainStore.enableWhiteList) {
|
||||
// args.push("--relay-network-whitelist", whiteList);
|
||||
// }
|
||||
// if (!whiteList && mainStore.enableWhiteList) {
|
||||
// args.push("--relay-network-whitelist");
|
||||
// }
|
||||
// return args;
|
||||
// }
|
||||
|
||||
if (config.dhcp) {
|
||||
args.push("-d");
|
||||
}
|
||||
@@ -1194,6 +1167,7 @@
|
||||
importConfigData.visible = true;
|
||||
}
|
||||
if (command === "create_server") {
|
||||
await handleShowServerDialog();
|
||||
// if (data.isStart) {
|
||||
// const [error] = await ElConfirmDanger("切换会停止{action},是否继续?", "提示", {
|
||||
// action: "`联机/服务`",
|
||||
@@ -1301,6 +1275,7 @@
|
||||
}, 650);
|
||||
},
|
||||
() => {
|
||||
logsTimer && clearInterval(logsTimer);
|
||||
data.logVisible = false;
|
||||
}
|
||||
);
|
||||
@@ -1362,4 +1337,30 @@
|
||||
}
|
||||
);
|
||||
};
|
||||
|
||||
const handleShowServerDialog = async () => {
|
||||
await etWindows(
|
||||
"server",
|
||||
{
|
||||
title: "自建服务器",
|
||||
minWidth: 550,
|
||||
minHeight: 460,
|
||||
width: 550,
|
||||
height: 460,
|
||||
resizable: true,
|
||||
url: "#/server"
|
||||
},
|
||||
(_, appWindow) => {
|
||||
data.serverVisible = true;
|
||||
serverLogsTimer && clearInterval(serverLogsTimer);
|
||||
serverLogsTimer = setInterval(() => {
|
||||
appWindow.emitTo("server", "server_logs", { log: data.serverLog, threadId: listenObj.server_thread_id.value });
|
||||
}, 650);
|
||||
},
|
||||
() => {
|
||||
serverLogsTimer && clearInterval(serverLogsTimer);
|
||||
data.serverVisible = false;
|
||||
}
|
||||
);
|
||||
};
|
||||
</script>
|
||||
|
||||
+42
-9
@@ -79,7 +79,9 @@
|
||||
<script setup lang="ts">
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { reactive, onMounted, onBeforeUnmount } from "vue";
|
||||
import { parsePeerInfo } from "@/utils";
|
||||
import { ATJ, parsePeerInfo } from "@/utils";
|
||||
import { ElConfirmDanger } from "~/utils/element";
|
||||
import { getCurrentWindow } from "@tauri-apps/api/window";
|
||||
// enum NatType {
|
||||
// // has NAT; but own a single public IP, port is not changed
|
||||
// Unknown = 0;
|
||||
@@ -122,8 +124,30 @@
|
||||
["tunnel_proto", "隧道协议"]
|
||||
];
|
||||
|
||||
let timer: NodeJS.Timeout | null = null;
|
||||
|
||||
const listenOutput = async () => {
|
||||
const member = await invoke<string>("get_members_by_cli");
|
||||
const [error, member] = await ATJ(invoke<string>("get_members_by_cli"));
|
||||
// if(!member) return;
|
||||
if (error) {
|
||||
data.member = [];
|
||||
return "";
|
||||
}
|
||||
if (member === "_EasytierGameCliFailedToConnect_") {
|
||||
stopTimer();
|
||||
const [error] = await ElConfirmDanger("连接已断开,是否重新尝试?", "警告", {
|
||||
confirmButtonText: "重试",
|
||||
cancelButtonText: "关闭窗口"
|
||||
});
|
||||
if (!error) {
|
||||
await listenOutput();
|
||||
} else {
|
||||
const appWindow = getCurrentWindow();
|
||||
await appWindow.close();
|
||||
}
|
||||
data.member = [];
|
||||
return;
|
||||
}
|
||||
const peerInfo = parsePeerInfo(member);
|
||||
peerInfo.forEach(value => {
|
||||
if (value.cost === "Local") {
|
||||
@@ -133,20 +157,29 @@
|
||||
value.ipv4 = value.ipv4.split("/")[0];
|
||||
}
|
||||
});
|
||||
// console.error(peerInfo);
|
||||
data.member = peerInfo;
|
||||
if(!timer) {
|
||||
startTimer();
|
||||
}
|
||||
};
|
||||
|
||||
let timer: NodeJS.Timeout | null = null;
|
||||
const startTimer = async () => {
|
||||
await listenOutput();
|
||||
timer = setInterval(async () => {
|
||||
await listenOutput();
|
||||
}, 1000);
|
||||
};
|
||||
|
||||
const stopTimer = () => {
|
||||
timer && clearInterval(timer);
|
||||
timer = null;
|
||||
}
|
||||
|
||||
onMounted(async () => {
|
||||
listenOutput();
|
||||
timer = setInterval(() => {
|
||||
listenOutput();
|
||||
}, 1000 * 10);
|
||||
await startTimer();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
timer && clearInterval(timer);
|
||||
stopTimer();
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -0,0 +1,128 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-[10px] h-full">
|
||||
<ElForm
|
||||
size="small"
|
||||
label-position="top"
|
||||
:model="mainStore.serverConfig"
|
||||
>
|
||||
<ElFormItem
|
||||
label="白名单"
|
||||
prop="ServerWhiteList"
|
||||
class="full-label full-content overflow-hidden !flex flex-col h-full !mb-[0]"
|
||||
>
|
||||
<template #label>
|
||||
<div class="flex items-center gap-[10px]">
|
||||
白名单
|
||||
<ElSwitch
|
||||
v-model="mainStore.serverConfig.enableWhiteList"
|
||||
inline-prompt
|
||||
active-text="启用"
|
||||
inactive-text="禁用"
|
||||
></ElSwitch>
|
||||
|
||||
<div class="ml-auto">
|
||||
<ElTooltip
|
||||
placement="top"
|
||||
content="打开软件的时候,就会开启这个自建服务"
|
||||
>
|
||||
<ElCheckbox v-model="mainStore.serverConfig.autoStart">自动启动</ElCheckbox>
|
||||
</ElTooltip>
|
||||
<ElTooltip
|
||||
placement="top"
|
||||
content="帮助其他虚拟网建立P2P链接"
|
||||
>
|
||||
<ElCheckbox v-model="mainStore.serverConfig.relayAllPeerrpc">转发所有对等节点的RPC数据包</ElCheckbox>
|
||||
</ElTooltip>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<div class="h-full w-full flex flex-col overflow-hidden">
|
||||
<div class="flex-1 overflow-auto">
|
||||
<ElInput
|
||||
:disabled="!mainStore.serverConfig.enableWhiteList"
|
||||
placeholder="一行一个,支持通配符列表,如(ab*)。当该参数的列表为空时,就不会为所有其他网络提供转发服务。"
|
||||
:maxlength="1000"
|
||||
v-model="mainStore.serverConfig.serverWhiteList"
|
||||
type="textarea"
|
||||
:rows="3"
|
||||
resize="none"
|
||||
></ElInput>
|
||||
</div>
|
||||
</div>
|
||||
</ElFormItem>
|
||||
</ElForm>
|
||||
<div class="flex items-center gap-[10px]">
|
||||
<div class="flex items-center gap-[5px]">
|
||||
<ElText>服务器端口</ElText>
|
||||
<div class="max-w-[100px]">
|
||||
<ElTooltip content="端口号">
|
||||
<ElInput v-model="mainStore.serverConfig.port"></ElInput>
|
||||
</ElTooltip>
|
||||
</div>
|
||||
</div>
|
||||
<ElButton
|
||||
size="large"
|
||||
:loading="data.loading"
|
||||
:type="data.isStart ? 'danger' : 'primary'"
|
||||
@click="hanldeClickStart"
|
||||
>
|
||||
{{ !data.isStart ? "启动服务器" : "停止服务器" }}
|
||||
</ElButton>
|
||||
</div>
|
||||
|
||||
<ElInput
|
||||
placeholder="服务器日志"
|
||||
:model-value="data.log"
|
||||
type="textarea"
|
||||
:rows="14"
|
||||
resize="none"
|
||||
></ElInput>
|
||||
</div>
|
||||
</template>
|
||||
<script setup lang="ts">
|
||||
import useMainStore from "@/stores/index";
|
||||
import { reactive, onMounted, onBeforeUnmount } from "vue";
|
||||
import { getCurrentWindow } from "@tauri-apps/api/window";
|
||||
import { listen, type UnlistenFn } from "@tauri-apps/api/event";
|
||||
import { getServerArgs } from "@/composables/server";
|
||||
|
||||
const appWindow = getCurrentWindow();
|
||||
const mainStore = useMainStore();
|
||||
const data = reactive({
|
||||
log: "",
|
||||
isStart: false,
|
||||
loading: true
|
||||
});
|
||||
|
||||
const listenStart = async () => {
|
||||
const unListen = await listen<{ log: string; threadId: number | null }>("server_logs", event => {
|
||||
data.log = event.payload.log || "";
|
||||
if (event.payload.threadId) {
|
||||
data.isStart = true;
|
||||
} else {
|
||||
data.isStart = false;
|
||||
}
|
||||
data.loading = false;
|
||||
});
|
||||
return unListen;
|
||||
};
|
||||
|
||||
let unlistenStart: UnlistenFn | null = null;
|
||||
onMounted(async () => {
|
||||
unlistenStart = await listenStart();
|
||||
});
|
||||
|
||||
onBeforeUnmount(() => {
|
||||
unlistenStart && unlistenStart();
|
||||
});
|
||||
|
||||
const hanldeClickStart = async () => {
|
||||
data.loading = true;
|
||||
const args = getServerArgs();
|
||||
await appWindow.emitTo("main", "startStopServer", { args });
|
||||
};
|
||||
|
||||
mainStore.$subscribe(async (...a) => {
|
||||
await appWindow.emitTo("main", "config", { serverConfig: { ...mainStore.serverConfig }});
|
||||
});
|
||||
</script>
|
||||
@@ -8,7 +8,8 @@
|
||||
"member",
|
||||
"cidr",
|
||||
"advance",
|
||||
"tool"
|
||||
"tool",
|
||||
"server"
|
||||
],
|
||||
"permissions": [
|
||||
"core:default",
|
||||
|
||||
+55
-31
@@ -9,10 +9,7 @@ use std::fs::{self, File};
|
||||
use std::io::{BufRead, BufReader, Write};
|
||||
use std::os::windows::process::CommandExt;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::{
|
||||
atomic::{AtomicBool, Ordering},
|
||||
mpsc, Arc,
|
||||
};
|
||||
use std::sync::mpsc;
|
||||
use std::{path, thread};
|
||||
use sysinfo::System;
|
||||
use tauri::tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent};
|
||||
@@ -142,15 +139,32 @@ fn get_members_by_cli() -> String {
|
||||
.output()
|
||||
{
|
||||
Ok(output) => {
|
||||
let output_str = String::from_utf8_lossy(&output.stdout);
|
||||
return output_str.trim().to_string();
|
||||
if output.status.success() {
|
||||
let output_str = String::from_utf8_lossy(&output.stdout);
|
||||
return output_str.trim().to_string();
|
||||
}else {
|
||||
let output_str = String::from_utf8_lossy(&output.stderr);
|
||||
log::error!("{}", output_str.trim().to_string());
|
||||
return "_EasytierGameCliFailedToConnect_".to_string();
|
||||
}
|
||||
}
|
||||
Err(_e) => return _e.to_string(),
|
||||
Err(_e) => {
|
||||
log::error!("get member list error");
|
||||
return "".to_string();
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command(rename_all = "snake_case")]
|
||||
async fn download_easytier_zip(download_url: String, file_name: String) {
|
||||
let cache_dir_path = get_tool_exe_path(String::from("\\easytier\\cache"));
|
||||
let cache_file_name = format!("{}\\{}", cache_dir_path, file_name);
|
||||
let cache_file_name_path = path::Path::new(&cache_file_name);
|
||||
if cache_file_name_path.exists() {
|
||||
unzip(cache_file_name_path);
|
||||
return;
|
||||
}
|
||||
|
||||
let target = format!("{}", download_url);
|
||||
let response = reqwest::get(target)
|
||||
.await
|
||||
@@ -177,10 +191,19 @@ async fn download_easytier_zip(download_url: String, file_name: String) {
|
||||
file.write_all(&content).expect("error to write easytier");
|
||||
println!("写入完成");
|
||||
unzip(path);
|
||||
match fs::remove_file(path) {
|
||||
Ok(_) => println!("删除zip文件成功"),
|
||||
Err(_) => log::error!("删除zip文件失败"),
|
||||
|
||||
let cache_dir_path = path::Path::new(&cache_dir_path);
|
||||
if !cache_dir_path.exists() {
|
||||
fs::create_dir_all(&cache_dir_path).unwrap();
|
||||
}
|
||||
match fs::rename(path, cache_file_name) {
|
||||
Ok(_) => println!("保存zip文件至easytier/cache成功"),
|
||||
Err(_) => log::error!("保存zip文件失败"),
|
||||
}
|
||||
// match fs::remove_file(path) {
|
||||
// Ok(_) => println!("删除zip文件成功"),
|
||||
// Err(_) => log::error!("删除zip文件失败"),
|
||||
// }
|
||||
}
|
||||
|
||||
fn unzip(fname: &path::Path) {
|
||||
@@ -228,18 +251,22 @@ fn unzip(fname: &path::Path) {
|
||||
}
|
||||
|
||||
#[tauri::command(rename_all = "snake_case")]
|
||||
fn run_command(
|
||||
app_handle: tauri::AppHandle,
|
||||
args: Vec<String>,
|
||||
stop_signal: tauri::State<Arc<AtomicBool>>,
|
||||
) {
|
||||
fn run_command(app_handle: tauri::AppHandle, args: Vec<String>, is_server: Option<bool>) {
|
||||
let is_server = is_server.unwrap_or(false);
|
||||
let (tx, rx) = mpsc::channel();
|
||||
stop_signal.store(false, Ordering::Relaxed);
|
||||
|
||||
let app_handle1 = app_handle.clone();
|
||||
let app_handle2 = app_handle.clone();
|
||||
let stop_signal1 = Arc::clone(&stop_signal);
|
||||
let stop_signal2 = Arc::clone(&stop_signal);
|
||||
|
||||
let args2 = args.clone();
|
||||
let mut thread_id_str = "thread-id";
|
||||
if is_server {
|
||||
thread_id_str = "server-thread-id";
|
||||
}
|
||||
let mut command_output_str = "command-output";
|
||||
if is_server {
|
||||
command_output_str = "server-command-output";
|
||||
}
|
||||
thread::spawn(move || {
|
||||
let core_path = get_tool_exe_path(String::from("\\easytier\\easytier-core.exe"));
|
||||
// trace, debug, info, warn, error, off
|
||||
@@ -252,36 +279,36 @@ fn run_command(
|
||||
|
||||
println!("child id: {}", child.id());
|
||||
app_handle1
|
||||
.emit("thread-id", child.id())
|
||||
.emit(thread_id_str, child.id())
|
||||
.expect("failed to emit id event");
|
||||
app_handle1
|
||||
.emit("command-output", args2.join(" "))
|
||||
.emit(command_output_str, args2.join(" "))
|
||||
.expect("error output args");
|
||||
let stdout = child.stdout.take().expect("failed to capture stdout");
|
||||
let reader = BufReader::new(stdout);
|
||||
|
||||
for line in reader.lines() {
|
||||
match line {
|
||||
Ok(line) => {
|
||||
tx.send(line).expect("failed to send line");
|
||||
}
|
||||
Ok(line) => match tx.send(line) {
|
||||
Ok(_) => {}
|
||||
Err(e) => {
|
||||
log::error!("error sending line: {}", e);
|
||||
break;
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
log::error!("error reading line: {}", e);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
stop_signal1.store(true, Ordering::Relaxed);
|
||||
println!("end");
|
||||
});
|
||||
|
||||
thread::spawn(move || {
|
||||
while let Ok(line) = rx.recv() {
|
||||
if stop_signal2.load(Ordering::Relaxed) {
|
||||
break;
|
||||
}
|
||||
app_handle2
|
||||
.emit("command-output", line)
|
||||
.emit(command_output_str, line)
|
||||
.expect("failed to emit event");
|
||||
}
|
||||
});
|
||||
@@ -523,8 +550,6 @@ pub fn run() {
|
||||
// 获取命令行参数
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
|
||||
let stop_signal = Arc::new(AtomicBool::new(false)); // 创建一个原子布尔值,用于控制命令的停止
|
||||
let stop_signal_clone = Arc::clone(&stop_signal); // 创建一个原子布尔值的克隆,用于传递给命令
|
||||
let context = tauri::generate_context!();
|
||||
tauri::Builder::default()
|
||||
.plugin(
|
||||
@@ -592,7 +617,6 @@ pub fn run() {
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.manage(stop_signal_clone)
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
run_command,
|
||||
stop_command,
|
||||
|
||||
+11
-3
@@ -32,11 +32,11 @@ export default defineStore("main", {
|
||||
netCardMetricValue: 1 //自定义网卡跃点值
|
||||
},
|
||||
serverConfig: {
|
||||
enableCreateServer: false, // 自建服务器
|
||||
enableWhiteList: true, // 是否启用白名单
|
||||
|
||||
relayAllPeerrpc: false, // 是否启用所有对等RPC
|
||||
serverWhiteList: "", // 服务器流量转发白名单
|
||||
enableListener: true, // 是否启用监听
|
||||
// enableListener: true, // 是否启用监听
|
||||
autoStart: false, //随软件自启
|
||||
port: "11010", // 服务器端口
|
||||
},
|
||||
cidrEnable: false,
|
||||
@@ -84,6 +84,14 @@ export default defineStore("main", {
|
||||
"config.enableNetCardMetric",
|
||||
"config.netCardMetricValue",
|
||||
|
||||
"serverConfig.autoStart",
|
||||
// 'serverConfig.enableListener',
|
||||
'serverConfig.enableWhiteList',
|
||||
'serverConfig.relayAllPeerrpc',
|
||||
'serverConfig.serverWhiteList',
|
||||
'serverConfig.port',
|
||||
|
||||
|
||||
"cidrEnable",
|
||||
"basePeers",
|
||||
"theme",
|
||||
|
||||
@@ -65,6 +65,7 @@ export const ATJ = (promise: Promise<any>, errorExt: string | undefined = undefi
|
||||
};
|
||||
|
||||
export const parsePeerInfo = (content: string) => {
|
||||
if(!content) return [];
|
||||
// 将表格字符串分割成行
|
||||
const lines = content.split("\n");
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ const releaseDir = "./src-tauri/target/release";
|
||||
const releaseDirEasytier = `${releaseDir}/easytier/`;
|
||||
const releaseExe = `${releaseDir}/easytier-game.exe`;
|
||||
const releaseHelp = `${releaseDir}/帮助.txt`;
|
||||
const deleteEasytierFiles = ["logs/", "guiLogs/"];
|
||||
const deleteEasytierFiles = ["logs/", "guiLogs/", "cache/"];
|
||||
const pkg = require("./package.json");
|
||||
const fileName = `easytier-game_windows_x86_64_${pkg.version}.zip`; // 发布包格式
|
||||
const releaseZipDir = "./release";
|
||||
|
||||
Reference in New Issue
Block a user