Compare commits

...
10 Commits
Author SHA1 Message Date
黑先森 8c911f47f9 优化日志输出和提示 成员列表显示bug修复 优化打包后的目录结构,清爽干净 2024-10-25 18:40:47 +08:00
leizi97 f3fc37957c 增加子网代理和部分高级配置功能 升级tauri到2.0.6 2024-10-23 21:58:36 +08:00
黑先森 a4d6fe6e95 封装二级弹窗方法,新增子网代理和高级配置按钮,新增子网代理页面 2024-10-23 18:37:11 +08:00
黑先森 9b883d686d 优化界面css,增加部分页面autostart权限
-- 更新 element-plus 2.7.1 -> 2.8.6 并修复升级后的问题
-- 升级autostart插件为2.0.1 win10测试开机自启成功
2024-10-22 19:09:45 +08:00
黑先森 2ac0afb847 插件版本更新,rust打包使用1.77.2,支持win7 2024-10-21 10:51:16 +08:00
黑先森 a04fae725d #improvement 联机成功后右下角角标增加绿点,优化二级窗口创建逻辑修复控制台报错,增加开机自启功能,禁用p2p默认改为不禁用 2024-10-17 19:30:05 +08:00
黑先森 3150878dbd #Fix 紧急修复日志无法打开的问题 2024-10-16 17:21:49 +08:00
黑先森 0467074eec #Fix 内置WinIPBroadcast默认开启,成员列表显示优化 1.0.5发布 2024-10-16 16:33:45 +08:00
黑先森 2e598ac026 优化成员列表表头为中文,修复日志接收失败的问题 2024-10-16 11:18:10 +08:00
luoleixin 4bb1216a07 增加日志窗口,增加成员弹窗,优化按钮和布局,增加仓库地址,增加license,优化退出代码,退出时停止子进程,屏蔽右键菜单 2024-10-15 20:49:23 +08:00
32 changed files with 1427 additions and 769 deletions
+5 -1
View File
@@ -9,4 +9,8 @@ dist
.fleet .fleet
.idea .idea
.vscode .vscode
release release
src-tauri/easytier-cli.exe
src-tauri/easytier-core.exe
src-tauri/Packet.dll
src-tauri/wintun.dll
+73
View File
@@ -0,0 +1,73 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files.
"Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions:
(a) You must give any other recipients of the Work or Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License.
You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives.
Copyright 2023 sunsijie
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-14
View File
@@ -27,17 +27,3 @@ body {
box-sizing: border-box; box-sizing: border-box;
padding: 3px 5px; padding: 3px 5px;
} }
::-webkit-scrollbar {
width: 6px;
}
::-webkit-scrollbar-thumb {
background-color: #0003;
border-radius: 10px;
transition: all 0.2s ease-in-out;
}
::-webkit-scrollbar-track {
border-radius: 10px;
}
+8
View File
@@ -0,0 +1,8 @@
// const infoDialog = new WebviewWindow("log", {
// title: "日志",
// resizable: false,
// width: 600,
// height: 400,
// parent: appWindow,
// url: "/log"
// });
+88 -87
View File
@@ -1,105 +1,106 @@
import { Menu, MenuItem, PredefinedMenuItem } from '@tauri-apps/api/menu' import { Menu, MenuItem, PredefinedMenuItem } from "@tauri-apps/api/menu";
import { TrayIcon } from '@tauri-apps/api/tray' import { TrayIcon } from "@tauri-apps/api/tray";
import { getCurrentWindow } from '@tauri-apps/api/window' import { getCurrentWindow } from "@tauri-apps/api/window";
import pkg from '@/package.json' import pkg from "@/package.json";
const DEFAULT_TRAY_NAME = 'main' const DEFAULT_TRAY_NAME = "main";
async function toggleVisibility() { async function toggleVisibility() {
if (await getCurrentWindow().isVisible()) { if (await getCurrentWindow().isVisible()) {
await getCurrentWindow().hide() await getCurrentWindow().hide();
} } else {
else { await getCurrentWindow().show();
await getCurrentWindow().show() await getCurrentWindow().setFocus();
await getCurrentWindow().setFocus() }
}
} }
export async function useTray(init: boolean = false) { export async function useTray(init: boolean = false, beforExit: Function) {
let tray let tray;
try { try {
tray = await TrayIcon.getById(DEFAULT_TRAY_NAME) tray = await TrayIcon.getById(DEFAULT_TRAY_NAME);
if (!tray) { if (!tray) {
tray = await TrayIcon.new({ tray = await TrayIcon.new({
tooltip: `EasyTier\n${pkg.version}`, tooltip: `EasyTier\n${pkg.version}`,
title: `EasyTier\n${pkg.version}`, title: `EasyTier\n${pkg.version}`,
id: DEFAULT_TRAY_NAME, id: DEFAULT_TRAY_NAME,
menu: await Menu.new({ menu: await Menu.new({
id: 'main', id: "main",
items: await generateMenuItem(), items: await generateMenuItem(beforExit)
}), }),
action: async () => { action: async e => {
toggleVisibility() toggleVisibility();
}, }
}) });
} }
} } catch (error) {
catch (error) { console.warn("Error while creating tray icon:", error);
console.warn('Error while creating tray icon:', error) return null;
return null }
}
if (init) { if (init) {
tray.setTooltip(`EasyTier\n${pkg.version}`) tray.setTooltip(`EasyTier\n${pkg.version}`);
tray.setMenuOnLeftClick(false) tray.setMenuOnLeftClick(false);
tray.setMenu(await Menu.new({ tray.setMenu(
id: 'main', await Menu.new({
items: await generateMenuItem(), id: "main",
})) items: await generateMenuItem(beforExit)
} })
);
}
return tray return tray;
} }
export async function generateMenuItem() { export async function generateMenuItem(beforExit: Function) {
return [ return [await MenuItemExit("退出", beforExit), await PredefinedMenuItem.new({ item: "Separator" }), await MenuItemShow("显示 / 隐藏")];
await MenuItemExit('Exit'),
await PredefinedMenuItem.new({ item: 'Separator' }),
await MenuItemShow('Show / Hide'),
]
} }
export async function MenuItemExit(text: string) { export async function MenuItemExit(text: string, beforExit: Function) {
return await PredefinedMenuItem.new({ return await MenuItem.new({
text, id: "quit",
item: 'Quit', text,
}) action: async () => {
if (beforExit) {
await beforExit();
}
await getCurrentWindow().close();
}
});
} }
export async function MenuItemShow(text: string) { export async function MenuItemShow(text: string) {
return await MenuItem.new({ return await MenuItem.new({
id: 'show', id: "show",
text, text,
action: async () => { action: async () => {
await toggleVisibility() await toggleVisibility();
}, }
}) });
} }
export async function setTrayMenu(items: (MenuItem | PredefinedMenuItem)[] | undefined = undefined) { // export async function setTrayMenu(items: (MenuItem | PredefinedMenuItem)[] | undefined = undefined) {
const tray = await useTray() // // const tray = await useTray()
if (!tray) // const tray = await TrayIcon.getById(DEFAULT_TRAY_NAME)
return // if (!tray)
const menu = await Menu.new({ // return
id: 'main', // const menu = await Menu.new({
items: items || await generateMenuItem(), // id: 'main',
}) // items: items || await generateMenuItem(),
tray.setMenu(menu) // })
// tray.setMenu(menu)
// }
export async function setTrayRunState(tray: TrayIcon | null, isRunning: boolean = false) {
if (!tray) return;
tray.setIcon(isRunning ? "easytier/icons/icon-inactive.ico" : "easytier/icons/icon.ico");
} }
export async function setTrayRunState(isRunning: boolean = false) { // export async function setTrayTooltip(tooltip: string) {
const tray = await useTray() // if (tooltip) {
if (!tray) // const tray = await useTray()
return // if (!tray)
tray.setIcon(isRunning ? 'icons/icon-inactive.ico' : 'icons/icon.ico') // return
} // tray.setTooltip(`EasyTier\n${pkg.version}\n${tooltip}`)
// tray.setTitle(`EasyTier\n${pkg.version}\n${tooltip}`)
export async function setTrayTooltip(tooltip: string) { // }
if (tooltip) { // }
const tray = await useTray()
if (!tray)
return
tray.setTooltip(`EasyTier\n${pkg.version}\n${tooltip}`)
tray.setTitle(`EasyTier\n${pkg.version}\n${tooltip}`)
}
}
+53
View File
@@ -0,0 +1,53 @@
import { type UnlistenFn } from "@tauri-apps/api/event";
import { getCurrentWindow, PhysicalPosition, type WindowOptions, Window } from "@tauri-apps/api/window";
import { WebviewWindow } from "@tauri-apps/api/webviewWindow";
import type { WebviewLabel, WebviewOptions, } from "@tauri-apps/api/webview";
export default async (
label: WebviewLabel,
options?: Omit<WebviewOptions, "x" | "y" | "width" | "height"> & WindowOptions,
afterCreatedFunc?: (webviewWindow: WebviewWindow, appWindow: Window) => void | null,
beforeCloseFunc?: () => void | null
) => {
let defaultOpts = {
parent: undefined,
closable: true,
resizable: true,
decorations: true,
maximizable: false,
minimizable: false,
x: 0,
y: 0
};
const appWindow = getCurrentWindow();
if (appWindow) {
const appSize = await appWindow.outerSize();
const factor = await appWindow.scaleFactor();
const appPosition = await appWindow.outerPosition();
const logicalPosition = new PhysicalPosition(appPosition.x + appSize.width, appPosition.y).toLogical(factor);
defaultOpts.parent = appWindow as any;
defaultOpts.x = logicalPosition.x;
defaultOpts.y = logicalPosition.y;
}
let unListenlogClose: UnlistenFn | null = null;
let unlistenLogCreated: UnlistenFn | null = null;
let dialog = await WebviewWindow.getByLabel(label);
if (!dialog) {
dialog = new WebviewWindow(label, {...defaultOpts, ...options});
unlistenLogCreated = await dialog.once("tauri://webview-created", async () => {
if (dialog) {
afterCreatedFunc && (await afterCreatedFunc(dialog, appWindow));
await dialog.show();
}
});
unListenlogClose = await dialog.onCloseRequested(async () => {
beforeCloseFunc && (await beforeCloseFunc());
unListenlogClose && (await unListenlogClose());
});
} else {
const visible = await dialog.isVisible();
if (visible) {
await dialog.close();
unlistenLogCreated && (await (unlistenLogCreated as Function)());
}
}
};
+3 -18
View File
@@ -3,23 +3,8 @@
</template> </template>
<script setup lang="tsx"> <script setup lang="tsx">
import { onBeforeUnmount } from "vue"; //屏蔽右键菜单
import { getCurrentWindow } from "@tauri-apps/api/window"; document.addEventListener("contextmenu", (e: MouseEvent) => {
import { listen } from "@tauri-apps/api/event"; // e.preventDefault();
const appWindow = getCurrentWindow();
const unlisten = listen("window-close-event", (event) => {
closeApp();
}); });
onBeforeUnmount(() => {
unlisten.then((unlisten) => {
unlisten && unlisten instanceof Function && unlisten();
});
});
const closeApp = async () => {
appWindow.hide();
};
</script> </script>
+1 -1
View File
@@ -70,7 +70,7 @@ export default defineNuxtConfig({
sourcemap: !!process.env.TAURI_DEBUG sourcemap: !!process.env.TAURI_DEBUG
}, },
esbuild: { esbuild: {
pure: ["console.log"], // pure: ["console.log"],
drop: ["debugger"] drop: ["debugger"]
} }
}, },
+8 -6
View File
@@ -1,9 +1,9 @@
{ {
"name": "easytier-game", "name": "easytier-game",
"private": true, "private": true,
"author": "luoleixin@digisky.com", "author": "leizi97",
"description": "A simple network initiator based on Easytier", "description": "A simple network initiator based on Easytier",
"version": "1.0.3", "version": "1.0.8",
"scripts": { "scripts": {
"dev": "nuxt dev --dotenv env/.env.dev --host 0.0.0.0", "dev": "nuxt dev --dotenv env/.env.dev --host 0.0.0.0",
"build": "nuxt generate --dotenv env/.env.prod" "build": "nuxt generate --dotenv env/.env.prod"
@@ -18,14 +18,14 @@
"@tauri-apps/cli": "^2.0.2", "@tauri-apps/cli": "^2.0.2",
"@tauri-apps/plugin-cli": "^2.0.0", "@tauri-apps/plugin-cli": "^2.0.0",
"@tauri-apps/plugin-http": "^2.0.0", "@tauri-apps/plugin-http": "^2.0.0",
"@tauri-apps/plugin-shell": "~2",
"@tinymce/tinymce-vue": "^5.1.1", "@tinymce/tinymce-vue": "^5.1.1",
"@types/lodash-es": "^4.17.12", "@types/lodash-es": "^4.17.12",
"@types/qs": "^6.9.15", "@types/qs": "^6.9.15",
"@vitejs/plugin-vue-jsx": "^3.1.0", "@vitejs/plugin-vue-jsx": "^3.1.0",
"dayjs": "^1.11.10", "dayjs": "^1.11.10",
"defu": "^6.1.4", "defu": "^6.1.4",
"element-plus": "^2.7.1", "element-plus": "^2.8.6",
"javascript-obfuscator": "^4.1.0",
"less": "^4.2.0", "less": "^4.2.0",
"lodash-es": "^4.17.21", "lodash-es": "^4.17.21",
"nuxt": "^3.11.2", "nuxt": "^3.11.2",
@@ -35,7 +35,9 @@
"typescript": "^5.4.5", "typescript": "^5.4.5",
"vue": "^3.4.24", "vue": "^3.4.24",
"vue-clipboard3": "^2.0.0", "vue-clipboard3": "^2.0.0",
"xlsx": "^0.18.5", "xlsx": "^0.18.5"
"@tauri-apps/plugin-shell": "~2" },
"dependencies": {
"@tauri-apps/plugin-autostart": "~2"
} }
} }
+28
View File
@@ -0,0 +1,28 @@
<template>
<div class="h-full overflow-auto flex flex-col items-start px-[25px]">
<div>
<ElCheckbox v-model="mainStore.config.disableIpv6">不使用IPv6</ElCheckbox>
</div>
<div><ElCheckbox v-model="mainStore.config.disbleListenner">不监听任何端口只连接到对等节点</ElCheckbox></div>
<div><ElCheckbox v-model="mainStore.config.enablExitNode">允许此节点成为出口节点</ElCheckbox></div>
<div><ElCheckbox v-model="mainStore.config.disableEncryption">禁用对等节点通信的加密默认为false必须与对等节点相同</ElCheckbox></div>
<div><ElCheckbox v-model="mainStore.config.multiThread">使用多线程运行时默认为单线程</ElCheckbox></div>
<div><ElCheckbox v-model="mainStore.config.noTun">不创建TUN设备可以使用子网代理访问节点</ElCheckbox></div>
<div><ElCheckbox v-model="mainStore.config.useSmoltcp">为子网代理启用smoltcp堆栈</ElCheckbox></div>
<div><ElCheckbox v-model="mainStore.config.latencyfirst">延迟优先模式将尝试使用最低延迟路径转发流量默认使用最短路径</ElCheckbox></div>
<div><ElCheckbox v-model="mainStore.config.disableUdpHolePunching">禁用UDP打洞功能</ElCheckbox></div>
<div>
<ElCheckbox v-model="mainStore.config.relayAllPeerrpc">转发所有对等节点的RPC数据包即使对等节点不在转发网络白名</ElCheckbox>
</div>
</div>
</template>
<script setup lang="ts">
import useMainStore from "@/stores/index";
import { getCurrentWindow } from "@tauri-apps/api/window";
const mainStore = useMainStore();
const appWindow = getCurrentWindow();
mainStore.$subscribe((...a) => {
// console.log("subscribe", a);
appWindow.emitTo("main", "config", { config: { ...mainStore.config } });
});
</script>
+25
View File
@@ -0,0 +1,25 @@
<template>
<div class="h-full flex flex-col gap-[10px]">
<ElRadioGroup v-model="mainStore.cidrEnable">
<ElRadioButton :value="true">开启</ElRadioButton>
<ElRadioButton :value="false">关闭</ElRadioButton>
</ElRadioGroup>
<div class="flex-1 overflow-auto">
<ElInput
placeholder="例如: 192.168.1.0/24 一行一个"
v-model="mainStore.config.proxyNetworks"
type="textarea"
:rows="30"
resize="none"></ElInput>
</div>
</div>
</template>
<script setup lang="ts">
import useMainStore from "@/stores/index";
import { getCurrentWindow } from "@tauri-apps/api/window";
const mainStore = useMainStore();
const appWindow = getCurrentWindow();
mainStore.$subscribe((...a) => {
appWindow.emitTo("main", "config", { cidrEnable: mainStore.cidrEnable, config: { ...mainStore.config } });
});
</script>
+355 -70
View File
@@ -13,26 +13,26 @@
<ElTag <ElTag
effect="dark" effect="dark"
:type="data.isSuccessGetIp ? 'success' : 'info'"> :type="data.isSuccessGetIp ? 'success' : 'info'">
{{ data.isSuccessGetIp ? "联机成功" : "联机中" }} {{ data.isSuccessGetIp ? "联机成功" : data.isStart && !data.isSuccessGetIp ? "联机中" : "未联机" }}
</ElTag> </ElTag>
<ElButton <ElButton
v-if="!data.coreVersion" v-if="!data.coreVersion"
@click="getCoreVersion(true)" @click="getCoreVersion(true)">
>获取工具版本</ElButton 获取工具版本
> </ElButton>
<ElTag <ElTag
v-else v-else
type="info" type="info">
>{{ data.coreVersion }}</ElTag core-{{ data.coreVersion }}
> </ElTag>
<ElButton <ElButton
:disabled="data.isStart" :disabled="data.isStart"
:loading="data.update" :loading="data.update"
type="warning" type="warning"
@click="handleUpdateCore" @click="handleUpdateCore"
size="small" size="small">
>{{ data.coreVersion ? "更新" : "下载" }}</ElButton {{ data.coreVersion ? "更新" : "下载" }}
> </ElButton>
</div> </div>
</template> </template>
<ElSelect <ElSelect
@@ -47,6 +47,7 @@
placeholder="协议" placeholder="协议"
multiple multiple
collapse-tags collapse-tags
@click.stop
v-model="config.protocol" v-model="config.protocol"
@change="handleServerUrlChange"> @change="handleServerUrlChange">
<ElOption <ElOption
@@ -68,8 +69,9 @@
@click.stop="handleDeleteServerUrl(item)" @click.stop="handleDeleteServerUrl(item)"
round round
:icon="Delete" :icon="Delete"
type="danger"></ElButton></div type="danger"></ElButton>
></ElOption> </div>
</ElOption>
</ElSelect> </ElSelect>
</ElFormItem> </ElFormItem>
<div class="flex flex-wrap gap-[0_10px] items-center"> <div class="flex flex-wrap gap-[0_10px] items-center">
@@ -149,90 +151,143 @@
</ElFormItem> </ElFormItem>
</div> </div>
<div class="flex items-start gap-[0_30px]"> <div class="flex items-start gap-[0_30px]">
<div> <div class="w-[95px]">
<div> <div>
<ElButton <ElButton
:type="!data.isStart ? 'primary' : 'danger'" :type="!data.isStart ? 'primary' : 'danger'"
:disabled="data.startLoading || !data.coreVersion || data.update" :disabled="data.startLoading || !data.coreVersion || data.update"
@click="handleConnection" @click="handleConnection"
size="default"> size="default">
{{ !data.isStart ? "开始联机" : "停止联机" }} {{ !data.isStart ? "启动联机" : "停止联机" }}
</ElButton> </ElButton>
</div> </div>
<div class="mt-[6px]"> <div class="mt-[6px] pl-[2px]">
<ElButton <!-- <ElButtonGroup> -->
type="info" <ElTooltip
@click="handleShowDialog" placement="left"
size="default"> content="日志">
日志信息 <ElButton
</ElButton> :type="!data.logVisible ? 'info' : 'warning'"
@click="handleShowLogDialog"
:icon="List"
size="small"
plain></ElButton>
</ElTooltip>
<ElTooltip
placement="left"
content="成员">
<ElButton
@click="handleShowMemberDialog"
:icon="UserFilled"
plain
type="success"
size="small"></ElButton>
</ElTooltip>
<!-- </ElButtonGroup> -->
</div> </div>
</div> </div>
<div> <div>
<ElCheckbox <ElCheckbox
v-model="config.disbleP2p" v-model="config.disbleP2p"
size="small"> size="small">
禁用p2p 强制中转
</ElCheckbox> </ElCheckbox>
<ElCheckbox <!-- <ElCheckbox
v-model="config.disableIpv6" v-model="config.disableIpv6"
size="small"> size="small"
>
禁用ipv6 禁用ipv6
</ElCheckbox> </ElCheckbox> -->
<ElCheckbox <ElCheckbox
v-model="config.disbleListenner" @change="handleAutoStart"
:model-value="config.autoStart"
size="small"> size="small">
禁用端口监听 开机自启
</ElCheckbox> </ElCheckbox>
<ElLink <!-- <ElCheckbox
class="!text-[11px] pb-[2px] ml-[15px]" v-model="config.disbleListenner"
type="info" size="small"
:underline="false" >
@click="open('https://github.com/EasyTier/EasyTier/releases')"> 禁用端口监听
easytier发布页 </ElCheckbox> -->
</ElLink>
<div> <div>
<ElButton
@click="handleShowCidrDialog"
:icon="Share"
>子网代理</ElButton
>
<ElButton
@click="handleShowAdvanceDialog"
:icon="Setting"
>高级选项</ElButton
>
</div>
<div class="flex items-center gap-[0_5px]">
<div>
<ElLink
class="!text-[11px]"
type="info"
:underline="false"
@click="open('https://github.com/dechamps/WinIPBroadcast/releases/tag/winipbroadcast-1.6')">
WinIPBroadcast
<ElTooltip content="找不到游戏房间时,就开启它后再刷新尝试(默认开启)">
<ElIcon class="ml-[3px]"><QuestionFilled /></ElIcon>
</ElTooltip>
</ElLink>
<ElSwitch
inline-prompt
:model-value="data.winipBcStart"
@change="handleWinipBcStart"
size="small"
label="WinIPBroadcast"
active-text="开启"
inactive-text="关闭"></ElSwitch>
</div>
<ElLink <ElLink
class="!text-[11px]" class="!text-[11px] pb-[2px] ml-[15px]"
type="danger" type="info"
:underline="false" :underline="false"
@click="open('https://github.com/dechamps/WinIPBroadcast/releases/tag/winipbroadcast-1.6')"> @click="open('https://github.com/EasyTier/EasytierGame')">
找不到房间建议安装WinIPBroadcast 主页
</ElLink> </ElLink>
</div> </div>
</div> </div>
</div> </div>
</ElForm> </ElForm>
<ElDialog
title="日志信息"
top="0"
v-model="data.visible"
width="100%"
class="!h-full !m-0">
<ElInput
type="textarea"
rows="10"
v-model="data.log"
resize="none"
readonly />
</ElDialog>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { invoke } from "@tauri-apps/api/core"; import { invoke } from "@tauri-apps/api/core";
import { listen } from "@tauri-apps/api/event"; import { listen } from "@tauri-apps/api/event";
import { open } from "@tauri-apps/plugin-shell"; import { open, Command } from "@tauri-apps/plugin-shell";
import { QuestionFilled, Delete } from "@element-plus/icons-vue"; import { QuestionFilled, Delete, List, UserFilled, Setting, Share } from "@element-plus/icons-vue";
import { reactive, onBeforeUnmount, onMounted } from "vue"; import { reactive, onBeforeUnmount, onMounted } from "vue";
import { useTray } from "~/composables/tray"; import { useTray, setTrayRunState } from "~/composables/tray";
import useMainStore from "@/stores/index"; import useMainStore from "@/stores/index";
import { ElMessage } from "element-plus"; import { ElMessage } from "element-plus";
import { getCurrentWindow, PhysicalPosition } from "@tauri-apps/api/window";
import { getAllWebviewWindows } from "@tauri-apps/api/webviewWindow";
import etWindows from "@/composables/windows";
import * as tauriAutoStart from "@tauri-apps/plugin-autostart";
let is_close = false;
const tray = await useTray(true, async () => {
is_close = true;
await invoke("stop_command", { child_id: listenObj.thread_id || 0 });
await invoke("stop_command", { child_id: data.winipBcPid || 0 });
});
useTray(true);
const mainStore = useMainStore(); const mainStore = useMainStore();
const config = mainStore.config; const config = mainStore.config;
// console.log(config);
const protocols = ["tcp", "udp", "ws", "wss", "wg"]; const protocols = ["tcp", "udp", "ws", "wss", "wg"];
const data = reactive({ const data = reactive({
visible: false, logVisible: false,
cidrVisible: false,
advanceVisible: false,
winipBcPid: 0, //WinIPBroadcast进程id
winipBcStart: false,
memberVisible: false,
log: "", log: "",
update: false, update: false,
releaseList: [], releaseList: [],
@@ -242,6 +297,19 @@
isStart: false, isStart: false,
}); });
const closePrevent = async () => {
const appWindow = getCurrentWindow();
if (appWindow.label == "main") {
appWindow.onCloseRequested(async (event) => {
console.log(appWindow.label);
if (!is_close) {
event.preventDefault();
appWindow.hide();
}
});
}
};
const handleDeleteServerUrl = (url: string) => { const handleDeleteServerUrl = (url: string) => {
const newBasePeers = [...mainStore.basePeers]; const newBasePeers = [...mainStore.basePeers];
const idx = newBasePeers.indexOf(url); const idx = newBasePeers.indexOf(url);
@@ -261,19 +329,22 @@
const listenObj: { [key: string]: any } = { const listenObj: { [key: string]: any } = {
unListenOutPut: null, unListenOutPut: null,
unListenThreadId: null, unListenThreadId: null,
unListenReleaseList: null, unListenConfigStart: null,
thread_id: null, thread_id: null,
async listenOutput() { async listenOutput() {
const unListen = await listen("command-output", (event) => { const appWindow = getCurrentWindow();
const unListen = await listen("command-output", async (event) => {
data.isStart = true; data.isStart = true;
if (event.payload) { if (event.payload) {
data.startLoading = false; data.startLoading = false;
let ipv4 = /new: Some\((\d+\.\d+\.\d+\.\d+)\/.*\)/g.exec(event.payload as string)?.[1]; let ipv4 = /new: Some\((\d+\.\d+\.\d+\.\d+)\/.*\)/g.exec(event.payload as string)?.[1];
if (ipv4) { if (ipv4) {
data.isSuccessGetIp = true; data.isSuccessGetIp = true;
await setTrayRunState(tray, true);
config.ipv4 = ipv4; config.ipv4 = ipv4;
} }
} }
appWindow.emitTo("log", "logs", data.log);
data.log += (event.payload as string) + "\n"; data.log += (event.payload as string) + "\n";
}); });
this.unListenOutPut = unListen; this.unListenOutPut = unListen;
@@ -286,14 +357,14 @@
}); });
this.unListenThreadId = unListen; this.unListenThreadId = unListen;
}, },
async listenConfigStart() {
async releaseListListener() { const unListen = await listen("config", (event) => {
const unListen = await listen("release-list", (event) => { // console.log("config", event.payload);
if (event.payload) { const ipv4 = config.ipv4;
console.log(event.payload); mainStore.$patch(event.payload as any);
} config.ipv4 = ipv4;
}); });
this.unListenReleaseList = unListen; this.unListenConfigStart = unListen;
}, },
}; };
@@ -330,12 +401,13 @@
ElMessage.error(`获取版本失败`); ElMessage.error(`获取版本失败`);
return [false, null, null]; return [false, null, null];
} }
} else {
ElMessage.error(`获取版本失败`);
} }
return [false, null, null]; return [false, null, null];
}; };
const handleUpdateCore = async () => { const handleUpdateCore = async () => {
// easytier-windows-x86_64-v2.0.3.zip
data.update = true; data.update = true;
await getCoreVersion(); await getCoreVersion();
const [isNeedUpdate, downloadUrl, latestVersionFileName] = await checkUpdate(); const [isNeedUpdate, downloadUrl, latestVersionFileName] = await checkUpdate();
@@ -353,19 +425,101 @@
data.releaseList = list as never[]; data.releaseList = list as never[];
}; };
const getWinIpBroadcastPid = async () => {
const pid = await invoke("search_pid_by_pname", { target_process_name: "WinIPBroadcast" });
data.winipBcPid = (pid as number) || 0;
if (data.winipBcPid && data.winipBcPid > 0) {
data.winipBcStart = true;
} else {
data.winipBcStart = false;
}
};
const handleWinipBcStart = async () => {
if (!data.winipBcStart) {
try {
await invoke("stop_command", { child_id: data.winipBcPid || 0 });
const child = await Command.create("WinIPBroadcast", ["run"]).spawn();
data.winipBcPid = child.pid || 0;
if (data.winipBcPid) {
data.winipBcStart = true;
} else {
ElMessage.error(`启动失败`);
}
} catch (err) {
ElMessage.error(`启动失败`);
console.log(err);
}
} else {
await invoke("stop_command", { child_id: data.winipBcPid || 0 });
await getWinIpBroadcastPid();
}
};
const initStartWinIpBroadcast = async () => {
await getWinIpBroadcastPid();
if (!data.winipBcStart) {
await handleWinipBcStart();
}
};
const handleAutoStart = async () => {
let is_enable = await tauriAutoStart.isEnabled();
if (!config.autoStart && !is_enable) {
try {
await tauriAutoStart.enable();
} catch (err) {
ElMessage.error(`开机自启失败`);
}
} else {
try {
await tauriAutoStart.disable();
} catch (err) {
// ElMessage.error(`取消自启失败`);
}
}
is_enable = await tauriAutoStart.isEnabled();
if (!is_enable) {
config.autoStart = false;
} else {
config.autoStart = true;
}
};
const initAutoStart = async () => {
try {
const is_enable = await tauriAutoStart.isEnabled();
if (!is_enable) {
config.autoStart = false;
} else {
config.autoStart = true;
}
} catch (err) {
config.autoStart = false;
}
};
let logsTimer: NodeJS.Timeout | null = null;
onMounted(async () => { onMounted(async () => {
// await handleUpdateCore(); //默认不自动更新 // await handleUpdateCore(); //默认不自动更新
await initAutoStart();
await initStartWinIpBroadcast();
await getCoreVersion(); await getCoreVersion();
await listenObj.releaseListListener();
await listenObj.listenThreadId(); await listenObj.listenThreadId();
await listenObj.listenConfigStart();
closePrevent();
}); });
onBeforeUnmount(() => { onBeforeUnmount(() => {
unListenAll(); unListenAll();
listenObj.unListenReleaseList && listenObj.unListenReleaseList(); listenObj.unListenReleaseList && listenObj.unListenReleaseList();
listenObj.unListenConfigStart && listenObj.unListenConfigStart();
logsTimer && clearInterval(logsTimer);
}); });
const getArgs = () => { const getArgs = () => {
// console.log(config.proxyNetworks);
const args = []; const args = [];
if (config.dhcp) { if (config.dhcp) {
args.push("-d"); args.push("-d");
@@ -395,13 +549,61 @@
if (config.disbleListenner) { if (config.disbleListenner) {
args.push("--no-listener"); args.push("--no-listener");
} }
if (mainStore.cidrEnable && config.proxyNetworks) {
// console.log(config.proxyNetworks);
const reg = /\d+\.\d+\.\d+\.\d+\/\d+/g;
const formatProxyNetworks = config.proxyNetworks
.split("\n")
.map((item) => item.trim())
.filter((item) => item && reg.test(item));
args.push("--proxy-networks", ...formatProxyNetworks);
config.proxyNetworks = formatProxyNetworks.join("\n");
}
if (config.disableEncryption) {
args.push("--disable-encryption");
}
if (config.multiThread) {
args.push("--multi-thread");
}
if (config.enablExitNode) {
args.push("--enable-exit-node");
}
if (config.noTun) {
args.push("--no-tun");
}
if (config.latencyfirst) {
args.push("--latency-first");
}
if (config.useSmoltcp) {
args.push("--use-smoltcp");
}
if (config.disableUdpHolePunching) {
args.push("--disable-udp-hole-punching");
}
if (config.relayAllPeerrpc) {
args.push("--relay-all-peer-rpc");
}
return args; return args;
}; };
const reset = async () => { const reset = async () => {
data.isStart = false; data.isStart = false;
data.isSuccessGetIp = false; data.isSuccessGetIp = false;
config.ipv4 = ""; if (config.dhcp) {
config.ipv4 = "";
}
const memberDialog = await getAllWebviewWindows();
const memberDialogs = memberDialog.filter((item) => item.label === "member");
if (memberDialogs && memberDialogs.length > 0) {
data.memberVisible = false;
for (const memberDialog of memberDialogs) {
const isVisible = await memberDialog.isVisible();
if (isVisible) {
await memberDialog.destroy();
}
}
}
await setTrayRunState(tray, false);
await unListenAll(); await unListenAll();
}; };
@@ -409,6 +611,7 @@
if (data.isStart) { if (data.isStart) {
await reset(); await reset();
} else { } else {
data.log = ""; //清空日志
data.startLoading = true; data.startLoading = true;
await unListenAll(); await unListenAll();
await listenObj.listenOutput(); await listenObj.listenOutput();
@@ -419,7 +622,89 @@
} }
}; };
const handleShowDialog = async () => { const handleShowMemberDialog = async () => {
data.visible = true; if (!data.isStart) {
return ElMessage.warning("请先开始联机");
}
if (!mainStore.config.ipv4) {
return ElMessage.warning("请等待获取IP");
}
await etWindows(
"member",
{
title: "成员列表",
width: 470,
height: 380,
url: "#/member",
},
() => {
data.memberVisible = true;
},
() => {
data.memberVisible = false;
}
);
};
const handleShowLogDialog = async () => {
await etWindows(
"log",
{
title: "联机日志",
width: 600,
height: 380,
resizable: false,
url: "#/log",
},
(_, appWindow) => {
data.logVisible = true;
logsTimer && clearInterval(logsTimer);
logsTimer = setInterval(() => {
appWindow.emitTo("log", "logs", data.log);
}, 600);
},
() => {
data.logVisible = false;
}
);
};
const handleShowCidrDialog = async () => {
await etWindows(
"cidr",
{
title: "子网代理",
width: 600,
height: 380,
resizable: false,
url: "#/cidr",
},
(_, appWindow) => {
data.cidrVisible = true;
},
() => {
data.cidrVisible = false;
}
);
};
const handleShowAdvanceDialog = async () => {
await etWindows(
"advance",
{
title: "高级选项",
width: 600,
height: 380,
resizable: false,
url: "#/advance",
},
(_, appWindow) => {
data.advanceVisible = true;
},
() => {
data.advanceVisible = false;
}
);
}; };
</script> </script>
+33
View File
@@ -0,0 +1,33 @@
<template>
<ElInput
type="textarea"
:rows="17"
v-model="data.log"
resize="none"
readonly
placeholder="等待日志中,请先'启动联机'..."
/>
</template>
<script setup lang="ts">
import { listen, type UnlistenFn } from "@tauri-apps/api/event";
import { reactive, onMounted, onBeforeUnmount } from "vue";
const data = reactive({
log: ""
});
const listenStart = async () => {
const unListen = await listen("logs", event => {
data.log = (event.payload as string) || "";
});
return unListen;
};
let unlistenStart: UnlistenFn | null = null;
onMounted(async () => {
unlistenStart = await listenStart();
});
onBeforeUnmount(() => {
unlistenStart && unlistenStart();
});
</script>
+76
View File
@@ -0,0 +1,76 @@
<template>
<div class="overflow-auto h-full">
<div class="w-[1200px]">
<span v-if="!data.member || data.member.length <= 0">{{ "等待成员信息中..." }}</span>
<ElTable
stripe
:data="data.member"
v-else
>
<ElTableColumn
v-for="prop in showTableHeader"
:label="prop[1]"
:key="prop[0]"
>
<template #default="{ row }">
<span v-if="prop[0] == 'loss_rate'">
{{ row[prop[0]] && row[prop[0]] != "-" ? Number(row[prop[0]] * 100).toFixed(2) + "%" : row[prop[0]] }}
</span>
<span v-else-if="prop[0] != 'cost'">{{ row[prop[0]] }}</span>
<ElTag
v-else
effect="dark"
:type="row[prop[0]] == 'p2p' ? 'success' : 'info'"
>
{{ row[prop[0]] }}
</ElTag>
</template>
</ElTableColumn>
</ElTable>
</div>
</div>
</template>
<script setup lang="ts">
import { invoke } from "@tauri-apps/api/core";
import { reactive, onMounted, onBeforeUnmount } from "vue";
import { parsePeerInfo } from "@/utils";
const data = reactive<{ member: any[] }>({
member: []
});
const showTableHeader = [
["ipv4", "虚拟网IP"],
["hostname", "主机名"],
["cost", "路由"],
["lat_ms", "延迟/ms"],
["loss_rate", "丢包率"],
["version", "版本"]
];
const listenOutput = async () => {
const member = await invoke("get_members_by_cli");
const peerInfo = parsePeerInfo(member as string);
peerInfo.forEach(value => {
if (value.cost === "Local") {
value.cost = "本机";
}
if (value.ipv4 && value.ipv4.includes("/")) {
value.ipv4 = value.ipv4.split("/")[0];
}
});
data.member = peerInfo;
};
let timer: NodeJS.Timeout | null = null;
onMounted(async () => {
listenOutput();
timer = setInterval(() => {
listenOutput();
}, 1000 * 10);
});
onBeforeUnmount(() => {
timer && clearInterval(timer);
});
</script>
+20 -430
View File
File diff suppressed because it is too large Load Diff
+1 -3
View File
@@ -1,6 +1,4 @@
# Generated by Cargo # Generated by Cargo
# will have compiled files and executables # will have compiled files and executables
/target/ /target/
/gen/schemas /gen/schemas
/easytier-windows-x86_64-v2.0.3.zip
/easytier-windows-x86_64/
+377 -58
View File
@@ -288,6 +288,17 @@ version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
[[package]]
name = "auto-launch"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f012b8cc0c850f34117ec8252a44418f2e34a2cf501de89e29b241ae5f79471"
dependencies = [
"dirs 4.0.0",
"thiserror",
"winreg 0.10.1",
]
[[package]] [[package]]
name = "autocfg" name = "autocfg"
version = "1.4.0" version = "1.4.0"
@@ -411,9 +422,9 @@ dependencies = [
[[package]] [[package]]
name = "brotli" name = "brotli"
version = "6.0.0" version = "7.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" checksum = "cc97b8f16f944bba54f0433f07e30be199b6dc2bd25937444bbad560bcea29bd"
dependencies = [ dependencies = [
"alloc-no-stdlib", "alloc-no-stdlib",
"alloc-stdlib", "alloc-stdlib",
@@ -810,6 +821,25 @@ dependencies = [
"crossbeam-utils", "crossbeam-utils",
] ]
[[package]]
name = "crossbeam-deque"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.20" version = "0.8.20"
@@ -960,13 +990,33 @@ dependencies = [
"subtle", "subtle",
] ]
[[package]]
name = "dirs"
version = "4.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
dependencies = [
"dirs-sys 0.3.7",
]
[[package]] [[package]]
name = "dirs" name = "dirs"
version = "5.0.1" version = "5.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225"
dependencies = [ dependencies = [
"dirs-sys", "dirs-sys 0.4.1",
]
[[package]]
name = "dirs-sys"
version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
dependencies = [
"libc",
"redox_users",
"winapi",
] ]
[[package]] [[package]]
@@ -1059,20 +1109,29 @@ checksum = "0d6ef0072f8a535281e4876be788938b528e9a1d43900b82c2569af7da799125"
[[package]] [[package]]
name = "easytier-game" name = "easytier-game"
version = "1.0.3" version = "1.0.8"
dependencies = [ dependencies = [
"log", "log",
"planif",
"reqwest", "reqwest",
"serde", "serde",
"serde_json", "serde_json",
"sysinfo",
"tauri", "tauri",
"tauri-build", "tauri-build",
"tauri-plugin-autostart",
"tauri-plugin-log", "tauri-plugin-log",
"tauri-plugin-shell", "tauri-plugin-shell",
"tauri-plugin-single-instance", "tauri-plugin-single-instance",
"zip", "zip",
] ]
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]] [[package]]
name = "embed-resource" name = "embed-resource"
version = "2.5.0" version = "2.5.0"
@@ -1084,7 +1143,7 @@ dependencies = [
"rustc_version", "rustc_version",
"toml 0.8.2", "toml 0.8.2",
"vswhom", "vswhom",
"winreg", "winreg 0.52.0",
] ]
[[package]] [[package]]
@@ -2106,7 +2165,19 @@ version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b1fb8864823fad91877e6caea0baca82e49e8db50f8e5c9f9a453e27d3330fc" checksum = "5b1fb8864823fad91877e6caea0baca82e49e8db50f8e5c9f9a453e27d3330fc"
dependencies = [ dependencies = [
"jsonptr", "jsonptr 0.4.7",
"serde",
"serde_json",
"thiserror",
]
[[package]]
name = "json-patch"
version = "3.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "863726d7afb6bc2590eeff7135d923545e5e964f004c2ccf8716c25e70a86f08"
dependencies = [
"jsonptr 0.6.3",
"serde", "serde",
"serde_json", "serde_json",
"thiserror", "thiserror",
@@ -2123,6 +2194,16 @@ dependencies = [
"serde_json", "serde_json",
] ]
[[package]]
name = "jsonptr"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5dea2b27dd239b2556ed7a25ba842fe47fd602e7fc7433c2a8d6106d4d9edd70"
dependencies = [
"serde",
"serde_json",
]
[[package]] [[package]]
name = "keyboard-types" name = "keyboard-types"
version = "0.7.0" version = "0.7.0"
@@ -2413,6 +2494,15 @@ version = "0.1.14"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb" checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
[[package]]
name = "ntapi"
version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8a3895c6391c39d7fe7ebc444a87eb2991b2a0bc718fdabd071eec617fc68e4"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "num-conv" name = "num-conv"
version = "0.1.0" version = "0.1.0"
@@ -2465,7 +2555,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1"
dependencies = [ dependencies = [
"malloc_buf", "malloc_buf",
"objc_exception",
] ]
[[package]] [[package]]
@@ -2473,6 +2562,9 @@ name = "objc-sys"
version = "0.3.5" version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "objc2" name = "objc2"
@@ -2500,6 +2592,30 @@ dependencies = [
"objc2-quartz-core", "objc2-quartz-core",
] ]
[[package]]
name = "objc2-cloud-kit"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009"
dependencies = [
"bitflags 2.6.0",
"block2",
"objc2",
"objc2-core-location",
"objc2-foundation",
]
[[package]]
name = "objc2-contacts"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889"
dependencies = [
"block2",
"objc2",
"objc2-foundation",
]
[[package]] [[package]]
name = "objc2-core-data" name = "objc2-core-data"
version = "0.2.2" version = "0.2.2"
@@ -2524,6 +2640,18 @@ dependencies = [
"objc2-metal", "objc2-metal",
] ]
[[package]]
name = "objc2-core-location"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781"
dependencies = [
"block2",
"objc2",
"objc2-contacts",
"objc2-foundation",
]
[[package]] [[package]]
name = "objc2-encode" name = "objc2-encode"
version = "4.0.3" version = "4.0.3"
@@ -2542,6 +2670,18 @@ dependencies = [
"objc2", "objc2",
] ]
[[package]]
name = "objc2-link-presentation"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398"
dependencies = [
"block2",
"objc2",
"objc2-app-kit",
"objc2-foundation",
]
[[package]] [[package]]
name = "objc2-metal" name = "objc2-metal"
version = "0.2.2" version = "0.2.2"
@@ -2568,21 +2708,71 @@ dependencies = [
] ]
[[package]] [[package]]
name = "objc_exception" name = "objc2-symbols"
version = "0.1.2" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad970fb455818ad6cba4c122ad012fae53ae8b4795f86378bce65e4f6bab2ca4" checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc"
dependencies = [ dependencies = [
"cc", "objc2",
"objc2-foundation",
] ]
[[package]] [[package]]
name = "objc_id" name = "objc2-ui-kit"
version = "0.1.1" version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c92d4ddb4bd7b50d730c215ff871754d0da6b2178849f8a2a2ab69712d0c073b" checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f"
dependencies = [ dependencies = [
"objc", "bitflags 2.6.0",
"block2",
"objc2",
"objc2-cloud-kit",
"objc2-core-data",
"objc2-core-image",
"objc2-core-location",
"objc2-foundation",
"objc2-link-presentation",
"objc2-quartz-core",
"objc2-symbols",
"objc2-uniform-type-identifiers",
"objc2-user-notifications",
]
[[package]]
name = "objc2-uniform-type-identifiers"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe"
dependencies = [
"block2",
"objc2",
"objc2-foundation",
]
[[package]]
name = "objc2-user-notifications"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3"
dependencies = [
"bitflags 2.6.0",
"block2",
"objc2",
"objc2-core-location",
"objc2-foundation",
]
[[package]]
name = "objc2-web-kit"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "68bc69301064cebefc6c4c90ce9cba69225239e4b8ff99d445a2b5563797da65"
dependencies = [
"bitflags 2.6.0",
"block2",
"objc2",
"objc2-app-kit",
"objc2-foundation",
] ]
[[package]] [[package]]
@@ -2920,6 +3110,14 @@ version = "0.3.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2"
[[package]]
name = "planif"
version = "1.0.0"
source = "git+https://github.com/mattrobineau/planif?tag=1.0.1#90e228e2bc0f142b16a0ba415ec242e1c836cc35"
dependencies = [
"windows 0.48.0",
]
[[package]] [[package]]
name = "plist" name = "plist"
version = "1.7.0" version = "1.7.0"
@@ -3172,6 +3370,26 @@ version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539"
[[package]]
name = "rayon"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]
[[package]] [[package]]
name = "redox_syscall" name = "redox_syscall"
version = "0.5.7" version = "0.5.7"
@@ -3913,6 +4131,20 @@ dependencies = [
"futures-core", "futures-core",
] ]
[[package]]
name = "sysinfo"
version = "0.32.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3b5ae3f4f7d64646c46c4cae4e3f01d1c5d255c7406fdd7c7f999a94e488791"
dependencies = [
"core-foundation-sys",
"libc",
"memchr",
"ntapi",
"rayon",
"windows 0.57.0",
]
[[package]] [[package]]
name = "system-configuration" name = "system-configuration"
version = "0.6.1" version = "0.6.1"
@@ -3980,7 +4212,7 @@ dependencies = [
"tao-macros", "tao-macros",
"unicode-segmentation", "unicode-segmentation",
"url", "url",
"windows", "windows 0.58.0",
"windows-core 0.58.0", "windows-core 0.58.0",
"windows-version", "windows-version",
"x11-dl", "x11-dl",
@@ -4011,13 +4243,13 @@ checksum = "61c41af27dd6d1e27b1b16b489db798443478cef1f06a660c96db617ba5de3b1"
[[package]] [[package]]
name = "tauri" name = "tauri"
version = "2.0.2" version = "2.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5920aad0804ea5e86808d4b6e8753d3bcbae7efc8f4e41a4da00b45427559868" checksum = "d3889b392db6d32a105d3757230ea0220090b8f94c90d3e60b6c5eb91178ab1b"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"bytes", "bytes",
"dirs", "dirs 5.0.1",
"dunce", "dunce",
"embed_plist", "embed_plist",
"futures-util", "futures-util",
@@ -4057,21 +4289,21 @@ dependencies = [
"webkit2gtk", "webkit2gtk",
"webview2-com", "webview2-com",
"window-vibrancy", "window-vibrancy",
"windows", "windows 0.58.0",
] ]
[[package]] [[package]]
name = "tauri-build" name = "tauri-build"
version = "2.0.1" version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "935f9b3c49b22b3e2e485a57f46d61cd1ae07b1cbb2ba87387a387caf2d8c4e7" checksum = "9f96827ccfb1aa40d55d0ded79562d18ba18566657a553f992a982d755148376"
dependencies = [ dependencies = [
"anyhow", "anyhow",
"cargo_toml", "cargo_toml",
"dirs", "dirs 5.0.1",
"glob", "glob",
"heck 0.5.0", "heck 0.5.0",
"json-patch", "json-patch 3.0.1",
"schemars", "schemars",
"semver", "semver",
"serde", "serde",
@@ -4084,14 +4316,14 @@ dependencies = [
[[package]] [[package]]
name = "tauri-codegen" name = "tauri-codegen"
version = "2.0.1" version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95d7443dd4f0b597704b6a14b964ee2ed16e99928d8e6292ae9825f09fbcd30e" checksum = "8947f16f47becd9e9cd39b74ee337fd1981574d78819be18e4384d85e5a0b82f"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"brotli", "brotli",
"ico", "ico",
"json-patch", "json-patch 2.0.0",
"plist", "plist",
"png", "png",
"proc-macro2", "proc-macro2",
@@ -4111,9 +4343,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-macros" name = "tauri-macros"
version = "2.0.1" version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d2c0963ccfc3f5194415f2cce7acc975942a8797fbabfb0aa1ed6f59326ae7f" checksum = "8bd1c8d4a66799d3438747c3a79705cd665a95d6f24cb5f315413ff7a981fe2a"
dependencies = [ dependencies = [
"heck 0.5.0", "heck 0.5.0",
"proc-macro2", "proc-macro2",
@@ -4140,6 +4372,21 @@ dependencies = [
"walkdir", "walkdir",
] ]
[[package]]
name = "tauri-plugin-autostart"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bba6bb936e0fd0a58ed958b49e2e423dd40949c9d9425cc991be996959e3838e"
dependencies = [
"auto-launch",
"log",
"serde",
"serde_json",
"tauri",
"tauri-plugin",
"thiserror",
]
[[package]] [[package]]
name = "tauri-plugin-log" name = "tauri-plugin-log"
version = "2.0.1" version = "2.0.1"
@@ -4164,9 +4411,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-plugin-shell" name = "tauri-plugin-shell"
version = "2.0.1" version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "371fb9aca2823990a2d0db7970573be5fdf07881fcaa2b835b29631feb84aec1" checksum = "0ad7880c5586b6b2104be451e3d7fc0f3800c84bda69e9ba81c828f87cb34267"
dependencies = [ dependencies = [
"encoding_rs", "encoding_rs",
"log", "log",
@@ -4200,9 +4447,9 @@ dependencies = [
[[package]] [[package]]
name = "tauri-runtime" name = "tauri-runtime"
version = "2.0.1" version = "2.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af12ad1af974b274ef1d32a94e6eba27a312b429ef28fcb98abc710df7f9151d" checksum = "a1ef7363e7229ac8d04e8a5d405670dbd43dde8fc4bc3bc56105c35452d03784"
dependencies = [ dependencies = [
"dpi", "dpi",
"gtk", "gtk",
@@ -4214,14 +4461,14 @@ dependencies = [
"tauri-utils", "tauri-utils",
"thiserror", "thiserror",
"url", "url",
"windows", "windows 0.58.0",
] ]
[[package]] [[package]]
name = "tauri-runtime-wry" name = "tauri-runtime-wry"
version = "2.0.1" version = "2.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e45e88aa0b11b302d836e6ea3e507a6359044c4a8bc86b865ba99868c695753d" checksum = "62fa2068e8498ad007b54d5773d03d57c3ff6dd96f8c8ce58beff44d0d5e0d30"
dependencies = [ dependencies = [
"gtk", "gtk",
"http", "http",
@@ -4239,15 +4486,15 @@ dependencies = [
"url", "url",
"webkit2gtk", "webkit2gtk",
"webview2-com", "webview2-com",
"windows", "windows 0.58.0",
"wry", "wry",
] ]
[[package]] [[package]]
name = "tauri-utils" name = "tauri-utils"
version = "2.0.1" version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c38b0230d6880cf6dd07b6d7dd7789a0869f98ac12146e0d18d1c1049215a045" checksum = "1fc65d6f5c54e56b66258948a6d9e47a82ea41f4b5a7612bfbdd1634c2913ed0"
dependencies = [ dependencies = [
"brotli", "brotli",
"cargo_metadata", "cargo_metadata",
@@ -4256,7 +4503,7 @@ dependencies = [
"glob", "glob",
"html5ever", "html5ever",
"infer", "infer",
"json-patch", "json-patch 2.0.0",
"kuchikiki", "kuchikiki",
"log", "log",
"memchr", "memchr",
@@ -4540,7 +4787,7 @@ checksum = "533fc2d4105e0e3d96ce1c71f2d308c9fbbe2ef9c587cab63dd627ab5bde218f"
dependencies = [ dependencies = [
"core-graphics", "core-graphics",
"crossbeam-channel", "crossbeam-channel",
"dirs", "dirs 5.0.1",
"libappindicator", "libappindicator",
"muda", "muda",
"objc2", "objc2",
@@ -4919,10 +5166,10 @@ checksum = "6f61ff3d9d0ee4efcb461b14eb3acfda2702d10dc329f339303fc3e57215ae2c"
dependencies = [ dependencies = [
"webview2-com-macros", "webview2-com-macros",
"webview2-com-sys", "webview2-com-sys",
"windows", "windows 0.58.0",
"windows-core 0.58.0", "windows-core 0.58.0",
"windows-implement", "windows-implement 0.58.0",
"windows-interface", "windows-interface 0.58.0",
] ]
[[package]] [[package]]
@@ -4943,7 +5190,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3a3e2eeb58f82361c93f9777014668eb3d07e7d174ee4c819575a9208011886" checksum = "a3a3e2eeb58f82361c93f9777014668eb3d07e7d174ee4c819575a9208011886"
dependencies = [ dependencies = [
"thiserror", "thiserror",
"windows", "windows 0.58.0",
"windows-core 0.58.0", "windows-core 0.58.0",
] ]
@@ -4992,6 +5239,25 @@ dependencies = [
"windows-version", "windows-version",
] ]
[[package]]
name = "windows"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f"
dependencies = [
"windows-targets 0.48.5",
]
[[package]]
name = "windows"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12342cb4d8e3b046f3d80effd474a7a02447231330ef77d71daa6fbc40681143"
dependencies = [
"windows-core 0.57.0",
"windows-targets 0.52.6",
]
[[package]] [[package]]
name = "windows" name = "windows"
version = "0.58.0" version = "0.58.0"
@@ -5011,19 +5277,42 @@ dependencies = [
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "windows-core"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d2ed2439a290666cd67ecce2b0ffaad89c2a56b976b736e6ece670297897832d"
dependencies = [
"windows-implement 0.57.0",
"windows-interface 0.57.0",
"windows-result 0.1.2",
"windows-targets 0.52.6",
]
[[package]] [[package]]
name = "windows-core" name = "windows-core"
version = "0.58.0" version = "0.58.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
dependencies = [ dependencies = [
"windows-implement", "windows-implement 0.58.0",
"windows-interface", "windows-interface 0.58.0",
"windows-result", "windows-result 0.2.0",
"windows-strings", "windows-strings",
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "windows-implement"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9107ddc059d5b6fbfbffdfa7a7fe3e22a226def0b2608f72e9d552763d3e1ad7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
]
[[package]] [[package]]
name = "windows-implement" name = "windows-implement"
version = "0.58.0" version = "0.58.0"
@@ -5035,6 +5324,17 @@ dependencies = [
"syn 2.0.79", "syn 2.0.79",
] ]
[[package]]
name = "windows-interface"
version = "0.57.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "29bee4b38ea3cde66011baa44dba677c432a78593e202392d1e9070cf2a7fca7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.79",
]
[[package]] [[package]]
name = "windows-interface" name = "windows-interface"
version = "0.58.0" version = "0.58.0"
@@ -5052,11 +5352,20 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0" checksum = "e400001bb720a623c1c69032f8e3e4cf09984deec740f007dd2b03ec864804b0"
dependencies = [ dependencies = [
"windows-result", "windows-result 0.2.0",
"windows-strings", "windows-strings",
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
[[package]]
name = "windows-result"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e383302e8ec8515204254685643de10811af0ed97ea37210dc26fb0032647f8"
dependencies = [
"windows-targets 0.52.6",
]
[[package]] [[package]]
name = "windows-result" name = "windows-result"
version = "0.2.0" version = "0.2.0"
@@ -5072,7 +5381,7 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
dependencies = [ dependencies = [
"windows-result", "windows-result 0.2.0",
"windows-targets 0.52.6", "windows-targets 0.52.6",
] ]
@@ -5308,6 +5617,15 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "winreg"
version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "winreg" name = "winreg"
version = "0.52.0" version = "0.52.0"
@@ -5320,14 +5638,12 @@ dependencies = [
[[package]] [[package]]
name = "wry" name = "wry"
version = "0.44.1" version = "0.46.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "440600584cfbd8b0d28eace95c1f2c253db05dae43780b79380aa1e868f04c73" checksum = "6fa1c8c760041c64ce6be99f83d6cb55fe3fcd85a1ad46d32895f6e65cee87ba"
dependencies = [ dependencies = [
"base64 0.22.1", "base64 0.22.1",
"block", "block2",
"cocoa",
"core-graphics",
"crossbeam-channel", "crossbeam-channel",
"dpi", "dpi",
"dunce", "dunce",
@@ -5340,8 +5656,11 @@ dependencies = [
"kuchikiki", "kuchikiki",
"libc", "libc",
"ndk", "ndk",
"objc", "objc2",
"objc_id", "objc2-app-kit",
"objc2-foundation",
"objc2-ui-kit",
"objc2-web-kit",
"once_cell", "once_cell",
"percent-encoding", "percent-encoding",
"raw-window-handle", "raw-window-handle",
@@ -5352,7 +5671,7 @@ dependencies = [
"webkit2gtk", "webkit2gtk",
"webkit2gtk-sys", "webkit2gtk-sys",
"webview2-com", "webview2-com",
"windows", "windows 0.58.0",
"windows-core 0.58.0", "windows-core 0.58.0",
"windows-version", "windows-version",
"x11-dl", "x11-dl",
+18 -9
View File
@@ -1,35 +1,44 @@
[package] [package]
name = "easytier-game" name = "easytier-game"
version = "1.0.3" version = "1.0.8"
homepage = "https://github.com/EasyTier/EasyTier"
repository = "https://github.com/EasyTier/EasytierGame"
description = "A simple network initiator based on Easytier" description = "A simple network initiator based on Easytier"
authors = ["you"] authors = ["leizi97"]
license = "" license = "LICENSE"
repository = ""
edition = "2021" edition = "2021"
rust-version = "1.77.2" rust-version = "1.77.2"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[lib] [lib]
name = "app_lib" name = "app_lib"
crate-type = ["staticlib", "cdylib", "rlib"] crate-type = ["staticlib", "cdylib", "rlib"]
[build-dependencies] [build-dependencies]
tauri-build = { version = "2.0.1", features = [] } tauri-build = { version = "2.0.2", features = [] }
# prost-build = "0.13.2"
[dependencies] [dependencies]
serde_json = "1.0" serde_json = "1.0"
serde = { version = "1.0", features = ["derive"] } serde = { version = "1.0", features = ["derive"] }
log = "0.4" log = "0.4"
tauri = { version = "2.0.2", features = [ tauri = { version = "2.0.6", features = [
"tray-icon", "tray-icon",
"image-png", "image-png",
"image-ico", "image-ico",
] } ] }
tauri-plugin-log = "2.0.0-rc" tauri-plugin-log = "2.0.1"
tauri-plugin-shell = "2" tauri-plugin-shell = "2.0.2"
reqwest = { version = "0.12", features = ["json"] } reqwest = { version = "0.12", features = ["json"] }
zip = "2.2.0" zip = "2.2.0"
sysinfo = '0.32.0'
planif = { git = "https://github.com/mattrobineau/planif", tag = "1.0.1" }
# prost = "0.13"
# prost-types = "0.13"
[target."cfg(not(any(target_os = \"android\", target_os = \"ios\")))".dependencies] [target."cfg(not(any(target_os = \"android\", target_os = \"ios\")))".dependencies]
tauri-plugin-single-instance = "2" tauri-plugin-autostart = "2.0.1"
tauri-plugin-single-instance = "2.0.1"
+1
View File
@@ -0,0 +1 @@
../LICENSE
+49 -13
View File
@@ -1,15 +1,51 @@
{ {
"$schema": "../gen/schemas/desktop-schema.json", "$schema": "../gen/schemas/desktop-schema.json",
"identifier": "default", "identifier": "default",
"description": "enables the default permissions", "description": "enables the default permissions",
"windows": [ "windows": ["main", "log", "member", "cidr", "advance"],
"main" "permissions": [
], "core:default",
"permissions": [ "core:window:allow-minimize",
"core:default", "core:window:allow-hide",
"core:window:allow-minimize", "core:window:allow-close",
"core:window:allow-hide", "shell:allow-open",
"core:window:allow-close", "core:window:allow-show",
"shell:allow-open" "core:window:allow-create",
] "core:window:allow-set-position",
"core:window:allow-destroy",
"core:webview:allow-create-webview-window",
"core:webview:allow-set-webview-size",
"core:webview:allow-set-webview-position",
"core:webview:allow-create-webview",
"core:webview:allow-webview-show",
"core:webview:allow-webview-hide",
"core:webview:allow-webview-close",
"autostart:default",
"autostart:allow-enable",
"autostart:allow-disable",
"autostart:allow-is-enabled",
"core:tray:allow-get-by-id",
"core:tray:allow-set-icon",
"core:tray:allow-new",
{
"identifier": "shell:allow-spawn",
"allow": [
{
"args": ["run"],
"cmd": "easytier/tool/WinIPBroadcast",
"name": "WinIPBroadcast"
}
]
},
{
"identifier": "shell:allow-execute",
"allow": [
{
"args": ["run"],
"cmd": "easytier/tool/WinIPBroadcast",
"name": "WinIPBroadcast"
}
]
}
]
} }
Binary file not shown.
+1
View File
@@ -0,0 +1 @@
这里存放每次打包需要用到的最新版本的easytier 和 相关工具
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.
Binary file not shown.
+127 -50
View File
@@ -1,5 +1,6 @@
use reqwest::{Client, Error}; use reqwest::{Client, Error};
use serde::Deserialize; use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::fs::{self, File}; use std::fs::{self, File};
use std::io::{BufRead, BufReader, Write}; use std::io::{BufRead, BufReader, Write};
use std::os::windows::process::CommandExt; use std::os::windows::process::CommandExt;
@@ -9,9 +10,11 @@ use std::sync::{
mpsc, Arc, mpsc, Arc,
}; };
use std::{path, thread}; use std::{path, thread};
use sysinfo::System;
use tauri::tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent}; use tauri::tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent};
use tauri::Emitter; use tauri::Emitter;
use tauri::{Manager, WindowEvent}; use tauri::Manager;
use tauri_plugin_autostart::MacosLauncher;
// 定义GitHub Release的结构体 // 定义GitHub Release的结构体
#[derive(Debug, Deserialize)] #[derive(Debug, Deserialize)]
@@ -47,29 +50,9 @@ pub async fn fetch_releases() -> Result<Vec<Release>, Error> {
response.json::<Vec<Release>>().await response.json::<Vec<Release>>().await
} }
static mut IS_CLOSE: bool = false;
#[tauri::command(rename_all = "snake_case")]
fn my_commit_output(commit_msg: String, window: tauri::Window) -> Result<bool, String> {
println!("{}", commit_msg);
unsafe {
IS_CLOSE = true;
}
window.close().unwrap();
return Ok(true);
}
#[tauri::command(rename_all = "snake_case")]
fn force_close(window: tauri::Window) {
unsafe {
IS_CLOSE = true;
}
window.close().unwrap();
}
#[tauri::command(rename_all = "snake_case")] #[tauri::command(rename_all = "snake_case")]
fn get_core_version() -> String { fn get_core_version() -> String {
match Command::new("easytier-core.exe") match Command::new("easytier/easytier-core.exe")
.arg("--version") .arg("--version")
.creation_flags(0x08000000) .creation_flags(0x08000000)
.output() .output()
@@ -82,13 +65,82 @@ fn get_core_version() -> String {
} }
} }
#[tauri::command(rename_all = "snake_case")]
fn get_cli_version() -> String {
match Command::new("easytier/easytier-cli.exe")
.arg("--version")
.creation_flags(0x08000000)
.output()
{
Ok(output) => {
let output_str = String::from_utf8_lossy(&output.stdout);
return output_str.trim().to_string();
}
Err(_e) => return "".to_string(),
}
}
#[derive(Serialize, Deserialize, Debug)]
struct RoutePeerInfo {
peer_id: u64,
cost: u64,
hostname: Option<String>,
udp_stun_info: String,
easytier_version: String,
network_length: u64,
}
#[derive(Serialize, Deserialize, Debug)]
struct RouteTable {
peer_infos: HashMap<u32, RoutePeerInfo>,
ipv4_peer_id_map: HashMap<String, u64>,
}
#[derive(Serialize, Deserialize, Debug)]
struct PeerRouteServiceImpl {
route_table_with_cost: RouteTable,
}
#[derive(Serialize, Deserialize, Debug)]
struct PeerRoute {
my_peer_id: u64,
service_impl: PeerRouteServiceImpl,
}
#[derive(Serialize, Deserialize, Debug)]
struct MyResponse {
response: PeerRoute,
}
#[tauri::command(rename_all = "snake_case")]
fn get_members_by_cli() -> String {
match Command::new("easytier/easytier-cli.exe")
.arg("peer")
.arg("list")
.creation_flags(0x08000000)
.output()
{
Ok(output) => {
let output_str = String::from_utf8_lossy(&output.stdout);
return output_str.trim().to_string();
}
Err(_e) => return _e.to_string(),
}
}
#[tauri::command(rename_all = "snake_case")] #[tauri::command(rename_all = "snake_case")]
async fn download_easytier_zip(download_url: String, file_name: String) { async fn download_easytier_zip(download_url: String, file_name: String) {
let target = format!("https://ghp.ci/?q={}",download_url); let target = format!("{}", download_url);
let response = reqwest::get(target) let response = reqwest::get(target)
.await .await
.expect("error to download easytier url"); .expect("error to download easytier url");
let file_path = format!("./{}", file_name); let file_path = format!("./easytier/{}", file_name);
let easytier_dir = path::Path::new("./easytier");
if !easytier_dir.exists() {
fs::create_dir_all(&easytier_dir).unwrap();
}
let path = path::Path::new(&file_path); let path = path::Path::new(&file_path);
let mut file = match File::create(&path) { let mut file = match File::create(&path) {
@@ -137,7 +189,14 @@ fn unzip(fname: &path::Path) {
// fs::create_dir_all(p).unwrap(); // fs::create_dir_all(p).unwrap();
// } // }
// } // }
let out_file_path = path::Path::new("./").join(outpath.file_name().clone().unwrap());
let easytier_dir = path::Path::new("./easytier");
// if !easytier_dir.exists() {
// fs::create_dir_all(&easytier_dir).unwrap();
// }
// let out_file_path = path::Path::new("./").join(outpath.file_name().clone().unwrap());
let out_file_path = easytier_dir.join(outpath.file_name().clone().unwrap());
println!("outFilePath: {}", out_file_path.display()); println!("outFilePath: {}", out_file_path.display());
let mut outfile = fs::File::create(&out_file_path).unwrap(); let mut outfile = fs::File::create(&out_file_path).unwrap();
std::io::copy(&mut file, &mut outfile).unwrap(); std::io::copy(&mut file, &mut outfile).unwrap();
@@ -150,18 +209,16 @@ fn run_command(
args: Vec<String>, args: Vec<String>,
stop_signal: tauri::State<Arc<AtomicBool>>, stop_signal: tauri::State<Arc<AtomicBool>>,
) { ) {
// if !path::Path::new("easytier-core.exe").exists() {
// app_handle.emit("command-output", "easytier-core.exe 不存在");
// return
// }
let (tx, rx) = mpsc::channel(); let (tx, rx) = mpsc::channel();
stop_signal.store(false, Ordering::Relaxed); stop_signal.store(false, Ordering::Relaxed);
let app_handle1 = app_handle.clone(); let app_handle1 = app_handle.clone();
let app_handle2 = app_handle.clone(); let app_handle2 = app_handle.clone();
let stop_signal = Arc::clone(&stop_signal); let stop_signal1 = Arc::clone(&stop_signal);
let stop_signal2 = Arc::clone(&stop_signal);
let args2 = args.clone(); let args2 = args.clone();
thread::spawn(move || { thread::spawn(move || {
let mut child = Command::new("easytier-core.exe") let mut child = Command::new("easytier/easytier-core.exe")
.args(args) .args(args)
.creation_flags(0x08000000) .creation_flags(0x08000000)
.stdout(Stdio::piped()) .stdout(Stdio::piped())
@@ -189,13 +246,13 @@ fn run_command(
} }
} }
} }
stop_signal1.store(true, Ordering::Relaxed);
println!("end"); println!("end");
}); });
thread::spawn(move || { thread::spawn(move || {
while let Ok(line) = rx.recv() { while let Ok(line) = rx.recv() {
if stop_signal.load(Ordering::Relaxed) { if stop_signal2.load(Ordering::Relaxed) {
break; break;
} }
app_handle2 app_handle2
@@ -206,8 +263,7 @@ fn run_command(
} }
#[tauri::command(rename_all = "snake_case")] #[tauri::command(rename_all = "snake_case")]
fn stop_command(child_id: u32, stop_signal: tauri::State<Arc<AtomicBool>>) { fn stop_command(child_id: u32) {
println!("stop command");
if child_id != 0 { if child_id != 0 {
let output = Command::new("taskkill") let output = Command::new("taskkill")
.arg("/F") .arg("/F")
@@ -223,8 +279,9 @@ fn stop_command(child_id: u32, stop_signal: tauri::State<Arc<AtomicBool>>) {
} else { } else {
eprintln!("Failed to terminate process {}.", child_id); eprintln!("Failed to terminate process {}.", child_id);
} }
} else {
println!("child id is 0");
} }
stop_signal.store(true, Ordering::Relaxed);
} }
#[tauri::command(rename_all = "snake_case")] #[tauri::command(rename_all = "snake_case")]
@@ -262,23 +319,42 @@ fn toggle_window_visibility<R: tauri::Runtime>(app: &tauri::AppHandle<R>) {
} }
} }
#[tauri::command(rename_all = "snake_case")]
fn search_pid_by_pname(target_process_name: String) -> u32 {
// 创建一个新的 System 实例
let mut system = System::new_all();
// 刷新所有进程信息
system.refresh_all();
// 遍历所有进程
for (pid, process) in system.processes() {
if process
.name()
.to_string_lossy()
.to_lowercase()
.contains(&target_process_name.to_lowercase())
{
println!("Found process '{}' with PID: {}", target_process_name, pid);
return pid.as_u32();
}
}
return 0;
}
pub const AUTOSTART_ARG: &str = "--autostart";
#[cfg_attr(mobile, tauri::mobile_entry_point)] #[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() { pub fn run() {
let stop_signal = Arc::new(AtomicBool::new(false)); // 创建一个原子布尔值,用于控制命令的停止 let stop_signal = Arc::new(AtomicBool::new(false)); // 创建一个原子布尔值,用于控制命令的停止
let stop_signal_clone = Arc::clone(&stop_signal); // 创建一个原子布尔值的克隆,用于传递给命令 let stop_signal_clone = Arc::clone(&stop_signal); // 创建一个原子布尔值的克隆,用于传递给命令
let context = tauri::generate_context!(); let context = tauri::generate_context!();
tauri::Builder::default() tauri::Builder::default()
.plugin(tauri_plugin_autostart::init(
MacosLauncher::LaunchAgent,
Some(vec![AUTOSTART_ARG]),
))
.plugin(tauri_plugin_shell::init()) .plugin(tauri_plugin_shell::init())
.on_window_event(move |window, event| {
if let WindowEvent::CloseRequested { api, .. } = event {
unsafe {
if !IS_CLOSE {
api.prevent_close();
window.emit("window-close-event", "").unwrap();
}
}
}
})
.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| { .plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
let _ = app let _ = app
.get_webview_window("main") .get_webview_window("main")
@@ -316,13 +392,14 @@ pub fn run() {
}) })
.manage(stop_signal_clone) .manage(stop_signal_clone)
.invoke_handler(tauri::generate_handler![ .invoke_handler(tauri::generate_handler![
my_commit_output,
force_close,
run_command, run_command,
stop_command, stop_command,
get_core_version, get_core_version,
fetch_easytier_list, fetch_easytier_list,
download_easytier_zip download_easytier_zip,
get_cli_version,
get_members_by_cli,
search_pid_by_pname
]) ])
.run(context) .run(context)
.expect("error while running tauri application"); .expect("error while running tauri application");
+19 -4
View File
@@ -1,7 +1,7 @@
{ {
"$schema": "../node_modules/@tauri-apps/cli/config.schema.json", "$schema": "../node_modules/@tauri-apps/cli/config.schema.json",
"productName": "easytier-game", "productName": "easytier-game",
"version": "1.0.3", "version": "1.0.8",
"identifier": "com.tauri.easytier-game", "identifier": "com.tauri.easytier-game",
"build": { "build": {
@@ -15,12 +15,12 @@
{ {
"title": "easytier-game", "title": "easytier-game",
"width": 331, "width": 331,
"height": 285, "height": 305,
"resizable": false, "resizable": false,
"fullscreen": false, "fullscreen": false,
"decorations": true, "decorations": true,
"maximizable": false,
"center": true, "center": true,
"maximizable": false,
"transparent": false "transparent": false
} }
], ],
@@ -28,10 +28,25 @@
"csp": null "csp": null
} }
}, },
"plugins": {},
"bundle": { "bundle": {
"active": false, "active": false,
"targets": "all", "targets": "all",
"resources": [
"easytier/tool/WinIPBroadcast.exe",
"easytier/icons/icon-inactive.ico",
"easytier/icons/icon.ico",
"easytier/easytier-cli.exe",
"easytier/easytier-core.exe",
"easytier/Packet.dll",
"easytier/wintun.dll"
],
"windows": {
"webviewInstallMode": {
"type": "embedBootstrapper"
}
},
"createUpdaterArtifacts": false, "createUpdaterArtifacts": false,
"icon": ["icons/32x32.png", "icons/128x128.png", "icons/128x128@2x.png", "icons/icon.icns", "icons/icon.ico"] "icon": ["icons/icon.png", "icons/icon.rgba", "icons/icon.icns", "icons/icon.ico"]
} }
} }
+23 -1
View File
@@ -9,24 +9,46 @@ export default defineStore("main", {
networkPassword: "", networkPassword: "",
hostname: "", hostname: "",
ipv4: "", ipv4: "",
proxyNetworks: "", // 子网代理
autoStart: false, // 是否自动启动
disableIpv6: false, // 是否禁用IPv6 disableIpv6: false, // 是否禁用IPv6
disbleListenner: false, // 是否禁用监听 disbleListenner: false, // 是否禁用监听
disbleP2p: true, // 是否使用P2P disableEncryption: false, // 是否禁用加密
multiThread: false, //使用多线程
enablExitNode: false, // 是否启用退出节点
noTun: false, // 是否使用TUN
latencyfirst: false, // 是否优先延迟
useSmoltcp: false, // 是否为子网代理启用smoltcp堆栈
disableUdpHolePunching: false, // 是否禁用UDP打洞
relayAllPeerrpc: false, // 是否启用所有对等RPC
disbleP2p: false, // 是否使用P2P
dhcp: true, // 是否使用DHCP dhcp: true, // 是否使用DHCP
}, },
cidrEnable: false,
basePeers: ["public.easytier.top:11010"], basePeers: ["public.easytier.top:11010"],
}; };
}, },
persist: { persist: {
paths: [ paths: [
"basePeers", "basePeers",
"cidrEnable",
"config.proxyNetworks",
"config.serverUrl", "config.serverUrl",
"config.networkName", "config.networkName",
"config.protocol", "config.protocol",
"config.networkPassword", "config.networkPassword",
"config.disbleP2p", "config.disbleP2p",
"config.autoStart",
"config.disableIpv6", "config.disableIpv6",
"config.disbleListenner", "config.disbleListenner",
"config.disableEncryption",
"config.multiThread",
"config.enablExitNode",
"config.noTun",
"config.latencyfirst",
"config.useSmoltcp",
"config.disableUdpHolePunching",
"config.relayAllPeerrpc",
"config.hostname", "config.hostname",
"config.dhcp", "config.dhcp",
], ],
+35 -4
View File
@@ -77,7 +77,38 @@ export const ATJ = (promise: Promise<any>, errorExt: string | undefined = undefi
}); });
}; };
export const openBrowser = (key: string) => { export const parsePeerInfo = (content: string) => {
// logger.info(`${import.meta.env.VITE_BROWSER_JOB_URL}${key}`) // 将表格字符串分割成行
// _launcherApi.openBrowser(`${import.meta.env.VITE_BROWSER_JOB_URL}${key}`); const lines = content.split('\n')
};
// 提取表头(keys
const headers = lines[1]
.split('│')
.slice(1, -1)
.map((h) => h.trim())
// 初始化结果数组
const result: any[] = []
// 遍历数据行
for (let i = 3; i < lines.length - 1; i += 2) {
if (lines[i].trim() === '') continue // 跳过空行
// 分割每一行的数据
const values = lines[i]
.split('│')
.slice(1, -1)
.map((v) => v.trim())
// 创建对象并添加到结果数组
const obj: any = {}
headers.forEach((header, index) => {
obj[header] = values[index] === '-' || values[index] === '' ? null : values[index]
})
// 每行数据都作为一个新对象添加到结果数组中
result.push(obj)
}
return result
}