Compare commits
41 Commits
3
.github/build-for-linux/build.sh
vendored
3
.github/build-for-linux/build.sh
vendored
@@ -1,8 +1,7 @@
|
||||
# pnpm install --resolution-only
|
||||
pnpm install
|
||||
pnpm check $INPUT_TARGET
|
||||
sed -i "s/#openssl/openssl={version=\"0.10\",features=[\"vendored\"]}/g" src-tauri/Cargo.toml
|
||||
if [ "$INPUT_TARGET" = "x86_64-unknown-linux-gnu" ] || [ "$INPUT_TARGET" = "i686-unknown-linux-gnu" ]; then
|
||||
if [ "$INPUT_TARGET" = "x86_64-unknown-linux-gnu" ]; then
|
||||
pnpm build --target $INPUT_TARGET
|
||||
else
|
||||
pnpm build --target $INPUT_TARGET -b deb
|
||||
|
||||
10
.github/build-for-linux/entrypoint.sh
vendored
10
.github/build-for-linux/entrypoint.sh
vendored
@@ -10,15 +10,7 @@ rustup target add "$INPUT_TARGET"
|
||||
if [ "$INPUT_TARGET" = "x86_64-unknown-linux-gnu" ]; then
|
||||
apt-get update
|
||||
apt-get install -y libgtk-3-dev libwebkit2gtk-4.0-dev libayatana-appindicator3-dev librsvg2-dev patchelf
|
||||
elif [ "$INPUT_TARGET" = "i686-unknown-linux-gnu" ]; then
|
||||
dpkg --add-architecture i386
|
||||
apt-get update
|
||||
apt-get install -y libstdc++6:i386 libgdk-pixbuf2.0-dev:i386 libatomic1:i386 gcc-multilib g++-multilib libwebkit2gtk-4.0-dev:i386 libssl-dev:i386 libgtk-3-dev:i386 librsvg2-dev:i386 patchelf:i386 libayatana-appindicator3-dev:i386
|
||||
export PKG_CONFIG_PATH=/usr/lib/i386-linux-gnu/pkgconfig/:$PKG_CONFIG_PATH
|
||||
export PKG_CONFIG_SYSROOT_DIR=/
|
||||
elif [ "$INPUT_TARGET" = "aarch64-unknown-linux-gnu" ]; then
|
||||
sed 's/http:\/\/\(.*\).ubuntu.com\/ubuntu\//[arch-=amd64,i386] http:\/\/ports.ubuntu.com\/ubuntu-ports\//g' /etc/apt/sources.list | tee /etc/apt/sources.list.d/ports.list
|
||||
sed -i 's/http:\/\/\(.*\).ubuntu.com\/ubuntu\//[arch=amd64,i386] http:\/\/\1.archive.ubuntu.com\/ubuntu\//g' /etc/apt/sources.list
|
||||
dpkg --add-architecture arm64
|
||||
apt-get update
|
||||
apt-get install -y libncurses6:arm64 libtinfo6:arm64 linux-libc-dev:arm64 libncursesw6:arm64 libssl3:arm64 libcups2:arm64
|
||||
@@ -29,8 +21,6 @@ elif [ "$INPUT_TARGET" = "aarch64-unknown-linux-gnu" ]; then
|
||||
export PKG_CONFIG_PATH=/usr/lib/aarch64-linux-gnu/pkgconfig
|
||||
export PKG_CONFIG_ALLOW_CROSS=1
|
||||
elif [ "$INPUT_TARGET" = "armv7-unknown-linux-gnueabihf" ]; then
|
||||
sed 's/http:\/\/\(.*\).ubuntu.com\/ubuntu\//[arch-=amd64,i386] http:\/\/ports.ubuntu.com\/ubuntu-ports\//g' /etc/apt/sources.list | tee /etc/apt/sources.list.d/ports.list
|
||||
sed -i 's/http:\/\/\(.*\).ubuntu.com\/ubuntu\//[arch=amd64,i386] http:\/\/\1.archive.ubuntu.com\/ubuntu\//g' /etc/apt/sources.list
|
||||
dpkg --add-architecture armhf
|
||||
apt-get update
|
||||
apt-get install -y libncurses6:armhf libtinfo6:armhf linux-libc-dev:armhf libncursesw6:armhf libssl3:armhf libcups2:armhf
|
||||
|
||||
169
.github/workflows/alpha.yml
vendored
Normal file
169
.github/workflows/alpha.yml
vendored
Normal file
@@ -0,0 +1,169 @@
|
||||
name: Alpha Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
branches: [main]
|
||||
tags-ignore: [updater, alpha]
|
||||
permissions: write-all
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
RUST_BACKTRACE: short
|
||||
|
||||
jobs:
|
||||
alpha:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
- os: windows-latest
|
||||
target: aarch64-pc-windows-msvc
|
||||
- os: macos-latest
|
||||
target: aarch64-apple-darwin
|
||||
- os: macos-latest
|
||||
target: x86_64-apple-darwin
|
||||
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Apply Patch
|
||||
if: matrix.target == 'aarch64-pc-windows-msvc'
|
||||
run: |
|
||||
git config --global user.email "clash-verge-rev@github.io"
|
||||
git config --global user.name "clash-verge-rev"
|
||||
git am patches/support-windows-aarch64.patch
|
||||
|
||||
- name: Init Submodule
|
||||
if: matrix.target == 'aarch64-pc-windows-msvc'
|
||||
run: git submodule update --init --recursive
|
||||
|
||||
- name: Install Rust Stable
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Add Rust Target
|
||||
run: rustup target add ${{ matrix.target }}
|
||||
|
||||
- name: Rust Cache
|
||||
uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: src-tauri
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
- uses: pnpm/action-setup@v2
|
||||
name: Install pnpm
|
||||
with:
|
||||
version: 8
|
||||
run_install: false
|
||||
|
||||
- name: Pnpm install and check
|
||||
run: |
|
||||
pnpm i
|
||||
pnpm check ${{ matrix.target }}
|
||||
|
||||
- name: Tauri build
|
||||
uses: tauri-apps/tauri-action@v0
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
with:
|
||||
tagName: alpha
|
||||
releaseName: "Clash Verge Rev Alpha"
|
||||
releaseBody: "More new features are now supported."
|
||||
releaseDraft: false
|
||||
prerelease: true
|
||||
tauriScript: pnpm
|
||||
args: --target ${{ matrix.target }}
|
||||
|
||||
- name: Portable Bundle
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: pnpm portable ${{ matrix.target }} --alpha
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
|
||||
alpha-for-linux:
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- os: ubuntu-latest
|
||||
target: aarch64-unknown-linux-gnu
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Build for Linux
|
||||
uses: ./.github/build-for-linux
|
||||
env:
|
||||
TAURI_PRIVATE_KEY: ${{ secrets.TAURI_PRIVATE_KEY }}
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
with:
|
||||
target: ${{ matrix.target }}
|
||||
- name: Get Version
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install jq
|
||||
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
|
||||
- name: Upload Release
|
||||
if: startsWith(matrix.target, 'x86_64')
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: alpha
|
||||
name: "Clash Verge Rev Alpha"
|
||||
body: "More new features are now supported."
|
||||
prerelease: true
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
files: src-tauri/target/${{ matrix.target }}/release/bundle/appimage/*.AppImage*
|
||||
- name: Upload Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: alpha
|
||||
name: "Clash Verge Rev Alpha"
|
||||
body: "More new features are now supported."
|
||||
prerelease: true
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
files: src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
|
||||
update_tag:
|
||||
name: Update tag
|
||||
runs-on: ubuntu-latest
|
||||
needs: [alpha, alpha-for-linux]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
- name: Set Env
|
||||
run: |
|
||||
echo "BUILDTIME=$(TZ=Asia/Shanghai date)" >> $GITHUB_ENV
|
||||
shell: bash
|
||||
- name: Update Tag
|
||||
uses: richardsimko/update-tag@v1
|
||||
with:
|
||||
tag_name: alpha
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
- run: |
|
||||
cat > release.txt << 'EOF'
|
||||
## Clash Verge Rev Alpha
|
||||
Created at ${{ env.BUILDTIME }}.
|
||||
EOF
|
||||
- name: Upload Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: alpha
|
||||
name: "Clash Verge Rev Alpha"
|
||||
body_path: release.txt
|
||||
prerelease: true
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
generate_release_notes: true
|
||||
24
.github/workflows/release.yml
vendored
24
.github/workflows/release.yml
vendored
@@ -2,9 +2,6 @@ name: Release Build
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
push:
|
||||
tags:
|
||||
- v**
|
||||
permissions: write-all
|
||||
env:
|
||||
CARGO_INCREMENTAL: 0
|
||||
@@ -18,8 +15,6 @@ jobs:
|
||||
include:
|
||||
- os: windows-latest
|
||||
target: x86_64-pc-windows-msvc
|
||||
- os: windows-latest
|
||||
target: i686-pc-windows-msvc
|
||||
- os: windows-latest
|
||||
target: aarch64-pc-windows-msvc
|
||||
- os: macos-latest
|
||||
@@ -78,7 +73,7 @@ jobs:
|
||||
TAURI_KEY_PASSWORD: ${{ secrets.TAURI_KEY_PASSWORD }}
|
||||
with:
|
||||
tagName: v__VERSION__
|
||||
releaseName: "Clash Verge v__VERSION__"
|
||||
releaseName: "Clash Verge Rev v__VERSION__"
|
||||
releaseBody: "More new features are now supported."
|
||||
releaseDraft: false
|
||||
prerelease: false
|
||||
@@ -100,12 +95,8 @@ jobs:
|
||||
include:
|
||||
- os: ubuntu-latest
|
||||
target: x86_64-unknown-linux-gnu
|
||||
- os: ubuntu-latest
|
||||
target: i686-unknown-linux-gnu
|
||||
- os: ubuntu-latest
|
||||
target: aarch64-unknown-linux-gnu
|
||||
# - os: ubuntu-latest
|
||||
# target: armv7-unknown-linux-gnueabihf
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- name: Checkout Repository
|
||||
@@ -124,11 +115,11 @@ jobs:
|
||||
sudo apt-get install jq
|
||||
echo "VERSION=$(cat package.json | jq '.version' | tr -d '"')" >> $GITHUB_ENV
|
||||
- name: Upload Release
|
||||
if: startsWith(matrix.target, 'x86_64') || startsWith(matrix.target, 'i686')
|
||||
if: startsWith(matrix.target, 'x86_64')
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: v${{env.VERSION}}
|
||||
name: "Clash Verge v${{env.VERSION}}"
|
||||
name: "Clash Verge Rev v${{env.VERSION}}"
|
||||
body: "More new features are now supported."
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
files: src-tauri/target/${{ matrix.target }}/release/bundle/appimage/*.AppImage*
|
||||
@@ -136,21 +127,20 @@ jobs:
|
||||
uses: softprops/action-gh-release@v1
|
||||
with:
|
||||
tag_name: v${{env.VERSION}}
|
||||
name: "Clash Verge v${{env.VERSION}}"
|
||||
name: "Clash Verge Rev v${{env.VERSION}}"
|
||||
body: "More new features are now supported."
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
files: src-tauri/target/${{ matrix.target }}/release/bundle/deb/*.deb
|
||||
|
||||
release-update:
|
||||
needs: [release]
|
||||
runs-on: ubuntu-latest
|
||||
if: startsWith(github.ref, 'refs/tags/v')
|
||||
needs: [release, release-for-linux]
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v3
|
||||
|
||||
- name: Install Node
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: "20"
|
||||
|
||||
|
||||
17
README.md
17
README.md
@@ -13,18 +13,15 @@ A Clash Meta GUI based on <a href="https://github.com/tauri-apps/tauri">Tauri</a
|
||||
|
||||
Click on the corresponding link below to download the installation package. Supports Windows (x64/x86), Linux (x64/arm64) and macOS 10.15+ (intel/apple).
|
||||
|
||||
[[Windows x64](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.0/Clash.Verge_1.5.0_x64-setup.exe)]
|
||||
[[Windows x86](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.0/Clash.Verge_1.5.0_x86-setup.exe)]
|
||||
[[Windows arm64](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.0/Clash.Verge_1.5.0_arm64-setup.exe)]
|
||||
[[Windows x64](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.4/Clash.Verge_1.5.4_x64-setup.exe)]
|
||||
[[Windows arm64](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.4/Clash.Verge_1.5.4_arm64-setup.exe)]
|
||||
|
||||
[[macOS intel](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.0/Clash.Verge_1.5.0_x64.dmg)]
|
||||
[[macOS apple](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.0/Clash.Verge_1.5.0_aarch64.dmg)]
|
||||
[[macOS intel](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.4/Clash.Verge_1.5.4_x64.dmg)]
|
||||
[[macOS apple](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.4/Clash.Verge_1.5.4_aarch64.dmg)]
|
||||
|
||||
[[Linux x64 AppImage](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.0/clash-verge_1.5.0_amd64.AppImage)]
|
||||
[[Linux x64 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.0/clash-verge_1.5.0_amd64.deb)]
|
||||
[[Linux x86 AppImage](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.0/clash-verge_1.5.0_i386.AppImage)]
|
||||
[[Linux x86 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.0/clash-verge_1.5.0_i386.deb)]
|
||||
[[Linux arm64 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.0/clash-verge_1.5.0_arm64.deb)]
|
||||
[[Linux x64 AppImage](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.4/clash-verge_1.5.4_amd64.AppImage)]
|
||||
[[Linux x64 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.4/clash-verge_1.5.4_amd64.deb)]
|
||||
[[Linux arm64 deb](https://github.com/clash-verge-rev/clash-verge-rev/releases/download/v1.5.4/clash-verge_1.5.4_arm64.deb)]
|
||||
|
||||
Or you can build it yourself. Supports Windows, Linux and macOS 10.15+
|
||||
|
||||
|
||||
55
UPDATELOG.md
55
UPDATELOG.md
@@ -1,3 +1,58 @@
|
||||
## v1.5.4
|
||||
|
||||
### Features
|
||||
|
||||
- 支持自定义托盘图标
|
||||
- 支持禁用代理组图标
|
||||
- 代理组显示当前代理
|
||||
- 修改 `打开面板` 快捷键为`打开/关闭面板`
|
||||
|
||||
---
|
||||
|
||||
## v1.5.3
|
||||
|
||||
### Features
|
||||
|
||||
- Tun 设置添加重置按钮
|
||||
|
||||
### Bugs Fixes
|
||||
|
||||
- Tun 设置项显示错误的问题
|
||||
- 修改一些默认值
|
||||
- 启动时不更改启动项设置
|
||||
|
||||
---
|
||||
|
||||
## v1.5.2
|
||||
|
||||
### Features
|
||||
|
||||
- 支持自定义延迟测试超时时间
|
||||
- 优化 Tun 相关设置
|
||||
|
||||
### Bugs Fixes
|
||||
|
||||
- Merge 操作出错
|
||||
- 安装后重启服务
|
||||
- 修复管理员权限启动时开机启动失效的问题
|
||||
|
||||
---
|
||||
|
||||
## v1.5.1
|
||||
|
||||
### Features
|
||||
|
||||
- 保存窗口最大化状态
|
||||
- Proxy Provider 显示数量
|
||||
- 不再提供 32 位安装包(因为 32 位经常出现各种奇怪问题,比如 tun 模式无法开启;现在系统也几乎没有 32 位了)
|
||||
|
||||
### Bugs Fixes
|
||||
|
||||
- 优化设置项名称
|
||||
- 自定义 GLOBAL 代理组时代理组显示错误的问题
|
||||
|
||||
---
|
||||
|
||||
## v1.5.0
|
||||
|
||||
### Features
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "clash-verge",
|
||||
"version": "1.5.0",
|
||||
"version": "1.5.4",
|
||||
"license": "GPL-3.0-only",
|
||||
"scripts": {
|
||||
"dev": "tauri dev",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
From 8b085aea2f11e64f433244eda092c178a2bb50bc Mon Sep 17 00:00:00 2001
|
||||
From 871c9a6d1ed014c93da2436a437df03734e9f76c Mon Sep 17 00:00:00 2001
|
||||
From: MystiPanda <mystipanda@proton.me>
|
||||
Date: Sun, 10 Dec 2023 19:47:45 +0800
|
||||
Subject: [PATCH] feat: Support windows aarch64
|
||||
@@ -22,7 +22,7 @@ index 0000000..2eda7e4
|
||||
+ path = src-tauri/quick-rs
|
||||
+ url = https://github.com/clash-verge-rev/quick-rs.git
|
||||
diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml
|
||||
index 4c6dde5..5fd9ad8 100644
|
||||
index 2f1a3be..d67f6ed 100644
|
||||
--- a/src-tauri/Cargo.toml
|
||||
+++ b/src-tauri/Cargo.toml
|
||||
@@ -25,7 +25,6 @@ log4rs = "1"
|
||||
@@ -32,8 +32,8 @@ index 4c6dde5..5fd9ad8 100644
|
||||
-rquickjs = "0.3" # 高版本不支持 Linux aarch64
|
||||
serde_json = "1.0"
|
||||
serde_yaml = "0.9"
|
||||
auto-launch = "0.5"
|
||||
@@ -34,6 +33,7 @@ port_scanner = "0.1.5"
|
||||
once_cell = "1.18"
|
||||
@@ -33,6 +32,7 @@ port_scanner = "0.1.5"
|
||||
delay_timer = "0.11.5"
|
||||
parking_lot = "0.12"
|
||||
percent-encoding = "2.3.1"
|
||||
@@ -49,7 +49,7 @@ index 0000000..78277c4
|
||||
@@ -0,0 +1 @@
|
||||
+Subproject commit 78277c4509c64f18c0fc5c9f2b84671de7c83343
|
||||
diff --git a/src-tauri/src/enhance/script.rs b/src-tauri/src/enhance/script.rs
|
||||
index 6c207d9..d47dc33 100644
|
||||
index 30a922f..d47dc33 100644
|
||||
--- a/src-tauri/src/enhance/script.rs
|
||||
+++ b/src-tauri/src/enhance/script.rs
|
||||
@@ -3,61 +3,83 @@ use anyhow::Result;
|
||||
|
||||
@@ -13,24 +13,20 @@ const FORCE = process.argv.includes("--force");
|
||||
|
||||
const PLATFORM_MAP = {
|
||||
"x86_64-pc-windows-msvc": "win32",
|
||||
"i686-pc-windows-msvc": "win32",
|
||||
"aarch64-pc-windows-msvc": "win32",
|
||||
"x86_64-apple-darwin": "darwin",
|
||||
"aarch64-apple-darwin": "darwin",
|
||||
"x86_64-unknown-linux-gnu": "linux",
|
||||
"i686-unknown-linux-gnu": "linux",
|
||||
"aarch64-unknown-linux-gnu": "linux",
|
||||
"armv7-unknown-linux-gnueabihf": "linux",
|
||||
"loongarch64-unknown-linux-gnu": "linux",
|
||||
};
|
||||
const ARCH_MAP = {
|
||||
"x86_64-pc-windows-msvc": "x64",
|
||||
"i686-pc-windows-msvc": "ia32",
|
||||
"aarch64-pc-windows-msvc": "arm64",
|
||||
"x86_64-apple-darwin": "x64",
|
||||
"aarch64-apple-darwin": "arm64",
|
||||
"x86_64-unknown-linux-gnu": "x64",
|
||||
"i686-unknown-linux-gnu": "ia32",
|
||||
"aarch64-unknown-linux-gnu": "arm64",
|
||||
"armv7-unknown-linux-gnueabihf": "arm",
|
||||
"loongarch64-unknown-linux-gnu": "loong64",
|
||||
@@ -57,12 +53,10 @@ let META_ALPHA_VERSION;
|
||||
|
||||
const META_ALPHA_MAP = {
|
||||
"win32-x64": "mihomo-windows-amd64-compatible",
|
||||
"win32-ia32": "mihomo-windows-386",
|
||||
"win32-arm64": "mihomo-windows-arm64",
|
||||
"darwin-x64": "mihomo-darwin-amd64",
|
||||
"darwin-arm64": "mihomo-darwin-arm64",
|
||||
"linux-x64": "mihomo-linux-amd64-compatible",
|
||||
"linux-ia32": "mihomo-linux-386",
|
||||
"linux-arm64": "mihomo-linux-arm64",
|
||||
"linux-arm": "mihomo-linux-armv7",
|
||||
"linux-loong64": "mihomo-linux-loong64",
|
||||
@@ -103,12 +97,10 @@ let META_VERSION;
|
||||
|
||||
const META_MAP = {
|
||||
"win32-x64": "mihomo-windows-amd64-compatible",
|
||||
"win32-ia32": "mihomo-windows-386",
|
||||
"win32-arm64": "mihomo-windows-arm64",
|
||||
"darwin-x64": "mihomo-darwin-amd64",
|
||||
"darwin-arm64": "mihomo-darwin-arm64",
|
||||
"linux-x64": "mihomo-linux-amd64-compatible",
|
||||
"linux-ia32": "mihomo-linux-386",
|
||||
"linux-arm64": "mihomo-linux-arm64",
|
||||
"linux-arm": "mihomo-linux-armv7",
|
||||
"linux-loong64": "mihomo-linux-loong64",
|
||||
@@ -317,6 +309,38 @@ async function downloadFile(url, path) {
|
||||
console.log(`[INFO]: download finished "${url}"`);
|
||||
}
|
||||
|
||||
// SimpleSC.dll
|
||||
const resolvePlugin = async () => {
|
||||
const url =
|
||||
"https://nsis.sourceforge.io/mediawiki/images/e/ef/NSIS_Simple_Service_Plugin_Unicode_1.30.zip";
|
||||
|
||||
const tempDir = path.join(TEMP_DIR, "SimpleSC");
|
||||
const tempZip = path.join(
|
||||
tempDir,
|
||||
"NSIS_Simple_Service_Plugin_Unicode_1.30.zip"
|
||||
);
|
||||
const tempDll = path.join(tempDir, "SimpleSC.dll");
|
||||
const pluginDir = path.join(process.env.APPDATA, "Local/NSIS");
|
||||
const pluginPath = path.join(pluginDir, "SimpleSC.dll");
|
||||
await fs.mkdirp(pluginDir);
|
||||
await fs.mkdirp(tempDir);
|
||||
if (!FORCE && (await fs.pathExists(pluginPath))) return;
|
||||
try {
|
||||
if (!(await fs.pathExists(tempZip))) {
|
||||
await downloadFile(url, tempZip);
|
||||
}
|
||||
const zip = new AdmZip(tempZip);
|
||||
zip.getEntries().forEach((entry) => {
|
||||
console.log(`[DEBUG]: "SimpleSC" entry name`, entry.entryName);
|
||||
});
|
||||
zip.extractAllTo(tempDir, true);
|
||||
await fs.copyFile(tempDll, pluginPath);
|
||||
console.log(`[INFO]: "SimpleSC" unzip finished`);
|
||||
} finally {
|
||||
await fs.remove(tempDir);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* main
|
||||
*/
|
||||
@@ -373,6 +397,7 @@ const tasks = [
|
||||
getLatestReleaseVersion().then(() => resolveSidecar(clashMeta())),
|
||||
retry: 5,
|
||||
},
|
||||
{ name: "plugin", func: resolvePlugin, retry: 5, winOnly: true },
|
||||
{ name: "service", func: resolveService, retry: 5, winOnly: true },
|
||||
{ name: "install", func: resolveInstall, retry: 5, winOnly: true },
|
||||
{ name: "uninstall", func: resolveUninstall, retry: 5, winOnly: true },
|
||||
|
||||
@@ -5,9 +5,9 @@ import { createRequire } from "module";
|
||||
import { getOctokit, context } from "@actions/github";
|
||||
|
||||
const target = process.argv.slice(2)[0];
|
||||
const alpha = process.argv.slice(2)[1];
|
||||
|
||||
const ARCH_MAP = {
|
||||
"i686-pc-windows-msvc": "x86",
|
||||
"x86_64-pc-windows-msvc": "x64",
|
||||
"aarch64-pc-windows-msvc": "arm64",
|
||||
};
|
||||
@@ -53,14 +53,25 @@ async function resolvePortable() {
|
||||
|
||||
const options = { owner: context.repo.owner, repo: context.repo.repo };
|
||||
const github = getOctokit(process.env.GITHUB_TOKEN);
|
||||
|
||||
console.log("[INFO]: upload to ", process.env.TAG_NAME || `v${version}`);
|
||||
const tag = alpha ? "alpha" : process.env.TAG_NAME || `v${version}`;
|
||||
console.log("[INFO]: upload to ", tag);
|
||||
|
||||
const { data: release } = await github.rest.repos.getReleaseByTag({
|
||||
...options,
|
||||
tag: process.env.TAG_NAME || `v${version}`,
|
||||
tag,
|
||||
});
|
||||
|
||||
let assets = release.assets.filter((x) => {
|
||||
return x.name === zipFile;
|
||||
});
|
||||
if (assets.length > 0) {
|
||||
let id = assets[0].id;
|
||||
await github.rest.repos.deleteReleaseAsset({
|
||||
...options,
|
||||
asset_id: id,
|
||||
});
|
||||
}
|
||||
|
||||
console.log(release.name);
|
||||
|
||||
await github.rest.repos.uploadReleaseAsset({
|
||||
|
||||
@@ -45,11 +45,9 @@ async function resolveUpdater() {
|
||||
"darwin-intel": { signature: "", url: "" },
|
||||
"darwin-x86_64": { signature: "", url: "" },
|
||||
"linux-x86_64": { signature: "", url: "" },
|
||||
"linux-i686": { signature: "", url: "" },
|
||||
"linux-aarch64": { signature: "", url: "" },
|
||||
"linux-armv7": { signature: "", url: "" },
|
||||
"windows-x86_64": { signature: "", url: "" },
|
||||
"windows-i686": { signature: "", url: "" },
|
||||
"windows-aarch64": { signature: "", url: "" },
|
||||
},
|
||||
};
|
||||
@@ -69,16 +67,6 @@ async function resolveUpdater() {
|
||||
updateData.platforms["windows-x86_64"].signature = sig;
|
||||
}
|
||||
|
||||
// win32 url
|
||||
if (name.endsWith("x86-setup.nsis.zip")) {
|
||||
updateData.platforms["windows-i686"].url = browser_download_url;
|
||||
}
|
||||
// win32 signature
|
||||
if (name.endsWith("x86-setup.nsis.zip.sig")) {
|
||||
const sig = await getSignature(browser_download_url);
|
||||
updateData.platforms["windows-i686"].signature = sig;
|
||||
}
|
||||
|
||||
// win arm url
|
||||
if (name.endsWith("arm64-setup.nsis.zip")) {
|
||||
updateData.platforms["windows-aarch64"].url = browser_download_url;
|
||||
@@ -130,16 +118,6 @@ async function resolveUpdater() {
|
||||
updateData.platforms["linux-aarch64"].signature = sig;
|
||||
updateData.platforms["linux-armv7"].signature = sig;
|
||||
}
|
||||
|
||||
// linux x86 url
|
||||
if (name.endsWith("i386.AppImage.tar.gz")) {
|
||||
updateData.platforms["linux-i686"].url = browser_download_url;
|
||||
}
|
||||
// linux x86 signature
|
||||
if (name.endsWith("i386.AppImage.tar.gz.sig")) {
|
||||
const sig = await getSignature(browser_download_url);
|
||||
updateData.platforms["linux-i686"].signature = sig;
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.allSettled(promises);
|
||||
|
||||
215
src-tauri/Cargo.lock
generated
215
src-tauri/Cargo.lock
generated
@@ -143,13 +143,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "async-channel"
|
||||
version = "2.1.1"
|
||||
version = "2.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1ca33f4bc4ed1babef42cad36cc1f51fa88be00420404e5b1e80ab1b18f7678c"
|
||||
checksum = "f28243a43d821d11341ab73c80bed182dc015c514b951616cf79bd4af39af0c3"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"event-listener 4.0.3",
|
||||
"event-listener-strategy",
|
||||
"event-listener 5.0.0",
|
||||
"event-listener-strategy 0.5.0",
|
||||
"futures-core",
|
||||
"pin-project-lite",
|
||||
]
|
||||
@@ -212,7 +212,7 @@ dependencies = [
|
||||
"futures-io",
|
||||
"futures-lite 2.2.0",
|
||||
"parking",
|
||||
"polling 3.3.2",
|
||||
"polling 3.4.0",
|
||||
"rustix 0.38.31",
|
||||
"slab",
|
||||
"tracing",
|
||||
@@ -235,7 +235,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d034b430882f8381900d3fe6f0aaa3ad94f2cb4ac519b429692a1bc2dda4ae7b"
|
||||
dependencies = [
|
||||
"event-listener 4.0.3",
|
||||
"event-listener-strategy",
|
||||
"event-listener-strategy 0.4.0",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
@@ -346,8 +346,7 @@ checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0"
|
||||
[[package]]
|
||||
name = "auto-launch"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f012b8cc0c850f34117ec8252a44418f2e34a2cf501de89e29b241ae5f79471"
|
||||
source = "git+https://github.com/zzzgydi/auto-launch?branch=main#2d94a103ca20652a3baf581ca2c296791c35c09b"
|
||||
dependencies = [
|
||||
"dirs 4.0.0",
|
||||
"thiserror",
|
||||
@@ -429,7 +428,7 @@ version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a37913e8dc4ddcc604f0c6d3bf2887c995153af3611de9e23c352b44c1b9118"
|
||||
dependencies = [
|
||||
"async-channel 2.1.1",
|
||||
"async-channel 2.2.0",
|
||||
"async-lock 3.3.0",
|
||||
"async-task",
|
||||
"fastrand 2.0.1",
|
||||
@@ -478,9 +477,9 @@ checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec"
|
||||
|
||||
[[package]]
|
||||
name = "bytemuck"
|
||||
version = "1.14.1"
|
||||
version = "1.14.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed2490600f404f2b94c167e31d3ed1d5f3c225a0f3b80230053b3e0b7b962bd9"
|
||||
checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
@@ -568,9 +567,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "cfg-expr"
|
||||
version = "0.15.6"
|
||||
version = "0.15.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6100bc57b6209840798d95cb2775684849d332f7bd788db2a8c8caf7ef82a41a"
|
||||
checksum = "fa50868b64a9a6fda9d593ce778849ea8715cd2a3d2cc17ffdb4a2f2f2f1961d"
|
||||
dependencies = [
|
||||
"smallvec",
|
||||
"target-lexicon",
|
||||
@@ -599,7 +598,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "clash-verge"
|
||||
version = "1.5.0"
|
||||
version = "1.5.4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"auto-launch",
|
||||
@@ -622,7 +621,7 @@ dependencies = [
|
||||
"runas",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"serde_yaml 0.9.31",
|
||||
"serde_yaml",
|
||||
"sysinfo",
|
||||
"sysproxy",
|
||||
"tauri",
|
||||
@@ -1145,9 +1144,9 @@ checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b"
|
||||
|
||||
[[package]]
|
||||
name = "either"
|
||||
version = "1.9.0"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07"
|
||||
checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a"
|
||||
|
||||
[[package]]
|
||||
name = "embed-resource"
|
||||
@@ -1158,7 +1157,7 @@ dependencies = [
|
||||
"cc",
|
||||
"memchr",
|
||||
"rustc_version 0.4.0",
|
||||
"toml 0.8.9",
|
||||
"toml 0.8.10",
|
||||
"vswhom",
|
||||
"winreg 0.51.0",
|
||||
]
|
||||
@@ -1253,6 +1252,17 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener"
|
||||
version = "5.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b72557800024fabbaa2449dd4bf24e37b93702d457a4d4f2b0dd1f0f039f20c1"
|
||||
dependencies = [
|
||||
"concurrent-queue",
|
||||
"parking",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener-strategy"
|
||||
version = "0.4.0"
|
||||
@@ -1263,6 +1273,16 @@ dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "event-listener-strategy"
|
||||
version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "feedafcaa9b749175d5ac357452a9d41ea2911da598fde46ce1fe02c37751291"
|
||||
dependencies = [
|
||||
"event-listener 5.0.0",
|
||||
"pin-project-lite",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "1.9.0"
|
||||
@@ -1920,9 +1940,9 @@ checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
|
||||
|
||||
[[package]]
|
||||
name = "hermit-abi"
|
||||
version = "0.3.4"
|
||||
version = "0.3.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f"
|
||||
checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3"
|
||||
|
||||
[[package]]
|
||||
name = "hex"
|
||||
@@ -2052,9 +2072,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.59"
|
||||
version = "0.1.60"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539"
|
||||
checksum = "e7ffbb5a1b541ea2561f8c41c087286cc091e21e556a4f09a8f6cbf17b69b141"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
@@ -2304,9 +2324,9 @@ checksum = "f5d4a7da358eff58addd2877a45865158f0d78c911d43a5784ceb7bbf52833b0"
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.67"
|
||||
version = "0.3.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1"
|
||||
checksum = "406cda4b368d531c842222cf9d2600a9a4acce8d29423695379c6868a143a9ee"
|
||||
dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
@@ -2408,12 +2428,6 @@ dependencies = [
|
||||
"safemem",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "linked-hash-map"
|
||||
version = "0.5.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f"
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.3.8"
|
||||
@@ -2462,9 +2476,9 @@ checksum = "a94d21414c1f4a51209ad204c1776a3d0765002c76c6abcb602a6f09f1e881c7"
|
||||
|
||||
[[package]]
|
||||
name = "log4rs"
|
||||
version = "1.2.0"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d36ca1786d9e79b8193a68d480a0907b612f109537115c6ff655a3a1967533fd"
|
||||
checksum = "0816135ae15bd0391cf284eab37e6e3ee0a6ee63d2ceeb659862bd8d0a984ca6"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"arc-swap",
|
||||
@@ -2475,11 +2489,13 @@ dependencies = [
|
||||
"libc",
|
||||
"log 0.4.20",
|
||||
"log-mdc",
|
||||
"once_cell",
|
||||
"parking_lot",
|
||||
"rand 0.8.5",
|
||||
"serde",
|
||||
"serde-value",
|
||||
"serde_json",
|
||||
"serde_yaml 0.8.26",
|
||||
"serde_yaml",
|
||||
"thiserror",
|
||||
"thread-id",
|
||||
"typemap-ors",
|
||||
@@ -2636,9 +2652,9 @@ checksum = "933dca44d65cdd53b355d0b73d380a2ff5da71f87f036053188bf1eab6a19881"
|
||||
|
||||
[[package]]
|
||||
name = "miniz_oxide"
|
||||
version = "0.7.1"
|
||||
version = "0.7.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7"
|
||||
checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7"
|
||||
dependencies = [
|
||||
"adler",
|
||||
"simd-adler32",
|
||||
@@ -2847,9 +2863,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.17"
|
||||
version = "0.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
|
||||
checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
@@ -3135,9 +3151,9 @@ checksum = "0a6dda33d67c26f0aac90d324ab2eb7239c819fc7b2552fe9faa4fe88441edc8"
|
||||
|
||||
[[package]]
|
||||
name = "pest"
|
||||
version = "2.7.6"
|
||||
version = "2.7.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1f200d8d83c44a45b21764d1916299752ca035d15ecd46faca3e9a2a2bf6ad06"
|
||||
checksum = "219c0dcc30b6a27553f9cc242972b67f75b60eb0db71f0b5462f38b058c41546"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"thiserror",
|
||||
@@ -3382,9 +3398,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "polling"
|
||||
version = "3.3.2"
|
||||
version = "3.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "545c980a3880efd47b2e262f6a4bb6daad6555cf3367aa9c4e52895f69537a41"
|
||||
checksum = "30054e72317ab98eddd8561db0f6524df3367636884b7b21b703e4b280a84a14"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"concurrent-queue",
|
||||
@@ -4042,7 +4058,7 @@ version = "0.10.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
|
||||
dependencies = [
|
||||
"pest 2.7.6",
|
||||
"pest 2.7.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -4120,9 +4136,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with"
|
||||
version = "3.6.0"
|
||||
version = "3.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b0ed1662c5a68664f45b76d18deb0e234aff37207086803165c961eb695e981"
|
||||
checksum = "15d167997bd841ec232f5b2b8e0e26606df2e7caa4c31b95ea9ca52b200bd270"
|
||||
dependencies = [
|
||||
"base64 0.21.7",
|
||||
"chrono",
|
||||
@@ -4130,6 +4146,7 @@ dependencies = [
|
||||
"indexmap 1.9.3",
|
||||
"indexmap 2.2.2",
|
||||
"serde",
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"serde_with_macros",
|
||||
"time",
|
||||
@@ -4137,9 +4154,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_with_macros"
|
||||
version = "3.6.0"
|
||||
version = "3.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "568577ff0ef47b879f736cd66740e022f3672788cdf002a05a4e609ea5a6fb15"
|
||||
checksum = "865f9743393e638991566a8b7a479043c2c8da94a33e0a31f18214c9cae0a64d"
|
||||
dependencies = [
|
||||
"darling",
|
||||
"proc-macro2",
|
||||
@@ -4147,18 +4164,6 @@ dependencies = [
|
||||
"syn 2.0.48",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.8.26"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b"
|
||||
dependencies = [
|
||||
"indexmap 1.9.3",
|
||||
"ryu",
|
||||
"serde",
|
||||
"yaml-rust",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_yaml"
|
||||
version = "0.9.31"
|
||||
@@ -4540,10 +4545,10 @@ version = "6.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a2d580ff6a20c55dfb86be5f9c238f67835d0e81cbdea8bf5680e0897320331"
|
||||
dependencies = [
|
||||
"cfg-expr 0.15.6",
|
||||
"cfg-expr 0.15.7",
|
||||
"heck 0.4.1",
|
||||
"pkg-config",
|
||||
"toml 0.8.9",
|
||||
"toml 0.8.10",
|
||||
"version-compare 0.1.1",
|
||||
]
|
||||
|
||||
@@ -4836,13 +4841,12 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.9.0"
|
||||
version = "3.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa"
|
||||
checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"fastrand 2.0.1",
|
||||
"redox_syscall",
|
||||
"rustix 0.38.31",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
@@ -4980,9 +4984,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.3.32"
|
||||
version = "0.3.34"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fe80ced77cbfb4cb91a94bf72b378b4b6791a0d9b7f09d0be747d1bdff4e68bd"
|
||||
checksum = "c8248b6521bb14bc45b4067159b9b6ad792e2d6d754d6c41fb50e29fefe38749"
|
||||
dependencies = [
|
||||
"deranged",
|
||||
"itoa 1.0.10",
|
||||
@@ -5026,9 +5030,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.35.1"
|
||||
version = "1.36.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104"
|
||||
checksum = "61285f6515fa018fb2d1e46eb21223fff441ee8db5d0f1435e8ab4f5cdb80931"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"bytes",
|
||||
@@ -5134,14 +5138,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml"
|
||||
version = "0.8.9"
|
||||
version = "0.8.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c6a4b9e8023eb94392d3dca65d717c53abc5dad49c07cb65bb8fcd87115fa325"
|
||||
checksum = "9a9aad4a3066010876e8dcf5a8a06e70a558751117a145c6ce2b82c2e2054290"
|
||||
dependencies = [
|
||||
"serde",
|
||||
"serde_spanned",
|
||||
"toml_datetime",
|
||||
"toml_edit 0.21.1",
|
||||
"toml_edit 0.22.4",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -5168,9 +5172,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "toml_edit"
|
||||
version = "0.21.1"
|
||||
version = "0.22.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
|
||||
checksum = "0c9ffdf896f8daaabf9b66ba8e77ea1ed5ed0f72821b398aba62352e95062951"
|
||||
dependencies = [
|
||||
"indexmap 2.2.2",
|
||||
"serde",
|
||||
@@ -5249,9 +5253,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "treediff"
|
||||
version = "4.0.2"
|
||||
version = "4.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "52984d277bdf2a751072b5df30ec0377febdb02f7696d64c2d7d54630bac4303"
|
||||
checksum = "4d127780145176e2b5d16611cc25a900150e86e9fd79d3bde6ff3a37359c9cb5"
|
||||
dependencies = [
|
||||
"serde_json",
|
||||
]
|
||||
@@ -5351,9 +5355,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "unicode-segmentation"
|
||||
version = "1.10.1"
|
||||
version = "1.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
|
||||
checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
|
||||
|
||||
[[package]]
|
||||
name = "unsafe-any-ors"
|
||||
@@ -5544,9 +5548,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.90"
|
||||
version = "0.2.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406"
|
||||
checksum = "c1e124130aee3fb58c5bdd6b639a0509486b0338acaaae0c84a5124b0f588b7f"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"wasm-bindgen-macro",
|
||||
@@ -5554,9 +5558,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.90"
|
||||
version = "0.2.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd"
|
||||
checksum = "c9e7e1900c352b609c8488ad12639a311045f40a35491fb69ba8c12f758af70b"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log 0.4.20",
|
||||
@@ -5569,9 +5573,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-futures"
|
||||
version = "0.4.40"
|
||||
version = "0.4.41"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461"
|
||||
checksum = "877b9c3f61ceea0e56331985743b13f3d25c406a7098d45180fb5f09bc19ed97"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"js-sys",
|
||||
@@ -5581,9 +5585,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.90"
|
||||
version = "0.2.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999"
|
||||
checksum = "b30af9e2d358182b5c7449424f017eba305ed32a7010509ede96cdc4696c46ed"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
@@ -5591,9 +5595,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.90"
|
||||
version = "0.2.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7"
|
||||
checksum = "642f325be6301eb8107a83d12a8ac6c1e1c54345a7ef1a9261962dfefda09e66"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -5604,9 +5608,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.90"
|
||||
version = "0.2.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b"
|
||||
checksum = "4f186bd2dcf04330886ce82d6f33dd75a7bfcf69ecf5763b89fcde53b6ac9838"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-streams"
|
||||
@@ -5623,9 +5627,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "web-sys"
|
||||
version = "0.3.67"
|
||||
version = "0.3.68"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed"
|
||||
checksum = "96565907687f7aceb35bc5fc03770a8a0471d82e479f25832f54a0e3f4b28446"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
@@ -5680,9 +5684,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "webpki-roots"
|
||||
version = "0.25.3"
|
||||
version = "0.25.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10"
|
||||
checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1"
|
||||
|
||||
[[package]]
|
||||
name = "webview2-com"
|
||||
@@ -6171,9 +6175,9 @@ checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04"
|
||||
|
||||
[[package]]
|
||||
name = "winnow"
|
||||
version = "0.5.36"
|
||||
version = "0.5.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "818ce546a11a9986bc24f93d0cdf38a8a1a400f1473ea8c82e59f6e0ffab9249"
|
||||
checksum = "5389a154b01683d28c77f8f68f49dea75f0a4da32557a58f68ee51ebba472d29"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
@@ -6311,28 +6315,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "xdg-home"
|
||||
version = "1.0.0"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2769203cd13a0c6015d515be729c526d041e9cf2c0cc478d57faee85f40c6dcd"
|
||||
checksum = "21e5a325c3cb8398ad6cf859c1135b25dd29e186679cf2da7581d9679f63b38e"
|
||||
dependencies = [
|
||||
"nix 0.26.4",
|
||||
"libc",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yaml-rust"
|
||||
version = "0.4.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85"
|
||||
dependencies = [
|
||||
"linked-hash-map",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zbus"
|
||||
version = "3.14.1"
|
||||
version = "3.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "31de390a2d872e4cd04edd71b425e29853f786dc99317ed72d73d6fcf5ebb948"
|
||||
checksum = "c45d06ae3b0f9ba1fb2671268b975557d8f5a84bb5ec6e43964f87e763d8bca8"
|
||||
dependencies = [
|
||||
"async-broadcast",
|
||||
"async-executor",
|
||||
@@ -6371,9 +6366,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zbus_macros"
|
||||
version = "3.14.1"
|
||||
version = "3.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d1794a946878c0e807f55a397187c11fc7a038ba5d868e7db4f3bd7760bc9d"
|
||||
checksum = "b4a1ba45ed0ad344b85a2bb5a1fe9830aed23d67812ea39a586e7d0136439c7d"
|
||||
dependencies = [
|
||||
"proc-macro-crate",
|
||||
"proc-macro2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "clash-verge"
|
||||
version = "1.5.0"
|
||||
version = "1.5.4"
|
||||
description = "clash verge"
|
||||
authors = ["zzzgydi", "wonfen", "MystiPanda"]
|
||||
license = "GPL-3.0-only"
|
||||
@@ -28,7 +28,6 @@ sysinfo = "0.30"
|
||||
rquickjs = "0.3" # 高版本不支持 Linux aarch64
|
||||
serde_json = "1.0"
|
||||
serde_yaml = "0.9"
|
||||
auto-launch = "0.5"
|
||||
once_cell = "1.18"
|
||||
port_scanner = "0.1.5"
|
||||
delay_timer = "0.11.5"
|
||||
@@ -39,7 +38,8 @@ tokio = { version = "1", features = ["full"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
reqwest = { version = "0.11", features = ["json", "rustls-tls"] }
|
||||
sysproxy = { git="https://github.com/zzzgydi/sysproxy-rs", branch = "main" }
|
||||
tauri = { version = "1.5", features = [ "dialog-open", "notification-all", "icon-png", "clipboard-all", "global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all"] }
|
||||
auto-launch = { git="https://github.com/zzzgydi/auto-launch", branch = "main" }
|
||||
tauri = { version = "1.5", features = [ "path-all", "protocol-asset", "dialog-open", "notification-all", "icon-png", "clipboard-all", "global-shortcut-all", "process-all", "shell-all", "system-tray", "updater", "window-all"] }
|
||||
|
||||
[target.'cfg(windows)'.dependencies]
|
||||
runas = "=1.0.0" # 高版本会返回错误 Status
|
||||
|
||||
@@ -249,8 +249,9 @@ pub mod uwp {
|
||||
pub async fn clash_api_get_proxy_delay(
|
||||
name: String,
|
||||
url: Option<String>,
|
||||
timeout: i32,
|
||||
) -> CmdResult<clash_api::DelayRes> {
|
||||
match clash_api::get_proxy_delay(name, url).await {
|
||||
match clash_api::get_proxy_delay(name, url, timeout).await {
|
||||
Ok(res) => Ok(res),
|
||||
Err(err) => Err(err.to_string()),
|
||||
}
|
||||
@@ -266,6 +267,33 @@ pub async fn test_delay(url: String) -> CmdResult<u32> {
|
||||
Ok(feat::test_delay(url).await.unwrap_or(10000u32))
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn get_app_dir() -> CmdResult<String> {
|
||||
let app_home_dir = wrap_err!(dirs::app_home_dir())?
|
||||
.to_string_lossy()
|
||||
.to_string();
|
||||
Ok(app_home_dir)
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn copy_icon_file(path: String, name: String) -> CmdResult<String> {
|
||||
let file_path = std::path::Path::new(&path);
|
||||
let icon_dir = wrap_err!(dirs::app_home_dir())?.join("icons");
|
||||
if !icon_dir.exists() {
|
||||
let _ = std::fs::create_dir_all(&icon_dir);
|
||||
}
|
||||
let dest_path = icon_dir.join(name);
|
||||
|
||||
if file_path.exists() {
|
||||
match std::fs::copy(file_path, &dest_path) {
|
||||
Ok(_) => Ok(dest_path.to_string_lossy().to_string()),
|
||||
Err(err) => Err(err.to_string()),
|
||||
}
|
||||
} else {
|
||||
return Err("file not found".to_string());
|
||||
}
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn exit_app(app_handle: tauri::AppHandle) {
|
||||
let _ = resolve::save_window_size_position(&app_handle, true);
|
||||
|
||||
@@ -12,17 +12,33 @@ pub struct IClashTemp(pub Mapping);
|
||||
|
||||
impl IClashTemp {
|
||||
pub fn new() -> Self {
|
||||
let template = Self::template();
|
||||
match dirs::clash_path().and_then(|path| help::read_merge_mapping(&path)) {
|
||||
Ok(map) => Self(Self::guard(map)),
|
||||
Ok(mut map) => {
|
||||
template.0.keys().for_each(|key| {
|
||||
if !map.contains_key(key) {
|
||||
map.insert(key.clone(), template.0.get(key).unwrap().clone());
|
||||
}
|
||||
});
|
||||
Self(Self::guard(map))
|
||||
}
|
||||
Err(err) => {
|
||||
log::error!(target: "app", "{err}");
|
||||
Self::template()
|
||||
template
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn template() -> Self {
|
||||
let mut map = Mapping::new();
|
||||
let mut tun = Mapping::new();
|
||||
tun.insert("stack".into(), "gvisor".into());
|
||||
tun.insert("device".into(), "Meta".into());
|
||||
tun.insert("auto-route".into(), true.into());
|
||||
tun.insert("strict-route".into(), false.into());
|
||||
tun.insert("auto-detect-interface".into(), true.into());
|
||||
tun.insert("dns-hijack".into(), vec!["any:53"].into());
|
||||
tun.insert("mtu".into(), 9000.into());
|
||||
|
||||
map.insert("mixed-port".into(), 7897.into());
|
||||
map.insert("socks-port".into(), 7898.into());
|
||||
@@ -32,6 +48,7 @@ impl IClashTemp {
|
||||
map.insert("mode".into(), "rule".into());
|
||||
map.insert("external-controller".into(), "127.0.0.1:9097".into());
|
||||
map.insert("secret".into(), "".into());
|
||||
map.insert("tun".into(), tun.into());
|
||||
|
||||
Self(map)
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::enhance::field::use_keys;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_yaml::Mapping;
|
||||
use serde_yaml::{Mapping, Value};
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Default, Debug, Clone, Deserialize, Serialize)]
|
||||
pub struct IRuntime {
|
||||
pub config: Option<Mapping>,
|
||||
@@ -16,7 +16,7 @@ impl IRuntime {
|
||||
Self::default()
|
||||
}
|
||||
|
||||
// 这里只更改 allow-lan | ipv6 | log-level
|
||||
// 这里只更改 allow-lan | ipv6 | log-level | tun
|
||||
pub fn patch_config(&mut self, patch: Mapping) {
|
||||
if let Some(config) = self.config.as_mut() {
|
||||
["allow-lan", "ipv6", "log-level"]
|
||||
@@ -26,6 +26,20 @@ impl IRuntime {
|
||||
config.insert(key.into(), value.clone());
|
||||
}
|
||||
});
|
||||
let tun = config.get("tun");
|
||||
let mut tun = tun.map_or(Mapping::new(), |val| {
|
||||
val.as_mapping().cloned().unwrap_or(Mapping::new())
|
||||
});
|
||||
let patch_tun = patch.get("tun");
|
||||
let patch_tun = patch_tun.map_or(Mapping::new(), |val| {
|
||||
val.as_mapping().cloned().unwrap_or(Mapping::new())
|
||||
});
|
||||
use_keys(&patch_tun).into_iter().for_each(|key| {
|
||||
if let Some(value) = patch_tun.get(&key).to_owned() {
|
||||
tun.insert(key.into(), value.clone());
|
||||
}
|
||||
});
|
||||
config.insert("tun".into(), Value::from(tun));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,6 +36,18 @@ pub struct IVerge {
|
||||
/// show memory info (only for Clash Meta)
|
||||
pub enable_memory_usage: Option<bool>,
|
||||
|
||||
/// enable group icon
|
||||
pub enable_group_icon: Option<bool>,
|
||||
|
||||
/// common tray icon
|
||||
pub common_tray_icon: Option<bool>,
|
||||
|
||||
/// sysproxy tray icon
|
||||
pub sysproxy_tray_icon: Option<bool>,
|
||||
|
||||
/// tun tray icon
|
||||
pub tun_tray_icon: Option<bool>,
|
||||
|
||||
/// clash tun mode
|
||||
pub enable_tun_mode: Option<bool>,
|
||||
|
||||
@@ -81,6 +93,9 @@ pub struct IVerge {
|
||||
/// 默认的延迟测试连接
|
||||
pub default_latency_test: Option<String>,
|
||||
|
||||
/// 默认的延迟测试超时时间
|
||||
pub default_latency_timeout: Option<i32>,
|
||||
|
||||
/// 是否使用内部的脚本支持,默认为真
|
||||
pub enable_builtin_enhanced: Option<bool>,
|
||||
|
||||
@@ -98,6 +113,10 @@ pub struct IVerge {
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub window_size_position: Option<Vec<f64>>,
|
||||
|
||||
/// window size and position
|
||||
#[serde(skip_serializing_if = "Option::is_none")]
|
||||
pub window_is_maximized: Option<bool>,
|
||||
|
||||
/// 是否启用随机端口
|
||||
pub enable_random_port: Option<bool>,
|
||||
|
||||
@@ -156,6 +175,10 @@ impl IVerge {
|
||||
start_page: Some("/".into()),
|
||||
traffic_graph: Some(true),
|
||||
enable_memory_usage: Some(true),
|
||||
enable_group_icon: Some(true),
|
||||
common_tray_icon: Some(false),
|
||||
sysproxy_tray_icon: Some(false),
|
||||
tun_tray_icon: Some(false),
|
||||
enable_auto_launch: Some(false),
|
||||
enable_silent_start: Some(false),
|
||||
enable_system_proxy: Some(false),
|
||||
@@ -197,6 +220,10 @@ impl IVerge {
|
||||
patch!(startup_script);
|
||||
patch!(traffic_graph);
|
||||
patch!(enable_memory_usage);
|
||||
patch!(enable_group_icon);
|
||||
patch!(common_tray_icon);
|
||||
patch!(sysproxy_tray_icon);
|
||||
patch!(tun_tray_icon);
|
||||
|
||||
patch!(enable_tun_mode);
|
||||
patch!(enable_service_mode);
|
||||
@@ -218,11 +245,13 @@ impl IVerge {
|
||||
|
||||
patch!(auto_close_connection);
|
||||
patch!(default_latency_test);
|
||||
patch!(default_latency_timeout);
|
||||
patch!(enable_builtin_enhanced);
|
||||
patch!(proxy_layout_column);
|
||||
patch!(test_list);
|
||||
patch!(auto_log_clean);
|
||||
patch!(window_size_position);
|
||||
patch!(window_is_maximized);
|
||||
}
|
||||
|
||||
/// 在初始化前尝试拿到单例端口的值
|
||||
|
||||
@@ -44,7 +44,11 @@ pub struct DelayRes {
|
||||
|
||||
/// GET /proxies/{name}/delay
|
||||
/// 获取代理延迟
|
||||
pub async fn get_proxy_delay(name: String, test_url: Option<String>) -> Result<DelayRes> {
|
||||
pub async fn get_proxy_delay(
|
||||
name: String,
|
||||
test_url: Option<String>,
|
||||
timeout: i32,
|
||||
) -> Result<DelayRes> {
|
||||
let (url, headers) = clash_client_info()?;
|
||||
let url = format!("{url}/proxies/{name}/delay");
|
||||
|
||||
@@ -57,7 +61,7 @@ pub async fn get_proxy_delay(name: String, test_url: Option<String>) -> Result<D
|
||||
let builder = client
|
||||
.get(&url)
|
||||
.headers(headers)
|
||||
.query(&[("timeout", "10000"), ("url", &test_url)]);
|
||||
.query(&[("timeout", &format!("{timeout}")), ("url", &test_url)]);
|
||||
let response = builder.send().await?;
|
||||
|
||||
Ok(response.json::<DelayRes>().await?)
|
||||
|
||||
@@ -144,10 +144,9 @@ impl CoreManager {
|
||||
|
||||
let config_path = dirs::path_to_str(&config_path)?;
|
||||
|
||||
// fix #212
|
||||
let args = match clash_core.as_str() {
|
||||
"clash-meta" => vec!["-m", "-d", app_dir, "-f", config_path],
|
||||
"clash-meta-alpha" => vec!["-m", "-d", app_dir, "-f", config_path],
|
||||
"clash-meta" => vec!["-d", app_dir, "-f", config_path],
|
||||
"clash-meta-alpha" => vec!["-d", app_dir, "-f", config_path],
|
||||
_ => vec!["-d", app_dir, "-f", config_path],
|
||||
};
|
||||
|
||||
|
||||
@@ -65,7 +65,7 @@ impl Hotkey {
|
||||
}
|
||||
|
||||
let f = match func.trim() {
|
||||
"open_dashboard" => feat::open_dashboard,
|
||||
"open_or_close_dashboard" => feat::open_or_close_dashboard,
|
||||
"clash_mode_rule" => || feat::change_clash_mode("rule".into()),
|
||||
"clash_mode_global" => || feat::change_clash_mode("global".into()),
|
||||
"clash_mode_direct" => || feat::change_clash_mode("direct".into()),
|
||||
|
||||
@@ -148,9 +148,6 @@ impl Sysopt {
|
||||
|
||||
/// init the auto launch
|
||||
pub fn init_launch(&self) -> Result<()> {
|
||||
let enable = { Config::verge().latest().enable_auto_launch };
|
||||
let enable = enable.unwrap_or(false);
|
||||
|
||||
let app_exe = current_exe()?;
|
||||
let app_exe = dunce::canonicalize(app_exe)?;
|
||||
let app_name = app_exe
|
||||
@@ -204,28 +201,6 @@ impl Sysopt {
|
||||
.set_app_path(&app_path)
|
||||
.build()?;
|
||||
|
||||
// 避免在开发时将自启动关了
|
||||
#[cfg(feature = "verge-dev")]
|
||||
if !enable {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
if enable && !auto.is_enabled().unwrap_or(false) {
|
||||
// 避免重复设置登录项
|
||||
let _ = auto.disable();
|
||||
auto.enable()?;
|
||||
} else if !enable {
|
||||
let _ = auto.disable();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
if enable {
|
||||
auto.enable()?;
|
||||
}
|
||||
|
||||
*self.auto_launch.lock() = Some(auto);
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -1,4 +1,9 @@
|
||||
use crate::{cmds, config::Config, feat, utils::resolve};
|
||||
use crate::{
|
||||
cmds,
|
||||
config::Config,
|
||||
feat,
|
||||
utils::{dirs, resolve},
|
||||
};
|
||||
use anyhow::Result;
|
||||
use tauri::{
|
||||
api, AppHandle, CustomMenuItem, Manager, SystemTrayEvent, SystemTrayMenu, SystemTrayMenuItem,
|
||||
@@ -129,26 +134,47 @@ impl Tray {
|
||||
let verge = verge.latest();
|
||||
let system_proxy = verge.enable_system_proxy.as_ref().unwrap_or(&false);
|
||||
let tun_mode = verge.enable_tun_mode.as_ref().unwrap_or(&false);
|
||||
let common_tray_icon = verge.common_tray_icon.as_ref().unwrap_or(&false);
|
||||
let sysproxy_tray_icon = verge.sysproxy_tray_icon.as_ref().unwrap_or(&false);
|
||||
let tun_tray_icon = verge.tun_tray_icon.as_ref().unwrap_or(&false);
|
||||
|
||||
let mut indication_icon = if *system_proxy {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let icon = include_bytes!("../../icons/tray-icon-sys.png").to_vec();
|
||||
let mut icon = include_bytes!("../../icons/tray-icon-sys.png").to_vec();
|
||||
#[cfg(target_os = "macos")]
|
||||
let icon = include_bytes!("../../icons/mac-tray-icon-sys.png").to_vec();
|
||||
let mut icon = include_bytes!("../../icons/mac-tray-icon-sys.png").to_vec();
|
||||
if *sysproxy_tray_icon {
|
||||
let path = dirs::app_home_dir()?.join("icons").join("sysproxy.png");
|
||||
if path.exists() {
|
||||
icon = std::fs::read(path).unwrap();
|
||||
}
|
||||
}
|
||||
icon
|
||||
} else {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let icon = include_bytes!("../../icons/tray-icon.png").to_vec();
|
||||
let mut icon = include_bytes!("../../icons/tray-icon.png").to_vec();
|
||||
#[cfg(target_os = "macos")]
|
||||
let icon = include_bytes!("../../icons/mac-tray-icon.png").to_vec();
|
||||
let mut icon = include_bytes!("../../icons/mac-tray-icon.png").to_vec();
|
||||
if *common_tray_icon {
|
||||
let path = dirs::app_home_dir()?.join("icons").join("common.png");
|
||||
if path.exists() {
|
||||
icon = std::fs::read(path).unwrap();
|
||||
}
|
||||
}
|
||||
icon
|
||||
};
|
||||
|
||||
if *tun_mode {
|
||||
#[cfg(not(target_os = "macos"))]
|
||||
let icon = include_bytes!("../../icons/tray-icon-tun.png").to_vec();
|
||||
let mut icon = include_bytes!("../../icons/tray-icon-tun.png").to_vec();
|
||||
#[cfg(target_os = "macos")]
|
||||
let icon = include_bytes!("../../icons/mac-tray-icon-tun.png").to_vec();
|
||||
let mut icon = include_bytes!("../../icons/mac-tray-icon-tun.png").to_vec();
|
||||
if *tun_tray_icon {
|
||||
let path = dirs::app_home_dir()?.join("icons").join("tun.png");
|
||||
if path.exists() {
|
||||
icon = std::fs::read(path).unwrap();
|
||||
}
|
||||
}
|
||||
indication_icon = icon
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ pub fn use_merge(merge: Mapping, mut config: Mapping) -> Mapping {
|
||||
// 直接覆盖原字段
|
||||
use_lowercase(merge.clone())
|
||||
.into_iter()
|
||||
.filter(|(key, _)| !MERGE_FIELDS.contains(&key.as_str().unwrap_or_default()))
|
||||
.for_each(|(key, value)| {
|
||||
config.insert(key, value);
|
||||
});
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
mod chain;
|
||||
mod field;
|
||||
pub mod field;
|
||||
mod merge;
|
||||
mod script;
|
||||
mod tun;
|
||||
@@ -66,6 +66,7 @@ pub fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
||||
match use_script(script, config.to_owned()) {
|
||||
Ok((res_config, res_logs)) => {
|
||||
exists_keys.extend(use_keys(&res_config));
|
||||
config = res_config;
|
||||
logs.extend(res_logs);
|
||||
}
|
||||
Err(err) => logs.push(("exception".into(), err.to_string())),
|
||||
@@ -77,7 +78,18 @@ pub fn enhance() -> (Mapping, Vec<String>, HashMap<String, ResultLog>) {
|
||||
|
||||
// 合并默认的config
|
||||
for (key, value) in clash_config.into_iter() {
|
||||
config.insert(key, value);
|
||||
if key.as_str() == Some("tun") {
|
||||
let mut tun = config.get_mut("tun").map_or(Mapping::new(), |val| {
|
||||
val.as_mapping().cloned().unwrap_or(Mapping::new())
|
||||
});
|
||||
let patch_tun = value.as_mapping().cloned().unwrap_or(Mapping::new());
|
||||
for (key, value) in patch_tun.into_iter() {
|
||||
tun.insert(key, value);
|
||||
}
|
||||
config.insert("tun".into(), tun.into());
|
||||
} else {
|
||||
config.insert(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
// 内建脚本最后跑
|
||||
|
||||
@@ -30,12 +30,6 @@ pub fn use_tun(mut config: Mapping, enable: bool) -> Mapping {
|
||||
});
|
||||
|
||||
revise!(tun_val, "enable", enable);
|
||||
if enable {
|
||||
append!(tun_val, "stack", "gvisor");
|
||||
append!(tun_val, "dns-hijack", vec!["any:53"]);
|
||||
append!(tun_val, "auto-route", true);
|
||||
append!(tun_val, "auto-detect-interface", true);
|
||||
}
|
||||
|
||||
revise!(config, "tun", tun_val);
|
||||
|
||||
|
||||
@@ -10,13 +10,19 @@ use crate::log_err;
|
||||
use crate::utils::resolve;
|
||||
use anyhow::{bail, Result};
|
||||
use serde_yaml::{Mapping, Value};
|
||||
use tauri::{AppHandle, ClipboardManager};
|
||||
use tauri::{AppHandle, ClipboardManager, Manager};
|
||||
|
||||
// 打开面板
|
||||
pub fn open_dashboard() {
|
||||
pub fn open_or_close_dashboard() {
|
||||
let handle = handle::Handle::global();
|
||||
let app_handle = handle.app_handle.lock();
|
||||
if let Some(app_handle) = app_handle.as_ref() {
|
||||
if let Some(window) = app_handle.get_window("main") {
|
||||
if let Ok(true) = window.is_focused() {
|
||||
let _ = window.close();
|
||||
return;
|
||||
}
|
||||
}
|
||||
resolve::create_window(app_handle);
|
||||
}
|
||||
}
|
||||
@@ -230,6 +236,9 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> {
|
||||
let proxy_bypass = patch.system_proxy_bypass;
|
||||
let language = patch.language;
|
||||
let port = patch.verge_mixed_port;
|
||||
let common_tray_icon = patch.common_tray_icon;
|
||||
let sysproxy_tray_icon = patch.sysproxy_tray_icon;
|
||||
let tun_tray_icon = patch.tun_tray_icon;
|
||||
|
||||
match {
|
||||
#[cfg(target_os = "windows")]
|
||||
@@ -269,7 +278,12 @@ pub async fn patch_verge(patch: IVerge) -> Result<()> {
|
||||
|
||||
if language.is_some() {
|
||||
handle::Handle::update_systray()?;
|
||||
} else if system_proxy.or(tun_mode).is_some() {
|
||||
} else if system_proxy.is_some()
|
||||
|| tun_mode.is_some()
|
||||
|| common_tray_icon.is_some()
|
||||
|| sysproxy_tray_icon.is_some()
|
||||
|| tun_tray_icon.is_some()
|
||||
{
|
||||
handle::Handle::update_systray_part()?;
|
||||
}
|
||||
|
||||
|
||||
@@ -55,6 +55,8 @@ fn main() -> std::io::Result<()> {
|
||||
cmds::get_verge_config,
|
||||
cmds::patch_verge_config,
|
||||
cmds::test_delay,
|
||||
cmds::get_app_dir,
|
||||
cmds::copy_icon_file,
|
||||
cmds::exit_app,
|
||||
// cmds::update_hotkeys,
|
||||
// profile
|
||||
|
||||
@@ -92,14 +92,9 @@ pub fn clash_pid_path() -> Result<PathBuf> {
|
||||
Ok(app_home_dir()?.join("clash.pid"))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn service_dir() -> Result<PathBuf> {
|
||||
Ok(app_home_dir()?.join("service"))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
pub fn service_path() -> Result<PathBuf> {
|
||||
Ok(service_dir()?.join("clash-verge-service.exe"))
|
||||
Ok(app_resources_dir()?.join("clash-verge-service.exe"))
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
|
||||
@@ -240,67 +240,6 @@ pub fn init_resources() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// initialize service resources
|
||||
/// after tauri setup
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn init_service() -> Result<()> {
|
||||
let service_dir = dirs::service_dir()?;
|
||||
let res_dir = dirs::app_resources_dir()?;
|
||||
|
||||
if !service_dir.exists() {
|
||||
let _ = fs::create_dir_all(&service_dir);
|
||||
}
|
||||
if !res_dir.exists() {
|
||||
let _ = fs::create_dir_all(&res_dir);
|
||||
}
|
||||
|
||||
let file_list = [
|
||||
"clash-verge-service.exe",
|
||||
"install-service.exe",
|
||||
"uninstall-service.exe",
|
||||
];
|
||||
|
||||
// copy the resource file
|
||||
// if the source file is newer than the destination file, copy it over
|
||||
for file in file_list.iter() {
|
||||
let src_path = res_dir.join(file);
|
||||
let dest_path = service_dir.join(file);
|
||||
|
||||
let handle_copy = || {
|
||||
match fs::copy(&src_path, &dest_path) {
|
||||
Ok(_) => log::debug!(target: "app", "resources copied '{file}'"),
|
||||
Err(err) => {
|
||||
log::error!(target: "app", "failed to copy resources '{file}', {err}")
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
if src_path.exists() && !dest_path.exists() {
|
||||
handle_copy();
|
||||
continue;
|
||||
}
|
||||
|
||||
let src_modified = fs::metadata(&src_path).and_then(|m| m.modified());
|
||||
let dest_modified = fs::metadata(&dest_path).and_then(|m| m.modified());
|
||||
|
||||
match (src_modified, dest_modified) {
|
||||
(Ok(src_modified), Ok(dest_modified)) => {
|
||||
if src_modified > dest_modified {
|
||||
handle_copy();
|
||||
} else {
|
||||
log::debug!(target: "app", "skipping resource copy '{file}'");
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
log::debug!(target: "app", "failed to get modified '{file}'");
|
||||
handle_copy();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// initialize url scheme
|
||||
#[cfg(target_os = "windows")]
|
||||
pub fn init_scheme() -> Result<()> {
|
||||
|
||||
@@ -12,6 +12,7 @@ use serde_yaml::Mapping;
|
||||
use std::net::TcpListener;
|
||||
use tauri::api::notification;
|
||||
use tauri::{App, AppHandle, Manager};
|
||||
use window_shadows::set_shadow;
|
||||
|
||||
pub static VERSION: OnceCell<String> = OnceCell::new();
|
||||
|
||||
@@ -41,8 +42,6 @@ pub fn resolve_setup(app: &mut App) {
|
||||
VERSION.get_or_init(|| version.clone());
|
||||
|
||||
log_err!(init::init_resources());
|
||||
#[cfg(target_os = "windows")]
|
||||
log_err!(init::init_service());
|
||||
log_err!(init::init_scheme());
|
||||
log_err!(init::startup_script());
|
||||
// 处理随机端口
|
||||
@@ -156,61 +155,58 @@ pub fn create_window(app_handle: &AppHandle) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
use window_shadows::set_shadow;
|
||||
|
||||
match builder
|
||||
.decorations(false)
|
||||
.transparent(true)
|
||||
.visible(false)
|
||||
.build()
|
||||
{
|
||||
Ok(win) => {
|
||||
log::trace!("try to calculate the monitor size");
|
||||
let center = (|| -> Result<bool> {
|
||||
let mut center = false;
|
||||
let monitor = win.current_monitor()?.ok_or(anyhow::anyhow!(""))?;
|
||||
let size = monitor.size();
|
||||
let pos = win.outer_position()?;
|
||||
|
||||
if pos.x < -400
|
||||
|| pos.x > (size.width - 200).try_into()?
|
||||
|| pos.y < -200
|
||||
|| pos.y > (size.height - 200).try_into()?
|
||||
{
|
||||
center = true;
|
||||
}
|
||||
Ok(center)
|
||||
})();
|
||||
|
||||
if center.unwrap_or(true) {
|
||||
trace_err!(win.center(), "set win center");
|
||||
}
|
||||
|
||||
log::trace!("try to create window");
|
||||
let app_handle = app_handle.clone();
|
||||
|
||||
if let Some(window) = app_handle.get_window("main") {
|
||||
trace_err!(set_shadow(&window, true), "set win shadow");
|
||||
} else {
|
||||
log::error!(target: "app", "failed to create window, get_window is None")
|
||||
}
|
||||
}
|
||||
Err(err) => log::error!(target: "app", "failed to create window, {err}"),
|
||||
}
|
||||
}
|
||||
|
||||
let window = builder
|
||||
.decorations(false)
|
||||
.transparent(true)
|
||||
.visible(false)
|
||||
.build();
|
||||
#[cfg(target_os = "macos")]
|
||||
crate::log_err!(builder
|
||||
let window = builder
|
||||
.decorations(true)
|
||||
.hidden_title(true)
|
||||
.title_bar_style(tauri::TitleBarStyle::Overlay)
|
||||
.build());
|
||||
|
||||
.build();
|
||||
#[cfg(target_os = "linux")]
|
||||
crate::log_err!(builder.decorations(true).transparent(false).build());
|
||||
let window = builder.decorations(true).transparent(false).build();
|
||||
|
||||
match window {
|
||||
Ok(win) => {
|
||||
let is_maximized = Config::verge()
|
||||
.latest()
|
||||
.window_is_maximized
|
||||
.unwrap_or(false);
|
||||
log::trace!("try to calculate the monitor size");
|
||||
let center = (|| -> Result<bool> {
|
||||
let mut center = false;
|
||||
let monitor = win.current_monitor()?.ok_or(anyhow::anyhow!(""))?;
|
||||
let size = monitor.size();
|
||||
let pos = win.outer_position()?;
|
||||
|
||||
if pos.x < -400
|
||||
|| pos.x > (size.width - 200) as i32
|
||||
|| pos.y < -200
|
||||
|| pos.y > (size.height - 200) as i32
|
||||
{
|
||||
center = true;
|
||||
}
|
||||
Ok(center)
|
||||
})();
|
||||
|
||||
if center.unwrap_or(true) {
|
||||
trace_err!(win.center(), "set win center");
|
||||
}
|
||||
|
||||
trace_err!(set_shadow(&win, true), "set win shadow");
|
||||
if is_maximized {
|
||||
trace_err!(win.maximize(), "set win maximize");
|
||||
}
|
||||
}
|
||||
Err(_) => {
|
||||
log::error!("failed to create window");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// save window size and position
|
||||
@@ -231,11 +227,11 @@ pub fn save_window_size_position(app_handle: &AppHandle, save_to_file: bool) ->
|
||||
let size = size.to_logical::<f64>(scale);
|
||||
let pos = win.outer_position()?;
|
||||
let pos = pos.to_logical::<f64>(scale);
|
||||
|
||||
if size.width >= 600.0 && size.height >= 520.0 {
|
||||
let is_maximized = win.is_maximized()?;
|
||||
verge.window_is_maximized = Some(is_maximized);
|
||||
if !is_maximized && size.width >= 600.0 && size.height >= 520.0 {
|
||||
verge.window_size_position = Some(vec![size.width, size.height, pos.x, pos.y]);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"package": {
|
||||
"productName": "Clash Verge",
|
||||
"version": "1.5.0"
|
||||
"version": "1.5.4"
|
||||
},
|
||||
"build": {
|
||||
"distDir": "../dist",
|
||||
@@ -58,11 +58,18 @@
|
||||
"dialog": {
|
||||
"all": false,
|
||||
"open": true
|
||||
},
|
||||
"protocol": {
|
||||
"asset": true,
|
||||
"assetScope": ["**"]
|
||||
},
|
||||
"path": {
|
||||
"all": true
|
||||
}
|
||||
},
|
||||
"windows": [],
|
||||
"security": {
|
||||
"csp": "script-src 'unsafe-eval' 'self'; default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self'; img-src http: https: data: 'self';"
|
||||
"csp": "script-src 'unsafe-eval' 'self'; default-src blob: data: filesystem: ws: wss: http: https: tauri: 'unsafe-eval' 'unsafe-inline' 'self'; img-src asset: http: https: data: 'self';"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,6 +15,7 @@ Unicode true
|
||||
!include WordFunc.nsh
|
||||
!include "LogicLib.nsh"
|
||||
!include "StrFunc.nsh"
|
||||
!addplugindir "$%AppData%\Local\NSIS\"
|
||||
${StrCase}
|
||||
${StrLoc}
|
||||
|
||||
@@ -423,6 +424,7 @@ FunctionEnd
|
||||
nsis_tauri_utils::FindProcess "Clash Verge.exe"
|
||||
${If} $R0 != 0
|
||||
; Kill the process
|
||||
DetailPrint "Kill Clash Verge.exe..."
|
||||
!if "${INSTALLMODE}" == "currentUser"
|
||||
nsis_tauri_utils::KillProcessCurrentUser "Clash Verge.exe"
|
||||
!else
|
||||
@@ -435,6 +437,7 @@ FunctionEnd
|
||||
nsis_tauri_utils::FindProcess "clash-verge-service.exe"
|
||||
${If} $R0 != 0
|
||||
; Kill the process
|
||||
DetailPrint "Kill clash-verge-service.exe..."
|
||||
!if "${INSTALLMODE}" == "currentUser"
|
||||
nsis_tauri_utils::KillProcessCurrentUser "clash-verge-service.exe"
|
||||
!else
|
||||
@@ -447,6 +450,7 @@ FunctionEnd
|
||||
nsis_tauri_utils::FindProcess "clash-meta-alpha.exe"
|
||||
${If} $R0 != 0
|
||||
; Kill the process
|
||||
DetailPrint "Kill clash-meta-alpha.exe..."
|
||||
!if "${INSTALLMODE}" == "currentUser"
|
||||
nsis_tauri_utils::KillProcessCurrentUser "clash-meta-alpha.exe"
|
||||
!else
|
||||
@@ -458,6 +462,7 @@ FunctionEnd
|
||||
nsis_tauri_utils::FindProcess "clash-meta.exe"
|
||||
${If} $R0 != 0
|
||||
; Kill the process
|
||||
DetailPrint "Kill clash-meta.exe..."
|
||||
!if "${INSTALLMODE}" == "currentUser"
|
||||
nsis_tauri_utils::KillProcessCurrentUser "clash-meta.exe"
|
||||
!else
|
||||
@@ -466,9 +471,70 @@ FunctionEnd
|
||||
${EndIf}
|
||||
!macroend
|
||||
|
||||
Section
|
||||
!insertmacro CheckAllVergeProcesses
|
||||
SectionEnd
|
||||
!macro StartVergeService
|
||||
; Check if the service exists
|
||||
SimpleSC::ExistsService "clash_verge_service"
|
||||
Pop $0 ; 0:service exists;other: service not exists
|
||||
; Service exists
|
||||
${If} $0 == 0
|
||||
Push $0
|
||||
; Check if the service is running
|
||||
SimpleSC::ServiceIsRunning "clash_verge_service"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns 1 (service is running) - returns 0 (service is not running)
|
||||
${If} $0 == 0
|
||||
Push $0
|
||||
${If} $1 == 0
|
||||
DetailPrint "Restart Clash Verge Service..."
|
||||
SimpleSC::StartService "clash_verge_service" "" 30
|
||||
${EndIf}
|
||||
${ElseIf} $0 != 0
|
||||
Push $0
|
||||
SimpleSC::GetErrorMessage
|
||||
Pop $0
|
||||
MessageBox MB_OK|MB_ICONSTOP "Check Service Status Error ($0)"
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
!macroend
|
||||
|
||||
!macro RemoveVergeService
|
||||
; Check if the service exists
|
||||
SimpleSC::ExistsService "clash_verge_service"
|
||||
Pop $0 ; 0:service exists;other: service not exists
|
||||
; Service exists
|
||||
${If} $0 == 0
|
||||
Push $0
|
||||
; Check if the service is running
|
||||
SimpleSC::ServiceIsRunning "clash_verge_service"
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
Pop $1 ; returns 1 (service is running) - returns 0 (service is not running)
|
||||
${If} $0 == 0
|
||||
Push $0
|
||||
${If} $1 == 1
|
||||
DetailPrint "Stop Clash Verge Service..."
|
||||
SimpleSC::StopService "clash_verge_service" 1 30
|
||||
Pop $0 ; returns an errorcode (<>0) otherwise success (0)
|
||||
${If} $0 == 0
|
||||
DetailPrint "Removing Clash Verge Service..."
|
||||
SimpleSC::RemoveService "clash_verge_service"
|
||||
${ElseIf} $0 != 0
|
||||
Push $0
|
||||
SimpleSC::GetErrorMessage
|
||||
Pop $0
|
||||
MessageBox MB_OK|MB_ICONSTOP "Clash Verge Service Stop Error ($0)"
|
||||
${EndIf}
|
||||
${ElseIf} $1 == 0
|
||||
DetailPrint "Removing Clash Verge Service..."
|
||||
SimpleSC::RemoveService "clash_verge_service"
|
||||
${EndIf}
|
||||
${ElseIf} $0 != 0
|
||||
Push $0
|
||||
SimpleSC::GetErrorMessage
|
||||
Pop $0
|
||||
MessageBox MB_OK|MB_ICONSTOP "Check Service Status Error ($0)"
|
||||
${EndIf}
|
||||
${EndIf}
|
||||
!macroend
|
||||
|
||||
Section EarlyChecks
|
||||
; Abort silent installer if downgrades is disabled
|
||||
@@ -608,6 +674,8 @@ Section Install
|
||||
File /a "/oname={{this}}" "{{@key}}"
|
||||
{{/each}}
|
||||
|
||||
!insertmacro StartVergeService
|
||||
|
||||
; Create uninstaller
|
||||
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||||
|
||||
@@ -679,6 +747,7 @@ FunctionEnd
|
||||
Section Uninstall
|
||||
!insertmacro CheckIfAppIsRunning
|
||||
!insertmacro CheckAllVergeProcesses
|
||||
!insertmacro RemoveVergeService
|
||||
; Delete the app directory and its content from disk
|
||||
; Copy main executable
|
||||
Delete "$INSTDIR\${MAINBINARYNAME}.exe"
|
||||
|
||||
@@ -27,8 +27,8 @@ body {
|
||||
}
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
width: 6px;
|
||||
height: 6px;
|
||||
width: 8px;
|
||||
height: 8px;
|
||||
background: transparent;
|
||||
}
|
||||
*::-webkit-scrollbar-thumb {
|
||||
|
||||
@@ -55,6 +55,7 @@ export const ProviderButton = () => {
|
||||
<Typography variant="h6">{t("Proxy Provider")}</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
onClick={async () => {
|
||||
Object.entries(data || {}).forEach(async ([key, item]) => {
|
||||
await proxyProviderUpdate(key);
|
||||
@@ -108,6 +109,9 @@ export const ProviderButton = () => {
|
||||
>
|
||||
{key}
|
||||
</Typography>
|
||||
<TypeBox component="span" sx={{ marginLeft: "8px" }}>
|
||||
{item.proxies.length}
|
||||
</TypeBox>
|
||||
</>
|
||||
}
|
||||
secondary={
|
||||
@@ -158,6 +162,17 @@ export const ProviderButton = () => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
const TypeBox = styled(Box)(({ theme }) => ({
|
||||
display: "inline-block",
|
||||
border: "1px solid #ccc",
|
||||
borderColor: alpha(theme.palette.secondary.main, 0.5),
|
||||
color: alpha(theme.palette.secondary.main, 0.8),
|
||||
borderRadius: 4,
|
||||
fontSize: 10,
|
||||
marginRight: "4px",
|
||||
padding: "0 2px",
|
||||
lineHeight: 1.25,
|
||||
}));
|
||||
|
||||
const StyledTypeBox = styled(Box)(({ theme }) => ({
|
||||
display: "inline-block",
|
||||
|
||||
@@ -25,6 +25,7 @@ export const ProxyGroups = (props: Props) => {
|
||||
|
||||
const { verge } = useVerge();
|
||||
const { current, patchCurrent } = useProfiles();
|
||||
const timeout = verge?.default_latency_timeout || 10000;
|
||||
|
||||
const virtuosoRef = useRef<VirtuosoHandle>(null);
|
||||
|
||||
@@ -83,7 +84,7 @@ export const ProxyGroups = (props: Props) => {
|
||||
}
|
||||
|
||||
const names = proxies.filter((p) => !p!.provider).map((p) => p!.name);
|
||||
await delayManager.checkListDelay(names, groupName);
|
||||
await delayManager.checkListDelay(names, groupName, timeout);
|
||||
|
||||
onProxies();
|
||||
});
|
||||
|
||||
@@ -4,6 +4,7 @@ import { CheckCircleOutlineRounded } from "@mui/icons-material";
|
||||
import { alpha, Box, ListItemButton, styled, Typography } from "@mui/material";
|
||||
import { BaseLoading } from "@/components/base";
|
||||
import delayManager from "@/services/delay";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
|
||||
interface Props {
|
||||
groupName: string;
|
||||
@@ -20,6 +21,8 @@ export const ProxyItemMini = (props: Props) => {
|
||||
// -1/<=0 为 不显示
|
||||
// -2 为 loading
|
||||
const [delay, setDelay] = useState(-1);
|
||||
const { verge } = useVerge();
|
||||
const timeout = verge?.default_latency_timeout || 10000;
|
||||
|
||||
useEffect(() => {
|
||||
delayManager.setListener(proxy.name, groupName, setDelay);
|
||||
@@ -36,7 +39,7 @@ export const ProxyItemMini = (props: Props) => {
|
||||
|
||||
const onDelay = useLockFn(async () => {
|
||||
setDelay(-2);
|
||||
setDelay(await delayManager.checkDelay(proxy.name, groupName));
|
||||
setDelay(await delayManager.checkDelay(proxy.name, groupName, timeout));
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -92,7 +95,32 @@ export const ProxyItemMini = (props: Props) => {
|
||||
</Typography>
|
||||
|
||||
{showType && (
|
||||
<Box sx={{ display: "flex", flexWrap: "nowrap", flex: "none" }}>
|
||||
<Box
|
||||
sx={{
|
||||
display: "flex",
|
||||
flexWrap: "nowrap",
|
||||
flex: "none",
|
||||
marginTop: "4px",
|
||||
}}
|
||||
>
|
||||
{proxy.now && (
|
||||
<Typography
|
||||
variant="body2"
|
||||
component="div"
|
||||
color="text.secondary"
|
||||
sx={{
|
||||
display: "block",
|
||||
textOverflow: "ellipsis",
|
||||
wordBreak: "break-all",
|
||||
overflow: "hidden",
|
||||
whiteSpace: "nowrap",
|
||||
fontSize: "0.75rem",
|
||||
marginRight: "8px",
|
||||
}}
|
||||
>
|
||||
{proxy.now}
|
||||
</Typography>
|
||||
)}
|
||||
{!!proxy.provider && (
|
||||
<TypeBox component="span">{proxy.provider}</TypeBox>
|
||||
)}
|
||||
@@ -139,14 +167,14 @@ export const ProxyItemMini = (props: Props) => {
|
||||
e.stopPropagation();
|
||||
onDelay();
|
||||
}}
|
||||
color={delayManager.formatDelayColor(delay)}
|
||||
color={delayManager.formatDelayColor(delay, timeout)}
|
||||
sx={({ palette }) =>
|
||||
!proxy.provider
|
||||
? { ":hover": { bgcolor: alpha(palette.primary.main, 0.15) } }
|
||||
: {}
|
||||
}
|
||||
>
|
||||
{delayManager.formatDelay(delay)}
|
||||
{delayManager.formatDelay(delay, timeout)}
|
||||
</Widget>
|
||||
)}
|
||||
|
||||
@@ -178,6 +206,16 @@ const TypeBox = styled(Box)(({ theme: { palette, typography } }) => ({
|
||||
fontSize: 10,
|
||||
fontFamily: typography.fontFamily,
|
||||
marginRight: "4px",
|
||||
marginTop: "auto",
|
||||
padding: "0 2px",
|
||||
lineHeight: 1.25,
|
||||
}));
|
||||
|
||||
const TypeTypo = styled(Box)(({ theme: { palette, typography } }) => ({
|
||||
display: "inline-block",
|
||||
fontSize: 10,
|
||||
fontFamily: typography.fontFamily,
|
||||
marginRight: "4px",
|
||||
padding: "0 2px",
|
||||
lineHeight: 1.25,
|
||||
}));
|
||||
|
||||
@@ -14,6 +14,7 @@ import {
|
||||
} from "@mui/material";
|
||||
import { BaseLoading } from "@/components/base";
|
||||
import delayManager from "@/services/delay";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
|
||||
interface Props {
|
||||
groupName: string;
|
||||
@@ -48,7 +49,8 @@ export const ProxyItem = (props: Props) => {
|
||||
// -1/<=0 为 不显示
|
||||
// -2 为 loading
|
||||
const [delay, setDelay] = useState(-1);
|
||||
|
||||
const { verge } = useVerge();
|
||||
const timeout = verge?.default_latency_timeout || 10000;
|
||||
useEffect(() => {
|
||||
delayManager.setListener(proxy.name, groupName, setDelay);
|
||||
|
||||
@@ -64,7 +66,7 @@ export const ProxyItem = (props: Props) => {
|
||||
|
||||
const onDelay = useLockFn(async () => {
|
||||
setDelay(-2);
|
||||
setDelay(await delayManager.checkDelay(proxy.name, groupName));
|
||||
setDelay(await delayManager.checkDelay(proxy.name, groupName, timeout));
|
||||
});
|
||||
|
||||
return (
|
||||
@@ -98,7 +100,9 @@ export const ProxyItem = (props: Props) => {
|
||||
secondary={
|
||||
<>
|
||||
<span style={{ marginRight: 4 }}>{proxy.name}</span>
|
||||
|
||||
{showType && proxy.now && (
|
||||
<TypeBox component="span">{proxy.now}</TypeBox>
|
||||
)}
|
||||
{showType && !!proxy.provider && (
|
||||
<TypeBox component="span">{proxy.provider}</TypeBox>
|
||||
)}
|
||||
@@ -149,14 +153,14 @@ export const ProxyItem = (props: Props) => {
|
||||
e.stopPropagation();
|
||||
onDelay();
|
||||
}}
|
||||
color={delayManager.formatDelayColor(delay)}
|
||||
color={delayManager.formatDelayColor(delay, timeout)}
|
||||
sx={({ palette }) =>
|
||||
!proxy.provider
|
||||
? { ":hover": { bgcolor: alpha(palette.primary.main, 0.15) } }
|
||||
: {}
|
||||
}
|
||||
>
|
||||
{delayManager.formatDelay(delay)}
|
||||
{delayManager.formatDelay(delay, timeout)}
|
||||
</Widget>
|
||||
)}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ import { ProxyHead } from "./proxy-head";
|
||||
import { ProxyItem } from "./proxy-item";
|
||||
import { ProxyItemMini } from "./proxy-item-mini";
|
||||
import type { IRenderItem } from "./use-render-list";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
|
||||
interface RenderProps {
|
||||
item: IRenderItem;
|
||||
@@ -30,6 +31,8 @@ export const ProxyRender = (props: RenderProps) => {
|
||||
const { indent, item, onLocation, onCheckAll, onHeadState, onChangeProxy } =
|
||||
props;
|
||||
const { type, group, headState, proxy, proxyCol } = item;
|
||||
const { verge } = useVerge();
|
||||
const enable_group_icon = verge?.enable_group_icon ?? true;
|
||||
|
||||
if (type === 0 && !group.hidden) {
|
||||
return (
|
||||
@@ -37,18 +40,32 @@ export const ProxyRender = (props: RenderProps) => {
|
||||
dense
|
||||
onClick={() => onHeadState(group.name, { open: !headState?.open })}
|
||||
>
|
||||
{group.icon && group.icon.trim().startsWith("http") && (
|
||||
<img src={group.icon} height="40px" style={{ marginRight: "8px" }} />
|
||||
)}
|
||||
{group.icon && group.icon.trim().startsWith("data") && (
|
||||
<img src={group.icon} height="40px" style={{ marginRight: "8px" }} />
|
||||
)}
|
||||
{group.icon && group.icon.trim().startsWith("<svg") && (
|
||||
<img
|
||||
src={`data:image/svg+xml;base64,${btoa(group.icon)}`}
|
||||
height="40px"
|
||||
/>
|
||||
)}
|
||||
{enable_group_icon &&
|
||||
group.icon &&
|
||||
group.icon.trim().startsWith("http") && (
|
||||
<img
|
||||
src={group.icon}
|
||||
height="40px"
|
||||
style={{ marginRight: "8px" }}
|
||||
/>
|
||||
)}
|
||||
{enable_group_icon &&
|
||||
group.icon &&
|
||||
group.icon.trim().startsWith("data") && (
|
||||
<img
|
||||
src={group.icon}
|
||||
height="40px"
|
||||
style={{ marginRight: "8px" }}
|
||||
/>
|
||||
)}
|
||||
{enable_group_icon &&
|
||||
group.icon &&
|
||||
group.icon.trim().startsWith("<svg") && (
|
||||
<img
|
||||
src={`data:image/svg+xml;base64,${btoa(group.icon)}`}
|
||||
height="40px"
|
||||
/>
|
||||
)}
|
||||
<ListItemText
|
||||
primary={group.name}
|
||||
secondary={
|
||||
|
||||
@@ -16,7 +16,7 @@ type HeadStateStorage = Record<string, Record<string, HeadState>>;
|
||||
const HEAD_STATE_KEY = "proxy-head-state";
|
||||
export const DEFAULT_STATE: HeadState = {
|
||||
open: false,
|
||||
showType: false,
|
||||
showType: true,
|
||||
sortType: 0,
|
||||
filterText: "",
|
||||
textState: null,
|
||||
|
||||
@@ -53,6 +53,7 @@ export const ProviderButton = () => {
|
||||
<Typography variant="h6">{t("Rule Provider")}</Typography>
|
||||
<Button
|
||||
variant="contained"
|
||||
size="small"
|
||||
onClick={async () => {
|
||||
Object.entries(data || {}).forEach(async ([key, item]) => {
|
||||
await ruleProviderUpdate(key);
|
||||
|
||||
@@ -14,7 +14,7 @@ const ItemWrapper = styled("div")`
|
||||
`;
|
||||
|
||||
const HOTKEY_FUNC = [
|
||||
"open_dashboard",
|
||||
"open_or_close_dashboard",
|
||||
"clash_mode_rule",
|
||||
"clash_mode_global",
|
||||
"clash_mode_direct",
|
||||
|
||||
@@ -1,16 +1,38 @@
|
||||
import { forwardRef, useImperativeHandle, useState } from "react";
|
||||
import { forwardRef, useEffect, useImperativeHandle, useState } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { List, Switch } from "@mui/material";
|
||||
import { List, Switch, Button } from "@mui/material";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { BaseDialog, DialogRef, Notice } from "@/components/base";
|
||||
import { SettingItem } from "./setting-comp";
|
||||
import { GuardState } from "./guard-state";
|
||||
import { open as openDialog } from "@tauri-apps/api/dialog";
|
||||
import { convertFileSrc } from "@tauri-apps/api/tauri";
|
||||
import { copyIconFile, getAppDir } from "@/services/cmds";
|
||||
import { join } from "@tauri-apps/api/path";
|
||||
|
||||
export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
const { t } = useTranslation();
|
||||
const { verge, patchVerge, mutateVerge } = useVerge();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [commonIcon, setCommonIcon] = useState("");
|
||||
const [sysproxyIcon, setSysproxyIcon] = useState("");
|
||||
const [tunIcon, setTunIcon] = useState("");
|
||||
|
||||
useEffect(() => {
|
||||
initIconPath();
|
||||
}, []);
|
||||
|
||||
async function initIconPath() {
|
||||
const appDir = await getAppDir();
|
||||
const icon_dir = await join(appDir, "icons");
|
||||
const common_icon = await join(icon_dir, "common.png");
|
||||
const sysproxy_icon = await join(icon_dir, "sysproxy.png");
|
||||
const tun_icon = await join(icon_dir, "tun.png");
|
||||
setCommonIcon(common_icon);
|
||||
setSysproxyIcon(sysproxy_icon);
|
||||
setTunIcon(tun_icon);
|
||||
}
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
open: () => setOpen(true),
|
||||
@@ -61,6 +83,149 @@ export const LayoutViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
<Switch edge="end" />
|
||||
</GuardState>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t("Proxy Group Icon")}>
|
||||
<GuardState
|
||||
value={verge?.enable_group_icon ?? true}
|
||||
valueProps="checked"
|
||||
onCatch={onError}
|
||||
onFormat={onSwitchFormat}
|
||||
onChange={(e) => onChangeData({ enable_group_icon: e })}
|
||||
onGuard={(e) => patchVerge({ enable_group_icon: e })}
|
||||
>
|
||||
<Switch edge="end" />
|
||||
</GuardState>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t("Common Tray Icon")}>
|
||||
<GuardState
|
||||
value={verge?.common_tray_icon}
|
||||
onCatch={onError}
|
||||
onChange={(e) => onChangeData({ common_tray_icon: e })}
|
||||
onGuard={(e) => patchVerge({ common_tray_icon: e })}
|
||||
>
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="small"
|
||||
startIcon={
|
||||
verge?.common_tray_icon &&
|
||||
commonIcon && (
|
||||
<img height="20px" src={convertFileSrc(commonIcon)} />
|
||||
)
|
||||
}
|
||||
onClick={async () => {
|
||||
if (verge?.common_tray_icon) {
|
||||
onChangeData({ common_tray_icon: false });
|
||||
patchVerge({ common_tray_icon: false });
|
||||
} else {
|
||||
const path = await openDialog({
|
||||
directory: false,
|
||||
multiple: false,
|
||||
filters: [
|
||||
{
|
||||
name: "Tray Icon Image",
|
||||
extensions: ["png"],
|
||||
},
|
||||
],
|
||||
});
|
||||
if (path?.length) {
|
||||
await copyIconFile(`${path}`, "common.png");
|
||||
onChangeData({ common_tray_icon: true });
|
||||
patchVerge({ common_tray_icon: true });
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
{verge?.common_tray_icon ? t("Clear") : t("Browse")}
|
||||
</Button>
|
||||
</GuardState>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t("System Proxy Tray Icon")}>
|
||||
<GuardState
|
||||
value={verge?.sysproxy_tray_icon}
|
||||
onCatch={onError}
|
||||
onChange={(e) => onChangeData({ sysproxy_tray_icon: e })}
|
||||
onGuard={(e) => patchVerge({ sysproxy_tray_icon: e })}
|
||||
>
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="small"
|
||||
startIcon={
|
||||
verge?.sysproxy_tray_icon &&
|
||||
sysproxyIcon && (
|
||||
<img height="20px" src={convertFileSrc(sysproxyIcon)} />
|
||||
)
|
||||
}
|
||||
onClick={async () => {
|
||||
if (verge?.sysproxy_tray_icon) {
|
||||
onChangeData({ sysproxy_tray_icon: false });
|
||||
patchVerge({ sysproxy_tray_icon: false });
|
||||
} else {
|
||||
const path = await openDialog({
|
||||
directory: false,
|
||||
multiple: false,
|
||||
filters: [
|
||||
{
|
||||
name: "Tray Icon Image",
|
||||
extensions: ["png"],
|
||||
},
|
||||
],
|
||||
});
|
||||
if (path?.length) {
|
||||
await copyIconFile(`${path}`, "sysproxy.png");
|
||||
onChangeData({ sysproxy_tray_icon: true });
|
||||
patchVerge({ sysproxy_tray_icon: true });
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
{verge?.sysproxy_tray_icon ? t("Clear") : t("Browse")}
|
||||
</Button>
|
||||
</GuardState>
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem label={t("Tun Tray Icon")}>
|
||||
<GuardState
|
||||
value={verge?.tun_tray_icon}
|
||||
onCatch={onError}
|
||||
onChange={(e) => onChangeData({ tun_tray_icon: e })}
|
||||
onGuard={(e) => patchVerge({ tun_tray_icon: e })}
|
||||
>
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="small"
|
||||
startIcon={
|
||||
verge?.tun_tray_icon &&
|
||||
tunIcon && <img height="20px" src={convertFileSrc(tunIcon)} />
|
||||
}
|
||||
onClick={async () => {
|
||||
if (verge?.tun_tray_icon) {
|
||||
onChangeData({ tun_tray_icon: false });
|
||||
patchVerge({ tun_tray_icon: false });
|
||||
} else {
|
||||
const path = await openDialog({
|
||||
directory: false,
|
||||
multiple: false,
|
||||
filters: [
|
||||
{
|
||||
name: "Tray Icon Image",
|
||||
extensions: ["png"],
|
||||
},
|
||||
],
|
||||
});
|
||||
if (path?.length) {
|
||||
await copyIconFile(`${path}`, "tun.png");
|
||||
onChangeData({ tun_tray_icon: true });
|
||||
patchVerge({ tun_tray_icon: true });
|
||||
}
|
||||
}
|
||||
}}
|
||||
>
|
||||
{verge?.tun_tray_icon ? t("Clear") : t("Browse")}
|
||||
</Button>
|
||||
</GuardState>
|
||||
</SettingItem>
|
||||
</List>
|
||||
</BaseDialog>
|
||||
);
|
||||
|
||||
@@ -25,6 +25,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
proxyLayoutColumn: 6,
|
||||
defaultLatencyTest: "",
|
||||
autoLogClean: 0,
|
||||
defaultLatencyTimeout: 10000,
|
||||
});
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
@@ -37,6 +38,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
proxyLayoutColumn: verge?.proxy_layout_column || 6,
|
||||
defaultLatencyTest: verge?.default_latency_test || "",
|
||||
autoLogClean: verge?.auto_log_clean || 0,
|
||||
defaultLatencyTimeout: verge?.default_latency_timeout || 10000,
|
||||
});
|
||||
},
|
||||
close: () => setOpen(false),
|
||||
@@ -50,6 +52,7 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
enable_builtin_enhanced: values.enableBuiltinEnhanced,
|
||||
proxy_layout_column: values.proxyLayoutColumn,
|
||||
default_latency_test: values.defaultLatencyTest,
|
||||
default_latency_timeout: values.defaultLatencyTimeout,
|
||||
auto_log_clean: values.autoLogClean as any,
|
||||
});
|
||||
setOpen(false);
|
||||
@@ -179,6 +182,27 @@ export const MiscViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Default Latency Timeout")} />
|
||||
<TextField
|
||||
size="small"
|
||||
type="number"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
sx={{ width: 250 }}
|
||||
value={values.defaultLatencyTimeout}
|
||||
placeholder="10000"
|
||||
onChange={(e) =>
|
||||
setValues((v) => ({
|
||||
...v,
|
||||
defaultLatencyTimeout: parseInt(e.target.value),
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
</BaseDialog>
|
||||
);
|
||||
|
||||
71
src/components/setting/mods/stack-mode-switch.tsx
Normal file
71
src/components/setting/mods/stack-mode-switch.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { Button, ButtonGroup, Tooltip } from "@mui/material";
|
||||
import { checkService } from "@/services/cmds";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import getSystem from "@/utils/get-system";
|
||||
import useSWR from "swr";
|
||||
|
||||
const isWIN = getSystem() === "windows";
|
||||
|
||||
interface Props {
|
||||
value?: string;
|
||||
onChange?: (value: string) => void;
|
||||
}
|
||||
|
||||
export const StackModeSwitch = (props: Props) => {
|
||||
const { value, onChange } = props;
|
||||
const { verge } = useVerge();
|
||||
const { enable_service_mode } = verge ?? {};
|
||||
// service mode
|
||||
const { data: serviceStatus } = useSWR(
|
||||
isWIN ? "checkService" : null,
|
||||
checkService,
|
||||
{
|
||||
revalidateIfStale: false,
|
||||
shouldRetryOnError: false,
|
||||
}
|
||||
);
|
||||
|
||||
const { t } = useTranslation();
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
title={
|
||||
isWIN && (serviceStatus !== "active" || !enable_service_mode)
|
||||
? t("System and Mixed Can Only be Used in Service Mode")
|
||||
: ""
|
||||
}
|
||||
>
|
||||
<ButtonGroup size="small" sx={{ my: "4px" }}>
|
||||
<Button
|
||||
variant={value?.toLowerCase() === "system" ? "contained" : "outlined"}
|
||||
onClick={() => onChange?.("system")}
|
||||
disabled={
|
||||
isWIN && (serviceStatus !== "active" || !enable_service_mode)
|
||||
}
|
||||
sx={{ textTransform: "capitalize" }}
|
||||
>
|
||||
System
|
||||
</Button>
|
||||
<Button
|
||||
variant={value?.toLowerCase() === "gvisor" ? "contained" : "outlined"}
|
||||
onClick={() => onChange?.("gvisor")}
|
||||
sx={{ textTransform: "capitalize" }}
|
||||
>
|
||||
gVisor
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
variant={value?.toLowerCase() === "mixed" ? "contained" : "outlined"}
|
||||
onClick={() => onChange?.("mixed")}
|
||||
disabled={
|
||||
isWIN && (serviceStatus !== "active" || !enable_service_mode)
|
||||
}
|
||||
sx={{ textTransform: "capitalize" }}
|
||||
>
|
||||
Mixed
|
||||
</Button>
|
||||
</ButtonGroup>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
224
src/components/setting/mods/tun-viewer.tsx
Normal file
224
src/components/setting/mods/tun-viewer.tsx
Normal file
@@ -0,0 +1,224 @@
|
||||
import { forwardRef, useImperativeHandle, useState } from "react";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
List,
|
||||
ListItem,
|
||||
ListItemText,
|
||||
Box,
|
||||
Typography,
|
||||
Button,
|
||||
Switch,
|
||||
TextField,
|
||||
} from "@mui/material";
|
||||
import { useClash } from "@/hooks/use-clash";
|
||||
import { BaseDialog, DialogRef, Notice } from "@/components/base";
|
||||
import { StackModeSwitch } from "./stack-mode-switch";
|
||||
|
||||
export const TunViewer = forwardRef<DialogRef>((props, ref) => {
|
||||
const { t } = useTranslation();
|
||||
|
||||
const { clash, mutateClash, patchClash } = useClash();
|
||||
|
||||
const [open, setOpen] = useState(false);
|
||||
const [values, setValues] = useState({
|
||||
stack: "gvisor",
|
||||
device: "Meta",
|
||||
autoRoute: true,
|
||||
autoDetectInterface: true,
|
||||
dnsHijack: ["any:53"],
|
||||
strictRoute: false,
|
||||
mtu: 9000,
|
||||
});
|
||||
|
||||
useImperativeHandle(ref, () => ({
|
||||
open: () => {
|
||||
setOpen(true);
|
||||
setValues({
|
||||
stack: clash?.tun.stack ?? "gvisor",
|
||||
device: clash?.tun.device ?? "Meta",
|
||||
autoRoute: clash?.tun["auto-route"] ?? true,
|
||||
autoDetectInterface: clash?.tun["auto-detect-interface"] ?? true,
|
||||
dnsHijack: clash?.tun["dns-hijack"] ?? ["any:53"],
|
||||
strictRoute: clash?.tun["strict-route"] ?? false,
|
||||
mtu: clash?.tun.mtu ?? 9000,
|
||||
});
|
||||
},
|
||||
close: () => setOpen(false),
|
||||
}));
|
||||
|
||||
const onSave = useLockFn(async () => {
|
||||
try {
|
||||
let tun = {
|
||||
stack: values.stack,
|
||||
device: values.device,
|
||||
"auto-route": values.autoRoute,
|
||||
"auto-detect-interface": values.autoDetectInterface,
|
||||
"dns-hijack": values.dnsHijack,
|
||||
"strict-route": values.strictRoute,
|
||||
mtu: values.mtu,
|
||||
};
|
||||
await patchClash({ tun });
|
||||
await mutateClash(
|
||||
(old) => ({
|
||||
...(old! || {}),
|
||||
tun,
|
||||
}),
|
||||
false
|
||||
);
|
||||
setOpen(false);
|
||||
} catch (err: any) {
|
||||
Notice.error(err.message || err.toString());
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<BaseDialog
|
||||
open={open}
|
||||
title={
|
||||
<Box display="flex" justifyContent="space-between" gap={1}>
|
||||
<Typography variant="h6">{t("Tun Mode")}</Typography>
|
||||
<Button
|
||||
variant="outlined"
|
||||
size="small"
|
||||
onClick={async () => {
|
||||
let tun = {
|
||||
stack: "gvisor",
|
||||
device: "Meta",
|
||||
"auto-route": true,
|
||||
"auto-detect-interface": true,
|
||||
"dns-hijack": ["any:53"],
|
||||
"strict-route": false,
|
||||
mtu: 9000,
|
||||
};
|
||||
setValues({
|
||||
stack: "gvisor",
|
||||
device: "Meta",
|
||||
autoRoute: true,
|
||||
autoDetectInterface: true,
|
||||
dnsHijack: ["any:53"],
|
||||
strictRoute: false,
|
||||
mtu: 9000,
|
||||
});
|
||||
await patchClash({ tun });
|
||||
await mutateClash(
|
||||
(old) => ({
|
||||
...(old! || {}),
|
||||
tun,
|
||||
}),
|
||||
false
|
||||
);
|
||||
}}
|
||||
>
|
||||
{t("Reset to Default")}
|
||||
</Button>
|
||||
</Box>
|
||||
}
|
||||
contentSx={{ width: 450 }}
|
||||
okBtn={t("Save")}
|
||||
cancelBtn={t("Cancel")}
|
||||
onClose={() => setOpen(false)}
|
||||
onCancel={() => setOpen(false)}
|
||||
onOk={onSave}
|
||||
>
|
||||
<List>
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Stack")} />
|
||||
<StackModeSwitch
|
||||
value={values.stack}
|
||||
onChange={(value) => {
|
||||
setValues((v) => ({
|
||||
...v,
|
||||
stack: value,
|
||||
}));
|
||||
}}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Device")} />
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
sx={{ width: 250 }}
|
||||
value={values.device}
|
||||
placeholder="Meta"
|
||||
onChange={(e) =>
|
||||
setValues((v) => ({ ...v, device: e.target.value }))
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Auto Route")} />
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={values.autoRoute}
|
||||
onChange={(_, c) => setValues((v) => ({ ...v, autoRoute: c }))}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Strict Route")} />
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={values.strictRoute}
|
||||
onChange={(_, c) => setValues((v) => ({ ...v, strictRoute: c }))}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("Auto Detect Interface")} />
|
||||
<Switch
|
||||
edge="end"
|
||||
checked={values.autoDetectInterface}
|
||||
onChange={(_, c) =>
|
||||
setValues((v) => ({ ...v, autoDetectInterface: c }))
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("DNS Hijack")} />
|
||||
<TextField
|
||||
size="small"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
sx={{ width: 250 }}
|
||||
value={values.dnsHijack.join(",")}
|
||||
placeholder="Please use , to separate multiple DNS servers"
|
||||
onChange={(e) =>
|
||||
setValues((v) => ({ ...v, dnsHijack: e.target.value.split(",") }))
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
|
||||
<ListItem sx={{ padding: "5px 2px" }}>
|
||||
<ListItemText primary={t("MTU")} />
|
||||
<TextField
|
||||
size="small"
|
||||
type="number"
|
||||
autoComplete="off"
|
||||
autoCorrect="off"
|
||||
autoCapitalize="off"
|
||||
spellCheck="false"
|
||||
sx={{ width: 250 }}
|
||||
value={values.mtu}
|
||||
placeholder="9000"
|
||||
onChange={(e) =>
|
||||
setValues((v) => ({
|
||||
...v,
|
||||
mtu: parseInt(e.target.value),
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</ListItem>
|
||||
</List>
|
||||
</BaseDialog>
|
||||
);
|
||||
});
|
||||
@@ -41,7 +41,6 @@ const SettingClash = ({ onError }: Props) => {
|
||||
const { enable_random_port = false, verge_mixed_port } = verge ?? {};
|
||||
|
||||
const webRef = useRef<DialogRef>(null);
|
||||
const fieldRef = useRef<DialogRef>(null);
|
||||
const portRef = useRef<DialogRef>(null);
|
||||
const ctrlRef = useRef<DialogRef>(null);
|
||||
const coreRef = useRef<DialogRef>(null);
|
||||
@@ -115,7 +114,7 @@ const SettingClash = ({ onError }: Props) => {
|
||||
</SettingItem>
|
||||
|
||||
<SettingItem
|
||||
label={t("Mixed Port")}
|
||||
label={t("Port Config")}
|
||||
extra={
|
||||
<Tooltip title={t("Random Port")}>
|
||||
<IconButton
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import useSWR from "swr";
|
||||
import { useRef } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import { IconButton, Switch } from "@mui/material";
|
||||
import { ArrowForward, PrivacyTipRounded, Settings } from "@mui/icons-material";
|
||||
import { IconButton, Switch, Tooltip } from "@mui/material";
|
||||
import { PrivacyTipRounded, Settings, InfoRounded } from "@mui/icons-material";
|
||||
import { checkService } from "@/services/cmds";
|
||||
import { useVerge } from "@/hooks/use-verge";
|
||||
import { DialogRef } from "@/components/base";
|
||||
@@ -10,6 +10,7 @@ import { SettingList, SettingItem } from "./mods/setting-comp";
|
||||
import { GuardState } from "./mods/guard-state";
|
||||
import { ServiceViewer } from "./mods/service-viewer";
|
||||
import { SysproxyViewer } from "./mods/sysproxy-viewer";
|
||||
import { TunViewer } from "./mods/tun-viewer";
|
||||
import getSystem from "@/utils/get-system";
|
||||
|
||||
interface Props {
|
||||
@@ -36,6 +37,7 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
|
||||
const serviceRef = useRef<DialogRef>(null);
|
||||
const sysproxyRef = useRef<DialogRef>(null);
|
||||
const tunRef = useRef<DialogRef>(null);
|
||||
|
||||
const {
|
||||
enable_tun_mode,
|
||||
@@ -53,11 +55,41 @@ const SettingSystem = ({ onError }: Props) => {
|
||||
return (
|
||||
<SettingList title={t("System Setting")}>
|
||||
<SysproxyViewer ref={sysproxyRef} />
|
||||
<TunViewer ref={tunRef} />
|
||||
{isWIN && (
|
||||
<ServiceViewer ref={serviceRef} enable={!!enable_service_mode} />
|
||||
)}
|
||||
|
||||
<SettingItem label={t("Tun Mode")}>
|
||||
<SettingItem
|
||||
label={t("Tun Mode")}
|
||||
extra={
|
||||
<>
|
||||
<Tooltip
|
||||
title={
|
||||
isWIN ? t("Tun Mode Info Windows") : t("Tun Mode Info Unix")
|
||||
}
|
||||
placement="top"
|
||||
>
|
||||
<IconButton color="inherit" size="small">
|
||||
<InfoRounded
|
||||
fontSize="inherit"
|
||||
style={{ cursor: "pointer", opacity: 0.75 }}
|
||||
/>
|
||||
</IconButton>
|
||||
</Tooltip>
|
||||
<IconButton
|
||||
color="inherit"
|
||||
size="small"
|
||||
onClick={() => tunRef.current?.open()}
|
||||
>
|
||||
<Settings
|
||||
fontSize="inherit"
|
||||
style={{ cursor: "pointer", opacity: 0.75 }}
|
||||
/>
|
||||
</IconButton>
|
||||
</>
|
||||
}
|
||||
>
|
||||
<GuardState
|
||||
value={enable_tun_mode ?? false}
|
||||
valueProps="checked"
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
import useSWR, { mutate } from "swr";
|
||||
import { useLockFn } from "ahooks";
|
||||
import { getAxios, getVersion, updateConfigs } from "@/services/api";
|
||||
import {
|
||||
getAxios,
|
||||
getClashConfig,
|
||||
getVersion,
|
||||
updateConfigs,
|
||||
} from "@/services/api";
|
||||
import { getClashInfo, patchClashConfig } from "@/services/cmds";
|
||||
getClashInfo,
|
||||
patchClashConfig,
|
||||
getRuntimeConfig,
|
||||
} from "@/services/cmds";
|
||||
|
||||
export const useClash = () => {
|
||||
const { data: clash, mutate: mutateClash } = useSWR(
|
||||
"getClashConfig",
|
||||
getClashConfig
|
||||
"getRuntimeConfig",
|
||||
getRuntimeConfig
|
||||
);
|
||||
|
||||
const { data: versionData, mutate: mutateVersion } = useSWR(
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
"Allow Lan": "Allow Lan",
|
||||
"IPv6": "IPv6",
|
||||
"Log Level": "Log Level",
|
||||
"Mixed Port": "Mixed Port",
|
||||
"Port Config": "Port Config",
|
||||
"Random Port": "Random Port",
|
||||
"After restart to take effect": "After restart to take effect",
|
||||
"External": "External",
|
||||
@@ -110,6 +110,10 @@
|
||||
"Hotkey Setting": "Hotkey Setting",
|
||||
"Traffic Graph": "Traffic Graph",
|
||||
"Memory Usage": "Memory Usage",
|
||||
"Proxy Group Icon": "Proxy Group Icon",
|
||||
"Common Tray Icon": "Common Tray Icon",
|
||||
"System Proxy Tray Icon": "System Proxy Tray Icon",
|
||||
"Tun Tray Icon": "Tun Tray Icon",
|
||||
"Language": "Language",
|
||||
"Open App Dir": "Open App Dir",
|
||||
"Open Core Dir": "Open Core Dir",
|
||||
@@ -134,7 +138,7 @@
|
||||
"Download Speed": "Download Speed",
|
||||
"Upload Speed": "Upload Speed",
|
||||
|
||||
"open_dashboard": "Open Dashboard",
|
||||
"open_or_close_dashboard": "Open/Close Dashboard",
|
||||
"clash_mode_rule": "Rule Mode",
|
||||
"clash_mode_global": "Global Mode",
|
||||
"clash_mode_direct": "Direct Mode",
|
||||
@@ -152,6 +156,7 @@
|
||||
"Enable Builtin Enhanced": "Enable Builtin Enhanced",
|
||||
"Proxy Layout Column": "Proxy Layout Column",
|
||||
"Default Latency Test": "Default Latency Test",
|
||||
"Defaule Latency Timeout": "Defaule Latency Timeout",
|
||||
|
||||
"Auto Log Clean": "Auto Log Clean",
|
||||
"Never Clean": "Never Clean",
|
||||
@@ -159,5 +164,16 @@
|
||||
"Retain 30 Days": "Retain 30 Days",
|
||||
"Retain 90 Days": "Retain 90 Days",
|
||||
|
||||
"Portable Updater Error": "The portable version does not support in-app updates. Please manually download and replace it"
|
||||
"Stack": "Tun Stack",
|
||||
"Device": "Device Name",
|
||||
"Auto Route": "Auto Route",
|
||||
"Strict Route": "Strict Route",
|
||||
"Auto Detect Interface": "Auto Detect Interface",
|
||||
"DNS Hijack": "DNS Hijack",
|
||||
"MTU": "Max Transmission Unit",
|
||||
|
||||
"Portable Updater Error": "The portable version does not support in-app updates. Please manually download and replace it",
|
||||
"Tun Mode Info Windows": "The Tun mode requires granting core-related permissions. Please enable service mode before using it",
|
||||
"Tun Mode Info Unix": "The Tun mode requires granting core-related permissions. Before using it, please authorize the core in the core settings",
|
||||
"System and Mixed Can Only be Used in Service Mode": "System and Mixed Can Only be Used in Service Mode"
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
"Allow Lan": "Разрешить локальную сеть",
|
||||
"IPv6": "IPv6",
|
||||
"Log Level": "Уровень логов",
|
||||
"Mixed Port": "Смешанный порт",
|
||||
"Port Config": "Настройка порта",
|
||||
"Random Port": "Случайный порт",
|
||||
"After restart to take effect": "Чтобы изменения вступили в силу, необходимо перезапустить приложение",
|
||||
"Clash Core": "Ядро Clash",
|
||||
@@ -118,7 +118,7 @@
|
||||
"Cancel": "Отмена",
|
||||
"Exit": "Выход",
|
||||
|
||||
"open_dashboard": "Open Dashboard",
|
||||
"open_or_close_dashboard": "Open/Close Dashboard",
|
||||
"clash_mode_rule": "Режим правил",
|
||||
"clash_mode_global": "Глобальный режим",
|
||||
"clash_mode_direct": "Прямой режим",
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
"Allow Lan": "局域网连接",
|
||||
"IPv6": "IPv6",
|
||||
"Log Level": "日志等级",
|
||||
"Mixed Port": "端口设置",
|
||||
"Port Config": "端口设置",
|
||||
"Random Port": "随机端口",
|
||||
"After restart to take effect": "重启后生效",
|
||||
"External": "外部控制",
|
||||
@@ -110,6 +110,10 @@
|
||||
"Hotkey Setting": "热键设置",
|
||||
"Traffic Graph": "流量图显",
|
||||
"Memory Usage": "内存使用",
|
||||
"Proxy Group Icon": "代理组图标",
|
||||
"Common Tray Icon": "常规托盘图标",
|
||||
"System Proxy Tray Icon": "系统代理托盘图标",
|
||||
"Tun Tray Icon": "Tun模式托盘图标",
|
||||
"Language": "语言设置",
|
||||
"Open App Dir": "应用目录",
|
||||
"Open Core Dir": "内核目录",
|
||||
@@ -134,7 +138,7 @@
|
||||
"Download Speed": "下载速度",
|
||||
"Upload Speed": "上传速度",
|
||||
|
||||
"open_dashboard": "打开面板",
|
||||
"open_or_close_dashboard": "打开/关闭面板",
|
||||
"clash_mode_rule": "规则模式",
|
||||
"clash_mode_global": "全局模式",
|
||||
"clash_mode_direct": "直连模式",
|
||||
@@ -152,6 +156,7 @@
|
||||
"Enable Builtin Enhanced": "开启内建增强功能",
|
||||
"Proxy Layout Column": "代理页布局列数",
|
||||
"Default Latency Test": "默认测试链接",
|
||||
"Default Latency Timeout": "测试超时时间",
|
||||
|
||||
"Auto Log Clean": "自动清理日志",
|
||||
"Never Clean": "不清理",
|
||||
@@ -159,5 +164,17 @@
|
||||
"Retain 30 Days": "保留30天",
|
||||
"Retain 90 Days": "保留90天",
|
||||
|
||||
"Portable Updater Error": "便携版不支持应用内更新,请手动下载替换"
|
||||
"Stack": "Tun 模式堆栈",
|
||||
"Device": "Tun 网卡名称",
|
||||
"Auto Route": "自动设置全局路由",
|
||||
"Strict Route": "严格路由",
|
||||
"Auto Detect Interface": "自动选择流量出口接口",
|
||||
"DNS Hijack": "DNS 劫持",
|
||||
"MTU": "最大传输单元",
|
||||
"Reset to Default": "重置为默认值",
|
||||
|
||||
"Portable Updater Error": "便携版不支持应用内更新,请手动下载替换",
|
||||
"Tun Mode Info Windows": "Tun模式需要授予内核相关权限,使用前请先开启服务模式",
|
||||
"Tun Mode Info Unix": "Tun模式需要授予内核相关权限,使用前请先在内核设置中给内核授权",
|
||||
"System and Mixed Can Only be Used in Service Mode": "System和Mixed只能在服务模式下使用"
|
||||
}
|
||||
|
||||
@@ -107,7 +107,6 @@ export const getProxies = async () => {
|
||||
getProxiesInner(),
|
||||
getProxyProviders(),
|
||||
]);
|
||||
|
||||
// provider name map
|
||||
const providerMap = Object.fromEntries(
|
||||
Object.entries(providerRecord).flatMap(([provider, item]) =>
|
||||
@@ -131,24 +130,27 @@ export const getProxies = async () => {
|
||||
|
||||
const { GLOBAL: global, DIRECT: direct, REJECT: reject } = proxyRecord;
|
||||
|
||||
let groups: IProxyGroupItem[] = [];
|
||||
let groups = Object.values(proxyRecord)
|
||||
.filter((each) => each.name !== "GLOBAL" && each.all)
|
||||
.map((each) => ({
|
||||
...each,
|
||||
all: each.all!.map((item) => generateItem(item)),
|
||||
}));
|
||||
|
||||
if (global?.all) {
|
||||
groups = global.all
|
||||
let globalGroups = global.all
|
||||
.filter((name) => proxyRecord[name]?.all)
|
||||
.map((name) => proxyRecord[name])
|
||||
.map((each) => ({
|
||||
...each,
|
||||
all: each.all!.map((item) => generateItem(item)),
|
||||
}));
|
||||
} else {
|
||||
groups = Object.values(proxyRecord)
|
||||
.filter((each) => each.name !== "GLOBAL" && each.all)
|
||||
.map((each) => ({
|
||||
...each,
|
||||
all: each.all!.map((item) => generateItem(item)),
|
||||
}))
|
||||
.sort((a, b) => b.name.localeCompare(a.name));
|
||||
let globalNames = globalGroups.map((each) => each.name);
|
||||
groups = groups
|
||||
.filter((group) => {
|
||||
return !globalNames.includes(group.name);
|
||||
})
|
||||
.concat(globalGroups);
|
||||
}
|
||||
|
||||
const proxies = [direct, reject].concat(
|
||||
|
||||
@@ -90,8 +90,9 @@ export async function getClashInfo() {
|
||||
return invoke<IClashInfo | null>("get_clash_info");
|
||||
}
|
||||
|
||||
// Get runtime config which controlled by verge
|
||||
export async function getRuntimeConfig() {
|
||||
return invoke<any | null>("get_runtime_config");
|
||||
return invoke<IConfigData | null>("get_runtime_config");
|
||||
}
|
||||
|
||||
export async function getRuntimeYaml() {
|
||||
@@ -138,6 +139,10 @@ export async function grantPermission(core: string) {
|
||||
return invoke<void>("grant_permission", { core });
|
||||
}
|
||||
|
||||
export async function getAppDir() {
|
||||
return invoke<string>("get_app_dir");
|
||||
}
|
||||
|
||||
export async function openAppDir() {
|
||||
return invoke<void>("open_app_dir").catch((err) =>
|
||||
Notice.error(err?.message || err.toString(), 1500)
|
||||
@@ -160,9 +165,17 @@ export async function openWebUrl(url: string) {
|
||||
return invoke<void>("open_web_url", { url });
|
||||
}
|
||||
|
||||
export async function cmdGetProxyDelay(name: string, url?: string) {
|
||||
export async function cmdGetProxyDelay(
|
||||
name: string,
|
||||
timeout: number,
|
||||
url?: string
|
||||
) {
|
||||
name = encodeURIComponent(name);
|
||||
return invoke<{ delay: number }>("clash_api_get_proxy_delay", { name, url });
|
||||
return invoke<{ delay: number }>("clash_api_get_proxy_delay", {
|
||||
name,
|
||||
url,
|
||||
timeout,
|
||||
});
|
||||
}
|
||||
|
||||
export async function cmdTestDelay(url: string) {
|
||||
@@ -203,3 +216,10 @@ export async function getPortableFlag() {
|
||||
export async function exitApp() {
|
||||
return invoke("exit_app");
|
||||
}
|
||||
|
||||
export async function copyIconFile(
|
||||
path: string,
|
||||
name: "common.png" | "sysproxy.png" | "tun.png"
|
||||
) {
|
||||
return invoke<void>("copy_icon_file", { path, name });
|
||||
}
|
||||
|
||||
@@ -69,12 +69,12 @@ class DelayManager {
|
||||
return -1;
|
||||
}
|
||||
|
||||
async checkDelay(name: string, group: string) {
|
||||
async checkDelay(name: string, group: string, timeout: number) {
|
||||
let delay = -1;
|
||||
|
||||
try {
|
||||
const url = this.getUrl(group);
|
||||
const result = await cmdGetProxyDelay(name, url);
|
||||
const result = await cmdGetProxyDelay(name, timeout, url);
|
||||
delay = result.delay;
|
||||
} catch {
|
||||
delay = 1e6; // error
|
||||
@@ -84,7 +84,12 @@ class DelayManager {
|
||||
return delay;
|
||||
}
|
||||
|
||||
async checkListDelay(nameList: string[], group: string, concurrency = 36) {
|
||||
async checkListDelay(
|
||||
nameList: string[],
|
||||
group: string,
|
||||
timeout: number,
|
||||
concurrency = 36
|
||||
) {
|
||||
const names = nameList.filter(Boolean);
|
||||
// 设置正在延迟测试中
|
||||
names.forEach((name) => this.setDelay(name, group, -2));
|
||||
@@ -98,7 +103,7 @@ class DelayManager {
|
||||
const task = names.shift();
|
||||
if (!task) return;
|
||||
current += 1;
|
||||
await this.checkDelay(task, group);
|
||||
await this.checkDelay(task, group, timeout);
|
||||
current -= 1;
|
||||
total -= 1;
|
||||
if (total <= 0) resolve(null);
|
||||
@@ -108,15 +113,15 @@ class DelayManager {
|
||||
});
|
||||
}
|
||||
|
||||
formatDelay(delay: number) {
|
||||
formatDelay(delay: number, timeout = 10000) {
|
||||
if (delay <= 0) return "Error";
|
||||
if (delay > 1e5) return "Error";
|
||||
if (delay >= 10000) return "Timeout"; // 10s
|
||||
if (delay >= timeout) return "Timeout"; // 10s
|
||||
return `${delay}`;
|
||||
}
|
||||
|
||||
formatDelayColor(delay: number) {
|
||||
if (delay >= 10000) return "error.main";
|
||||
formatDelayColor(delay: number, timeout = 10000) {
|
||||
if (delay >= timeout) return "error.main";
|
||||
if (delay <= 0) return "error.main";
|
||||
if (delay > 500) return "warning.main";
|
||||
return "success.main";
|
||||
|
||||
14
src/services/types.d.ts
vendored
14
src/services/types.d.ts
vendored
@@ -32,6 +32,15 @@ interface IConfigData {
|
||||
"tproxy-port": number;
|
||||
"external-controller": string;
|
||||
secret: string;
|
||||
tun: {
|
||||
stack: string;
|
||||
device: string;
|
||||
"auto-route": boolean;
|
||||
"auto-detect-interface": boolean;
|
||||
"dns-hijack": string[];
|
||||
"strict-route": boolean;
|
||||
mtu: number;
|
||||
};
|
||||
}
|
||||
|
||||
interface IRuleItem {
|
||||
@@ -191,6 +200,10 @@ interface IVergeConfig {
|
||||
theme_mode?: "light" | "dark" | "system";
|
||||
traffic_graph?: boolean;
|
||||
enable_memory_usage?: boolean;
|
||||
enable_group_icon?: boolean;
|
||||
common_tray_icon?: boolean;
|
||||
sysproxy_tray_icon?: boolean;
|
||||
tun_tray_icon?: boolean;
|
||||
enable_tun_mode?: boolean;
|
||||
enable_auto_launch?: boolean;
|
||||
enable_service_mode?: boolean;
|
||||
@@ -219,6 +232,7 @@ interface IVergeConfig {
|
||||
};
|
||||
auto_close_connection?: boolean;
|
||||
default_latency_test?: string;
|
||||
default_latency_timeout?: number;
|
||||
enable_builtin_enhanced?: boolean;
|
||||
auto_log_clean?: 0 | 1 | 2 | 3;
|
||||
proxy_layout_column?: number;
|
||||
|
||||
Reference in New Issue
Block a user